diff --git a/doc/en/scripting/builtins/libapp.md b/doc/en/scripting/builtins/libapp.md index ffc4d923..3a8712c7 100644 --- a/doc/en/scripting/builtins/libapp.md +++ b/doc/en/scripting/builtins/libapp.md @@ -77,12 +77,14 @@ Checks if content is loaded. ```lua app.new_world( - -- world name + -- world name, empty string will create a nameless world name: str, -- generation seed seed: str, -- generator name generator: str + -- local player id + [optional] local_player: int=0 ) ``` diff --git a/doc/en/scripting/builtins/libhud.md b/doc/en/scripting/builtins/libhud.md index 72b1a4ed..06766422 100644 --- a/doc/en/scripting/builtins/libhud.md +++ b/doc/en/scripting/builtins/libhud.md @@ -62,4 +62,7 @@ hud.is_paused() -> bool -- Returns true if inventory is open or overlay is shown. hud.is_inventory_open() -> bool + +-- Sets whether to allow pausing. If false, the pause menu will not pause the game. +hud.set_allow_pause(flag: bool) ``` diff --git a/doc/en/scripting/builtins/libplayer.md b/doc/en/scripting/builtins/libplayer.md index 041bf442..e235377a 100644 --- a/doc/en/scripting/builtins/libplayer.md +++ b/doc/en/scripting/builtins/libplayer.md @@ -37,10 +37,10 @@ player.set_vel(playerid: int, x: number, y: number, z: number) Sets x, y, z player linear velocity ```lua -player.get_rot(playerid: int) -> number, number, number +player.get_rot(playerid: int, interpolated: bool) -> number, number, number ``` -Returns x, y, z of camera rotation (radians) +Returns x, y, z of camera rotation (radians). Interpolation is relevant in cases where the rotation refresh rate is lower than the frame rate. ```lua player.set_rot(playerid: int, x: number, y: number, z: number) diff --git a/doc/ru/scripting/builtins/libapp.md b/doc/ru/scripting/builtins/libapp.md index c0f3b741..eb504d25 100644 --- a/doc/ru/scripting/builtins/libapp.md +++ b/doc/ru/scripting/builtins/libapp.md @@ -77,12 +77,14 @@ app.is_content_loaded() -> bool ```lua app.new_world( - -- название мира + -- название мира, пустая строка приведёт к созданию безымянного мира name: str, -- зерно генерации seed: str, -- название генератора generator: str + -- id локального игрока + [опционально] local_player: int=0 ) ``` diff --git a/doc/ru/scripting/builtins/libhud.md b/doc/ru/scripting/builtins/libhud.md index d43867ac..311542cb 100644 --- a/doc/ru/scripting/builtins/libhud.md +++ b/doc/ru/scripting/builtins/libhud.md @@ -65,4 +65,7 @@ hud.is_paused() -> bool -- Возвращает true если открыт инвентарь или оверлей. hud.is_inventory_open() -> bool + +-- Устанавливает разрешение на паузу. При значении false меню паузы не приостанавливает игру. +hud.set_allow_pause(flag: bool) ``` diff --git a/doc/ru/scripting/builtins/libplayer.md b/doc/ru/scripting/builtins/libplayer.md index a9662015..35dda747 100644 --- a/doc/ru/scripting/builtins/libplayer.md +++ b/doc/ru/scripting/builtins/libplayer.md @@ -37,10 +37,10 @@ player.set_vel(playerid: int, x: number, y: number, z: number) Устанавливает x, y, z линейной скорости игрока ```lua -player.get_rot(playerid: int) -> number, number, number +player.get_rot(playerid: int, interpolated: bool=false) -> number, number, number ``` -Возвращает x, y, z вращения камеры (в радианах) +Возвращает x, y, z вращения камеры (в радианах). Интерполяция актуальна в случаях, когда частота обновления вращения ниже частоты кадров. ```lua player.set_rot(playerid: int, x: number, y: number, z: number) diff --git a/res/content/base/scripts/components/player_animator.lua b/res/content/base/scripts/components/player_animator.lua index 871284d5..8862c6c2 100644 --- a/res/content/base/scripts/components/player_animator.lua +++ b/res/content/base/scripts/components/player_animator.lua @@ -3,7 +3,9 @@ local body = entity.rigidbody local rig = entity.skeleton local itemid = 0 +local headIndex = rig:index("head") local itemIndex = rig:index("item") +local bodyIndex = rig:index("body") local function refresh_model(id) itemid = id @@ -12,7 +14,16 @@ local function refresh_model(id) end function on_render() - local invid, slotid = player.get_inventory() + local pid = entity:get_player() + if pid == -1 then + return + end + + local rx, ry, rz = player.get_rot(pid, true) + rig:set_matrix(headIndex, mat4.rotate({1, 0, 0}, ry)) + rig:set_matrix(bodyIndex, mat4.rotate({0, 1, 0}, rx)) + + local invid, slotid = player.get_inventory(pid) local id, _ = inventory.get(invid, slotid) if id ~= itemid then refresh_model(id) diff --git a/res/layouts/pages/scripts.xml.lua b/res/layouts/pages/scripts.xml.lua index 259792b8..3529b3d2 100644 --- a/res/layouts/pages/scripts.xml.lua +++ b/res/layouts/pages/scripts.xml.lua @@ -37,4 +37,6 @@ end function on_open() refresh() + + input.add_callback("key:f5", refresh, document.root) end diff --git a/res/modules/gui_util.lua b/res/modules/gui_util.lua index d2983765..877d4b01 100644 --- a/res/modules/gui_util.lua +++ b/res/modules/gui_util.lua @@ -1,4 +1,6 @@ -local gui_util = {} +local gui_util = { + local_dispatchers = {} +} --- Parse `pagename?arg1=value1&arg2=value2` queries --- @param query page query string @@ -25,6 +27,11 @@ end --- @return document_id function gui_util.load_page(query) local name, args = gui_util.parse_query(query) + for i = #gui_util.local_dispatchers, 1, -1 do + local newname, newargs = gui_util.local_dispatchers[i](name, args) + name = newname or name + args = newargs or args + end local filename = file.find(string.format("layouts/pages/%s.xml", name)) if filename then name = file.prefix(filename)..":pages/"..name @@ -33,4 +40,15 @@ function gui_util.load_page(query) end end +function gui_util.add_page_dispatcher(dispatcher) + if type(dispatcher) ~= "function" then + error("function expected") + end + table.insert(gui_util.local_dispatchers, dispatcher) +end + +function gui_util.reset_local() + gui_util.local_dispatchers = {} +end + return gui_util diff --git a/res/modules/internal/stdcomp.lua b/res/modules/internal/stdcomp.lua index 6c77af1d..9e208038 100644 --- a/res/modules/internal/stdcomp.lua +++ b/res/modules/internal/stdcomp.lua @@ -49,6 +49,7 @@ local Skeleton = {__index={ set_visible=function(self, i, b) return __skeleton.set_visible(self.eid, i, b) end, get_color=function(self) return __skeleton.get_color(self.eid) end, set_color=function(self, color) return __skeleton.set_color(self.eid, color) end, + set_interpolated=function(self, b) return __skeleton.set_interpolated(self.eid, b) end, }} local function new_Skeleton(eid) @@ -66,6 +67,7 @@ local Entity = {__index={ get_uid=function(self) return self.eid end, def_index=function(self) return entities.get_def(self.eid) end, def_name=function(self) return entities.def_name(entities.get_def(self.eid)) end, + get_player=function(self) return entities.get_player(self.eid) end, }} local entities = {} diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 71ba2f4f..0df1c387 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -201,7 +201,7 @@ _GUI_ROOT = Document.new("core:root") _MENU = _GUI_ROOT.menu menu = _MENU -local gui_util = require "core:gui_util" +gui_util = require "core:gui_util" __vc_page_loader = gui_util.load_page --- Console library extension --- @@ -385,6 +385,15 @@ function __vc_on_hud_open() hud.show_overlay("core:console", false, {"chat"}) end) end) + input.add_callback("key:escape", function() + if hud.is_paused() then + hud.resume() + elseif hud.is_inventory_open() then + hud.close_inventory() + else + hud.pause() + end + end) end local RULES_FILE = "world:rules.toml" @@ -408,6 +417,7 @@ end function __vc_on_world_quit() _rules.clear() + gui_util:reset_local() end local __vc_coroutines = {} @@ -470,7 +480,10 @@ function __process_post_runnables() local dead = {} for name, co in pairs(__vc_named_coroutines) do - coroutine.resume(co) + local success, err = coroutine.resume(co) + if not success then + debug.error(err) + end if coroutine.status(co) == "dead" then table.insert(dead, name) end diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 9184fdd6..00382420 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -272,7 +272,7 @@ PacksManager Engine::createPacksManager(const fs::path& worldFolder) { return manager; } -void Engine::setLevelConsumer(consumer> levelConsumer) { +void Engine::setLevelConsumer(OnWorldOpen levelConsumer) { this->levelConsumer = std::move(levelConsumer); } @@ -446,14 +446,14 @@ void Engine::setLanguage(std::string locale) { langs::setup(paths.getResourcesFolder(), std::move(locale), contentPacks); } -void Engine::onWorldOpen(std::unique_ptr level) { +void Engine::onWorldOpen(std::unique_ptr level, int64_t localPlayer) { logger.info() << "world open"; - levelConsumer(std::move(level)); + levelConsumer(std::move(level), localPlayer); } void Engine::onWorldClosed() { logger.info() << "world closed"; - levelConsumer(nullptr); + levelConsumer(nullptr, -1); } void Engine::quit() { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index af9f7fb9..406d420a 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -53,6 +53,8 @@ struct CoreParameters { std::filesystem::path scriptFile; }; +using OnWorldOpen = std::function, int64_t)>; + class Engine : public util::ObjectsKeeper { CoreParameters params; EngineSettings settings; @@ -71,7 +73,7 @@ class Engine : public util::ObjectsKeeper { std::unique_ptr gui; PostRunnables postRunnables; Time time; - consumer> levelConsumer; + OnWorldOpen levelConsumer; bool quitSignal = false; void loadControls(); @@ -134,7 +136,7 @@ public: /// @brief Get engine resource paths controller ResPaths* getResPaths(); - void onWorldOpen(std::unique_ptr level); + void onWorldOpen(std::unique_ptr level, int64_t localPlayer); void onWorldClosed(); void quit(); @@ -166,7 +168,7 @@ public: PacksManager createPacksManager(const fs::path& worldFolder); - void setLevelConsumer(consumer> levelConsumer); + void setLevelConsumer(OnWorldOpen levelConsumer); SettingsHandler& getSettingsHandler(); diff --git a/src/engine/Mainloop.cpp b/src/engine/Mainloop.cpp index e0e64d10..2de6291d 100644 --- a/src/engine/Mainloop.cpp +++ b/src/engine/Mainloop.cpp @@ -15,14 +15,16 @@ Mainloop::Mainloop(Engine& engine) : engine(engine) { void Mainloop::run() { auto& time = engine.getTime(); - engine.setLevelConsumer([this](auto level) { + engine.setLevelConsumer([this](auto level, int64_t localPlayer) { if (level == nullptr) { // destroy LevelScreen and run quit callbacks engine.setScreen(nullptr); // create and go to menu screen engine.setScreen(std::make_shared(engine)); } else { - engine.setScreen(std::make_shared(engine, std::move(level))); + engine.setScreen(std::make_shared( + engine, std::move(level), localPlayer + )); } }); diff --git a/src/engine/ServerMainloop.cpp b/src/engine/ServerMainloop.cpp index b97919be..954c2a11 100644 --- a/src/engine/ServerMainloop.cpp +++ b/src/engine/ServerMainloop.cpp @@ -30,7 +30,7 @@ void ServerMainloop::run() { logger.info() << "nothing to do"; return; } - engine.setLevelConsumer([this](auto level) { + engine.setLevelConsumer([this](auto level, auto) { setLevel(std::move(level)); }); diff --git a/src/frontend/debug_panel.cpp b/src/frontend/debug_panel.cpp index a234c38a..779597e1 100644 --- a/src/frontend/debug_panel.cpp +++ b/src/frontend/debug_panel.cpp @@ -13,7 +13,9 @@ #include "graphics/render/ParticlesRenderer.hpp" #include "graphics/render/ChunksRenderer.hpp" #include "logic/scripting/scripting.hpp" +#include "network/Network.hpp" #include "objects/Player.hpp" +#include "objects/Players.hpp" #include "objects/Entities.hpp" #include "objects/EntityDef.hpp" #include "physics/Hitbox.hpp" @@ -41,6 +43,7 @@ static std::shared_ptr