From 12767cf5585bdaf2ff049b4a17acccce30f746f5 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sat, 25 Jan 2025 14:40:58 +0000 Subject: [PATCH] fix: resolve a crash caused by compatibility issues with the script API during server reload --- .../event/handlers/actor_gameplay_handler.cpp | 5 +++ .../event/handlers/actor_gameplay_handler.h | 1 + .../event/handlers/block_gameplay_handler.cpp | 5 +++ .../event/handlers/block_gameplay_handler.h | 1 + .../event/handlers/level_gameplay_handler.cpp | 5 +++ .../event/handlers/level_gameplay_handler.h | 1 + .../handlers/player_gameplay_handler.cpp | 5 +++ .../event/handlers/player_gameplay_handler.h | 1 + .../handlers/scripting_event_handler.cpp | 5 +++ .../event/handlers/scripting_event_handler.h | 1 + .../handlers/server_network_event_handler.cpp | 5 +++ .../handlers/server_network_event_handler.h | 1 + src/endstone/core/server.cpp | 37 +++++++++++-------- src/endstone/core/server.h | 15 +++++++- 14 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/endstone/core/event/handlers/actor_gameplay_handler.cpp b/src/endstone/core/event/handlers/actor_gameplay_handler.cpp index 3af985446..532f06e9a 100644 --- a/src/endstone/core/event/handlers/actor_gameplay_handler.cpp +++ b/src/endstone/core/event/handlers/actor_gameplay_handler.cpp @@ -54,6 +54,11 @@ GameplayHandlerResult EndstoneActorGameplayHandler::handleEve return handle_->handleEvent(event); } +std::unique_ptr EndstoneActorGameplayHandler::unwrap() +{ + return std::move(handle_); +} + bool EndstoneActorGameplayHandler::handleEvent(const ActorKilledEvent &event) { if (const auto *mob = WeakEntityRef(event.actor_context).tryUnwrap<::Mob>(); mob && !mob->isPlayer()) { diff --git a/src/endstone/core/event/handlers/actor_gameplay_handler.h b/src/endstone/core/event/handlers/actor_gameplay_handler.h index 5c3412c8c..b11a4716b 100644 --- a/src/endstone/core/event/handlers/actor_gameplay_handler.h +++ b/src/endstone/core/event/handlers/actor_gameplay_handler.h @@ -26,6 +26,7 @@ class EndstoneActorGameplayHandler final : public ActorGameplayHandler { HandlerResult handleEvent(const ActorGameplayEvent &event) override; GameplayHandlerResult handleEvent(const ActorGameplayEvent &event) override; GameplayHandlerResult handleEvent(MutableActorGameplayEvent &event) override; + std::unique_ptr unwrap(); private: bool handleEvent(const ActorKilledEvent &event); diff --git a/src/endstone/core/event/handlers/block_gameplay_handler.cpp b/src/endstone/core/event/handlers/block_gameplay_handler.cpp index be9cb1da9..18ed63b03 100644 --- a/src/endstone/core/event/handlers/block_gameplay_handler.cpp +++ b/src/endstone/core/event/handlers/block_gameplay_handler.cpp @@ -76,6 +76,11 @@ GameplayHandlerResult EndstoneBlockGameplayHandler::handleEve return std::visit(visitor, event.variant); } +std::unique_ptr EndstoneBlockGameplayHandler::unwrap() +{ + return std::move(handle_); +} + bool EndstoneBlockGameplayHandler::handleEvent(const PistonActionEvent &event) { // TODO(event): piston events diff --git a/src/endstone/core/event/handlers/block_gameplay_handler.h b/src/endstone/core/event/handlers/block_gameplay_handler.h index 55189789d..b02e963b3 100644 --- a/src/endstone/core/event/handlers/block_gameplay_handler.h +++ b/src/endstone/core/event/handlers/block_gameplay_handler.h @@ -28,6 +28,7 @@ class EndstoneBlockGameplayHandler final : public BlockGameplayHandler { GameplayHandlerResult> handleEvent( const BlockGameplayEvent> &event) override; GameplayHandlerResult handleEvent(MutableBlockGameplayEvent &event) override; + std::unique_ptr unwrap(); private: bool handleEvent(const PistonActionEvent &event); diff --git a/src/endstone/core/event/handlers/level_gameplay_handler.cpp b/src/endstone/core/event/handlers/level_gameplay_handler.cpp index 61c312364..f74659a63 100644 --- a/src/endstone/core/event/handlers/level_gameplay_handler.cpp +++ b/src/endstone/core/event/handlers/level_gameplay_handler.cpp @@ -57,6 +57,11 @@ GameplayHandlerResult EndstoneLevelGameplayHandler::handleEve return std::visit(visitor, event.variant); } +std::unique_ptr EndstoneLevelGameplayHandler::unwrap() +{ + return std::move(handle_); +} + bool EndstoneLevelGameplayHandler::handleEvent(const LevelAddedActorEvent &event) { if (auto *actor = WeakEntityRef(event.actor).tryUnwrap<::Actor>(); actor && !actor->isPlayer()) { diff --git a/src/endstone/core/event/handlers/level_gameplay_handler.h b/src/endstone/core/event/handlers/level_gameplay_handler.h index 8acb5e9f1..35da24cc1 100644 --- a/src/endstone/core/event/handlers/level_gameplay_handler.h +++ b/src/endstone/core/event/handlers/level_gameplay_handler.h @@ -25,6 +25,7 @@ class EndstoneLevelGameplayHandler final : public LevelGameplayHandler { explicit EndstoneLevelGameplayHandler(std::unique_ptr handle); HandlerResult handleEvent(LevelGameplayEvent const &event) override; GameplayHandlerResult handleEvent(MutableLevelGameplayEvent &event) override; + std::unique_ptr unwrap(); private: bool handleEvent(const LevelAddedActorEvent &event); diff --git a/src/endstone/core/event/handlers/player_gameplay_handler.cpp b/src/endstone/core/event/handlers/player_gameplay_handler.cpp index 5b817a40d..0342d94bb 100644 --- a/src/endstone/core/event/handlers/player_gameplay_handler.cpp +++ b/src/endstone/core/event/handlers/player_gameplay_handler.cpp @@ -94,6 +94,11 @@ GameplayHandlerResult EndstonePlayerGameplayHandler::handleEv return std::visit(visitor, event.variant); } +std::unique_ptr EndstonePlayerGameplayHandler::unwrap() +{ + return std::move(handle_); +} + bool EndstonePlayerGameplayHandler::handleEvent(const PlayerDamageEvent &event) { if (auto *player = WeakEntityRef(event.player).tryUnwrap<::Player>(); player) { diff --git a/src/endstone/core/event/handlers/player_gameplay_handler.h b/src/endstone/core/event/handlers/player_gameplay_handler.h index ff81702e3..9978598f5 100644 --- a/src/endstone/core/event/handlers/player_gameplay_handler.h +++ b/src/endstone/core/event/handlers/player_gameplay_handler.h @@ -26,6 +26,7 @@ class EndstonePlayerGameplayHandler final : public PlayerGameplayHandler { HandlerResult handleEvent(const PlayerGameplayEvent &event) override; GameplayHandlerResult handleEvent(const PlayerGameplayEvent &event) override; GameplayHandlerResult handleEvent(MutablePlayerGameplayEvent &event) override; + std::unique_ptr unwrap(); private: bool handleEvent(const PlayerDamageEvent &event); diff --git a/src/endstone/core/event/handlers/scripting_event_handler.cpp b/src/endstone/core/event/handlers/scripting_event_handler.cpp index 0213baf77..d4a332eca 100644 --- a/src/endstone/core/event/handlers/scripting_event_handler.cpp +++ b/src/endstone/core/event/handlers/scripting_event_handler.cpp @@ -50,6 +50,11 @@ GameplayHandlerResult EndstoneScriptingEventHandler::handleEv return std::visit(visitor, event.variant); } +std::unique_ptr EndstoneScriptingEventHandler::unwrap() +{ + return std::move(handle_); +} + bool EndstoneScriptingEventHandler::handleEvent(const ScriptCommandMessageEvent &event) { const auto &server = entt::locator::value(); diff --git a/src/endstone/core/event/handlers/scripting_event_handler.h b/src/endstone/core/event/handlers/scripting_event_handler.h index 2eecaa153..31b7f56e7 100644 --- a/src/endstone/core/event/handlers/scripting_event_handler.h +++ b/src/endstone/core/event/handlers/scripting_event_handler.h @@ -27,6 +27,7 @@ class EndstoneScriptingEventHandler final : public ScriptingEventHandler { MutableScriptingGameplayEvent &event) override; GameplayHandlerResult handleEvent( const ScriptingGameplayEvent &event) override; + std::unique_ptr unwrap(); private: bool handleEvent(const ScriptCommandMessageEvent &event); diff --git a/src/endstone/core/event/handlers/server_network_event_handler.cpp b/src/endstone/core/event/handlers/server_network_event_handler.cpp index ad6235d7a..a73f3b318 100644 --- a/src/endstone/core/event/handlers/server_network_event_handler.cpp +++ b/src/endstone/core/event/handlers/server_network_event_handler.cpp @@ -41,6 +41,11 @@ GameplayHandlerResult EndstoneServerNetworkEventHandler::hand return std::visit(visitor, event.variant); } +std::unique_ptr EndstoneServerNetworkEventHandler::unwrap() +{ + return std::move(handle_); +} + bool EndstoneServerNetworkEventHandler::handleEvent(ChatEvent &event) { const auto &server = entt::locator::value(); diff --git a/src/endstone/core/event/handlers/server_network_event_handler.h b/src/endstone/core/event/handlers/server_network_event_handler.h index 2182ef43a..9efb910f0 100644 --- a/src/endstone/core/event/handlers/server_network_event_handler.h +++ b/src/endstone/core/event/handlers/server_network_event_handler.h @@ -26,6 +26,7 @@ class EndstoneServerNetworkEventHandler final : public ServerNetworkEventHandler explicit EndstoneServerNetworkEventHandler(std::unique_ptr handle); GameplayHandlerResult handleEvent( MutableServerNetworkGameplayEvent &event) override; + std::unique_ptr unwrap(); private: bool handleEvent(ChatEvent &event); diff --git a/src/endstone/core/server.cpp b/src/endstone/core/server.cpp index 20f820e25..6688f36f9 100644 --- a/src/endstone/core/server.cpp +++ b/src/endstone/core/server.cpp @@ -72,6 +72,7 @@ EndstoneServer::~EndstoneServer() { py::gil_scoped_acquire acquire{}; disablePlugins(); + unregisterEventListeners(); } void EndstoneServer::init(ServerInstance &server_instance) @@ -98,7 +99,7 @@ void EndstoneServer::setLevel(::Level &level) scoreboard_ = std::make_unique(level.getScoreboard()); command_map_ = std::make_unique(*this); loadResourcePacks(); - registerGameplayHandlers(); + registerEventListeners(); level._getPlayerDeathManager()->sender_.reset(); // prevent BDS from sending the death message enablePlugins(PluginLoadOrder::PostWorld); ServerLoadEvent event{ServerLoadEvent::LoadType::Startup}; @@ -154,22 +155,26 @@ void EndstoneServer::loadResourcePacks() std::make_move_iterator(pack_stack->stack.end())); } -void EndstoneServer::registerGameplayHandlers() +void EndstoneServer::registerEventListeners() { auto &level = level_->getHandle(); - level.getActorEventCoordinator().actor_gameplay_handler_ = std::make_unique( - std::move(level.getActorEventCoordinator().actor_gameplay_handler_)); - level.getBlockEventCoordinator().block_gameplay_handler_ = std::make_unique( - std::move(level.getBlockEventCoordinator().block_gameplay_handler_)); - level.getLevelEventCoordinator().level_gameplay_handler_ = std::make_unique( - std::move(level.getLevelEventCoordinator().level_gameplay_handler_)); - level.getServerPlayerEventCoordinator().player_gameplay_handler_ = std::make_unique( - std::move(level.getServerPlayerEventCoordinator().player_gameplay_handler_)); - level.getScriptingEventCoordinator().scripting_event_handler_ = std::make_unique( - std::move(level.getScriptingEventCoordinator().scripting_event_handler_)); - level.getServerNetworkEventCoordinator().server_network_event_handler_ = - std::make_unique( - std::move(level.getServerNetworkEventCoordinator().server_network_event_handler_)); + wrap(level.getActorEventCoordinator().actor_gameplay_handler_); + wrap(level.getBlockEventCoordinator().block_gameplay_handler_); + wrap(level.getLevelEventCoordinator().level_gameplay_handler_); + wrap(level.getServerPlayerEventCoordinator().player_gameplay_handler_); + wrap(level.getScriptingEventCoordinator().scripting_event_handler_); + wrap(level.getServerNetworkEventCoordinator().server_network_event_handler_); +} + +void EndstoneServer::unregisterEventListeners() +{ + auto &level = level_->getHandle(); + unwrap(level.getActorEventCoordinator().actor_gameplay_handler_); + unwrap(level.getBlockEventCoordinator().block_gameplay_handler_); + unwrap(level.getLevelEventCoordinator().level_gameplay_handler_); + unwrap(level.getServerPlayerEventCoordinator().player_gameplay_handler_); + unwrap(level.getScriptingEventCoordinator().scripting_event_handler_); + unwrap(level.getServerNetworkEventCoordinator().server_network_event_handler_); } std::string EndstoneServer::getName() const @@ -366,9 +371,11 @@ void EndstoneServer::reload() { plugin_manager_->clearPlugins(); command_map_->clearCommands(); + unregisterEventListeners(); reloadData(); // TODO(server): Wait for at most 2.5 seconds for all async tasks to finish, otherwise issue a warning + registerEventListeners(); loadPlugins(); enablePlugins(PluginLoadOrder::Startup); enablePlugins(PluginLoadOrder::PostWorld); diff --git a/src/endstone/core/server.h b/src/endstone/core/server.h index e21d74de7..5f962e726 100644 --- a/src/endstone/core/server.h +++ b/src/endstone/core/server.h @@ -112,7 +112,7 @@ class EndstoneServer : public Server { void init(ServerInstance &server_instance); void setLevel(::Level &level); void setResourcePackRepository(Bedrock::NotNullNonOwnerPtr repo); - PackSource &getPackSource() const; + [[nodiscard]] PackSource &getPackSource() const; [[nodiscard]] ServerInstance &getServer() const; @@ -122,7 +122,18 @@ class EndstoneServer : public Server { friend class EndstonePlayer; void enablePlugin(Plugin &plugin); void loadResourcePacks(); - void registerGameplayHandlers(); + template + void wrap(std::unique_ptr &target) + { + target = std::make_unique(std::move(target)); + } + void registerEventListeners(); + template + void unwrap(std::unique_ptr &target) + { + target = static_cast(target.get())->unwrap(); + } + void unregisterEventListeners(); ServerInstance *server_instance_{nullptr}; Logger &logger_;