From 43f0cbe3fe5f8231af0415207fda129e5e58b81f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 15 Jan 2025 22:25:51 +0300 Subject: [PATCH 01/18] add player.is_suspended, player.set_suspended --- src/logic/LevelController.cpp | 6 ++++++ src/logic/scripting/lua/libs/libplayer.cpp | 16 ++++++++++++++++ src/objects/Player.cpp | 8 ++++++++ src/objects/Player.hpp | 4 ++++ src/objects/Players.cpp | 21 +++++++++++++++++++++ src/objects/Players.hpp | 4 ++++ 6 files changed, 59 insertions(+) diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 47a6384d..422807c6 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -66,6 +66,9 @@ LevelController::LevelController( void LevelController::update(float delta, bool pause) { for (const auto& [_, player] : *level->players) { + if (player->isSuspended()) { + continue; + } glm::vec3 position = player->getPosition(); player->chunks->configure( position.x, @@ -85,6 +88,9 @@ void LevelController::update(float delta, bool pause) { level->entities->updatePhysics(delta); level->entities->update(delta); for (const auto& [_, player] : *level->players) { + if (player->isSuspended()) { + continue; + } if (playerTickClock.update(delta)) { if (player->getId() % playerTickClock.getParts() == playerTickClock.getPart()) { diff --git a/src/logic/scripting/lua/libs/libplayer.cpp b/src/logic/scripting/lua/libs/libplayer.cpp index af908aea..5979d0f6 100644 --- a/src/logic/scripting/lua/libs/libplayer.cpp +++ b/src/logic/scripting/lua/libs/libplayer.cpp @@ -284,6 +284,20 @@ static int l_delete(lua::State* L) { return 0; } +static int l_is_suspended(lua::State* L) { + if (auto player = get_player(L, 1)) { + return lua::pushboolean(L, player->isSuspended()); + } + return 0; +} + +static int l_set_suspended(lua::State* L) { + if (auto player = get_player(L, 1)) { + player->setSuspended(lua::toboolean(L, 2)); + } + return 0; +} + const luaL_Reg playerlib[] = { {"get_pos", lua::wrap}, {"set_pos", lua::wrap}, @@ -293,6 +307,8 @@ const luaL_Reg playerlib[] = { {"set_rot", lua::wrap}, {"get_dir", lua::wrap}, {"get_inventory", lua::wrap}, + {"is_suspended", lua::wrap}, + {"set_suspended", lua::wrap}, {"is_flight", lua::wrap}, {"set_flight", lua::wrap}, {"is_noclip", lua::wrap}, diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index f80fffa7..e0a4a49e 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -224,6 +224,14 @@ float Player::getSpeed() const { return speed; } +bool Player::isSuspended() const { + return suspended; +} + +void Player::setSuspended(bool flag) { + suspended = flag; +} + bool Player::isFlight() const { return flight; } diff --git a/src/objects/Player.hpp b/src/objects/Player.hpp index 1e87e2a7..8caf7a63 100644 --- a/src/objects/Player.hpp +++ b/src/objects/Player.hpp @@ -47,6 +47,7 @@ class Player : public Serializable { glm::vec3 position; glm::vec3 spawnpoint {}; std::shared_ptr inventory; + bool suspended = false; bool flight = false; bool noclip = false; bool infiniteItems = true; @@ -85,6 +86,9 @@ public: int getChosenSlot() const; float getSpeed() const; + bool isSuspended() const; + void setSuspended(bool flag); + bool isFlight() const; void setFlight(bool flag); diff --git a/src/objects/Players.cpp b/src/objects/Players.cpp index 1a683a34..edd74274 100644 --- a/src/objects/Players.cpp +++ b/src/objects/Players.cpp @@ -4,6 +4,7 @@ #include "items/Inventories.hpp" #include "world/Level.hpp" #include "world/World.hpp" +#include "objects/Entities.hpp" Players::Players(Level& level) : level(level) {} @@ -36,6 +37,26 @@ Player* Players::create() { return player; } +void Players::suspend(int64_t id) { + if (auto player = get(id)) { + if (player->isSuspended()) { + return; + } + player->setSuspended(true); + level.entities->despawn(player->getEntity()); + player->setEntity(0); + } +} + +void Players::resume(int64_t id) { + if (auto player = get(id)) { + if (!player->isSuspended()) { + return; + } + player->setSuspended(false); + } +} + void Players::remove(int64_t id) { players.erase(id); } diff --git a/src/objects/Players.hpp b/src/objects/Players.hpp index 74f5c565..74146ade 100644 --- a/src/objects/Players.hpp +++ b/src/objects/Players.hpp @@ -25,6 +25,10 @@ public: Player* create(); + void suspend(int64_t id); + + void resume(int64_t id); + void remove(int64_t id); dv::value serialize() const override; From b59752bc845c0d224ac8c376961e109ffd941a14 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 01:23:45 +0300 Subject: [PATCH 02/18] fix player_animator --- res/content/base/scripts/components/player_animator.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/content/base/scripts/components/player_animator.lua b/res/content/base/scripts/components/player_animator.lua index 871284d5..f85deddc 100644 --- a/res/content/base/scripts/components/player_animator.lua +++ b/res/content/base/scripts/components/player_animator.lua @@ -12,7 +12,7 @@ local function refresh_model(id) end function on_render() - local invid, slotid = player.get_inventory() + local invid, slotid = player.get_inventory(hud.get_player()) local id, _ = inventory.get(invid, slotid) if id ~= itemid then refresh_model(id) From 44b9e21d460217787a9f7379fbd1b0b318994c53 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 03:46:56 +0300 Subject: [PATCH 03/18] fix input.add_callback --- src/logic/scripting/lua/libs/libinput.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/logic/scripting/lua/libs/libinput.cpp b/src/logic/scripting/lua/libs/libinput.cpp index 3447728b..4121a384 100644 --- a/src/logic/scripting/lua/libs/libinput.cpp +++ b/src/logic/scripting/lua/libs/libinput.cpp @@ -45,11 +45,6 @@ static int l_add_callback(lua::State* L) { handler = Events::keyCallbacks[key].add(actual_callback); } } - - const auto& bind = Events::bindings.find(bindname); - if (bind == Events::bindings.end()) { - throw std::runtime_error("unknown binding " + util::quote(bindname)); - } auto callback = [=]() -> bool { if (!scripting::engine->getGUI()->isFocusCaught()) { return actual_callback(); @@ -57,6 +52,10 @@ static int l_add_callback(lua::State* L) { return false; }; if (handler == nullptr) { + const auto& bind = Events::bindings.find(bindname); + if (bind == Events::bindings.end()) { + throw std::runtime_error("unknown binding " + util::quote(bindname)); + } handler = bind->second.onactived.add(callback); } From 2073d3782ad40ebc7cddf27e73388bb0ce39c077 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 04:16:32 +0300 Subject: [PATCH 04/18] fix HandlersList concurrency --- src/util/HandlersList.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/util/HandlersList.hpp b/src/util/HandlersList.hpp index 737fdf36..45882512 100644 --- a/src/util/HandlersList.hpp +++ b/src/util/HandlersList.hpp @@ -14,7 +14,7 @@ namespace util { int nextid = 1; std::unordered_map> handlers; std::vector order; - std::recursive_mutex mutex; + std::mutex mutex; public: HandlersList() = default; @@ -46,11 +46,15 @@ namespace util { } void notify(Types...args) { - std::lock_guard lock(mutex); - - auto orderCopy = order; + std::vector orderCopy; + decltype(handlers) handlersCopy; + { + std::lock_guard lock(mutex); + orderCopy = order; + handlersCopy = handlers; + } for (auto it = orderCopy.rbegin(); it != orderCopy.rend(); ++it) { - if (handlers.at(*it)(args...)) { + if (handlersCopy.at(*it)(args...)) { break; } } From 8aee8d81fb639fbdea005f5227f2c9284e84418e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 05:55:49 +0300 Subject: [PATCH 05/18] fix: player name still visible after player removal --- src/graphics/render/Decorator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/graphics/render/Decorator.cpp b/src/graphics/render/Decorator.cpp index 4c9b9289..e9fda381 100644 --- a/src/graphics/render/Decorator.cpp +++ b/src/graphics/render/Decorator.cpp @@ -156,6 +156,7 @@ void Decorator::update(float delta, const Camera& camera) { auto note = renderer.texts->get(textsIter->second); auto player = level.players->get(textsIter->first); if (player == nullptr) { + renderer.texts->remove(textsIter->second); textsIter = playerTexts.erase(textsIter); } else { note->setPosition(player->getPosition() + glm::vec3(0, 1, 0)); From b5999fe36420d116674abc353ed3dad739ac5f70 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 05:57:01 +0300 Subject: [PATCH 06/18] fix some UB --- src/lighting/Lighting.cpp | 12 +++++++++++- src/logic/scripting/lua/lua_util.hpp | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/lighting/Lighting.cpp b/src/lighting/Lighting.cpp index bf55e001..eb721db2 100644 --- a/src/lighting/Lighting.cpp +++ b/src/lighting/Lighting.cpp @@ -8,9 +8,12 @@ #include "voxels/Block.hpp" #include "constants.hpp" #include "util/timeutil.hpp" +#include "debug/Logger.hpp" #include +static debug::Logger logger("lighting"); + Lighting::Lighting(const Content& content, Chunks& chunks) : content(content), chunks(chunks) { auto& indices = *content.getIndices(); @@ -63,6 +66,10 @@ void Lighting::buildSkyLight(int cx, int cz){ const auto blockDefs = content.getIndices()->blocks.getDefs(); Chunk* chunk = chunks.getChunk(cx, cz); + if (chunk == nullptr) { + logger.error() << "attempted to build sky lights to chunk missing in local matrix"; + return; + } for (int z = 0; z < CHUNK_D; z++){ for (int x = 0; x < CHUNK_W; x++){ int gx = x + cx * CHUNK_W; @@ -95,7 +102,10 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) { auto blockDefs = content.getIndices()->blocks.getDefs(); auto chunk = chunks.getChunk(cx, cz); - + if (chunk == nullptr) { + logger.error() << "attempted to build lights to chunk missing in local matrix"; + return; + } for (uint y = 0; y < CHUNK_H; y++){ for (uint z = 0; z < CHUNK_D; z++){ for (uint x = 0; x < CHUNK_W; x++){ diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index 9f3ac414..1baf9c35 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -19,6 +19,7 @@ namespace lua { int userdata_destructor(lua::State* L); std::string env_name(int env); + void dump_stack(lua::State*); inline bool getglobal(lua::State* L, const std::string& name) { lua_getglobal(L, name.c_str()); @@ -208,7 +209,7 @@ namespace lua { return lua_isnumber(L, idx); } inline bool isstring(lua::State* L, int idx) { - return lua_isstring(L, idx); + return lua_type(L, idx) == LUA_TSTRING; } inline bool istable(lua::State* L, int idx) { return lua_istable(L, idx); @@ -226,6 +227,11 @@ namespace lua { return lua_toboolean(L, idx); } inline lua::Integer tointeger(lua::State* L, int idx) { +#ifndef NDEBUG + if (lua_type(L, idx) == LUA_TSTRING) { + throw std::runtime_error("integer expected, got string"); + } +#endif return lua_tointeger(L, idx); } inline uint64_t touinteger(lua::State* L, int idx) { @@ -236,6 +242,11 @@ namespace lua { return static_cast(val); } inline lua::Number tonumber(lua::State* L, int idx) { +#ifndef NDEBUG + if (lua_type(L, idx) != LUA_TNUMBER && !lua_isnoneornil(L, idx)) { + throw std::runtime_error("integer expected"); + } +#endif return lua_tonumber(L, idx); } inline const char* tostring(lua::State* L, int idx) { @@ -588,7 +599,6 @@ namespace lua { } int create_environment(lua::State*, int parent); void remove_environment(lua::State*, int id); - void dump_stack(lua::State*); inline void close(lua::State* L) { lua_close(L); From 65fec4f4a9ba9a25d40ef3c9e0f22cde421c356d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 05:59:43 +0300 Subject: [PATCH 07/18] introduce local player --- src/engine/Engine.cpp | 8 ++++---- src/engine/Engine.hpp | 8 +++++--- src/engine/Mainloop.cpp | 6 ++++-- src/engine/ServerMainloop.cpp | 2 +- src/frontend/debug_panel.cpp | 6 ++++++ src/frontend/screens/LevelScreen.cpp | 13 ++++++++----- src/frontend/screens/LevelScreen.hpp | 4 +++- src/logic/ChunksController.cpp | 6 ++++-- src/logic/EngineController.cpp | 16 +++++++++++----- src/logic/EngineController.hpp | 3 +++ src/logic/LevelController.cpp | 5 +++++ src/logic/PlayerController.cpp | 1 - src/logic/scripting/lua/libs/libcore.cpp | 6 ++++++ src/logic/scripting/lua/libs/libplayer.cpp | 13 +++++++++---- src/objects/Players.cpp | 13 +++++++++++-- src/objects/Players.hpp | 5 ++++- 16 files changed, 84 insertions(+), 31 deletions(-) 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..936c3b2e 100644 --- a/src/frontend/debug_panel.cpp +++ b/src/frontend/debug_panel.cpp @@ -14,6 +14,7 @@ #include "graphics/render/ChunksRenderer.hpp" #include "logic/scripting/scripting.hpp" #include "objects/Player.hpp" +#include "objects/Players.hpp" #include "objects/Entities.hpp" #include "objects/EntityDef.hpp" #include "physics/Hitbox.hpp" @@ -41,6 +42,7 @@ static std::shared_ptr