diff options
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.h | 3 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptReloadMgr.cpp | 58 |
3 files changed, 55 insertions, 14 deletions
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 476b87f2440..d7bfc47bf79 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -987,7 +987,7 @@ void ScriptMgr::Initialize() FillSpellSummary(); // Load core scripts - SetScriptContext("___static___"); + SetScriptContext(GetNameOfStaticContext()); // SmartAI AddSC_SmartScripts(); @@ -1042,6 +1042,12 @@ void ScriptMgr::SwapScriptContext(bool initialize) _currentContext.clear(); } +std::string const& ScriptMgr::GetNameOfStaticContext() +{ + static std::string const name = "___static___"; + return name; +} + void ScriptMgr::ReleaseScriptContext(std::string const& context) { sScriptRegistryCompositum->ReleaseContext(context); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index c3deab43ee6..850a979923c 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -875,6 +875,9 @@ class TC_GAME_API ScriptMgr /// calls for better performance (bulk changes). void SwapScriptContext(bool initialize = false); + /// Returns the context name of the static context provided by the worldserver + static std::string const& GetNameOfStaticContext(); + /// Acquires a strong module reference to the module containing the given script name, /// which prevents the shared library which contains the script from unloading. /// The shared library is lazy unloaded as soon as all references to it are released. diff --git a/src/server/game/Scripting/ScriptReloadMgr.cpp b/src/server/game/Scripting/ScriptReloadMgr.cpp index d13fa9c30f0..b0c9b6821d2 100644 --- a/src/server/game/Scripting/ScriptReloadMgr.cpp +++ b/src/server/game/Scripting/ScriptReloadMgr.cpp @@ -194,6 +194,8 @@ public: static Optional<std::shared_ptr<ScriptModule>> CreateFromPath(fs::path const& path, Optional<fs::path> cache_path); + static void ScheduleDelayedDelete(ScriptModule* module); + char const* GetScriptModuleRevisionHash() const override { return _getScriptModuleRevisionHash(); @@ -287,8 +289,13 @@ Optional<std::shared_ptr<ScriptModule>> GetFunctionFromSharedLibrary(handle, "AddScripts", addScripts) && GetFunctionFromSharedLibrary(handle, "GetScriptModule", getScriptModule) && GetFunctionFromSharedLibrary(handle, "GetBuildDirective", getBuildDirective)) - return std::make_shared<ScriptModule>(std::move(holder), getScriptModuleRevisionHash, + { + auto module = new ScriptModule(std::move(holder), getScriptModuleRevisionHash, addScripts, getScriptModule, getBuildDirective, path); + + // Unload the module at the next update tick as soon as all references are removed + return std::shared_ptr<ScriptModule>(module, ScheduleDelayedDelete); + } else { TC_LOG_ERROR("scripts.hotswap", "Could not extract all required functions from the shared library \"%s\"!", @@ -937,13 +944,6 @@ private: } } - sScriptMgr->SetScriptContext(module_name); - (*module)->AddScripts(); - TC_LOG_TRACE("scripts.hotswap", ">> Registered all scripts of module %s.", module_name.c_str()); - - if (swap_context) - sScriptMgr->SwapScriptContext(); - // Create the source listener auto listener = Trinity::make_unique<SourceUpdateListener>( sScriptReloadMgr->GetSourceDirectory() / module_name, @@ -952,8 +952,16 @@ private: // Store the module _known_modules_build_directives.insert(std::make_pair(module_name, (*module)->GetBuildDirective())); _running_script_modules.insert(std::make_pair(module_name, - std::make_pair(std::move(*module), std::move(listener)))); + std::make_pair(*module, std::move(listener)))); _running_script_module_names.insert(std::make_pair(path, module_name)); + + // Process the script loading after the module was registered correctly (#17557). + sScriptMgr->SetScriptContext(module_name); + (*module)->AddScripts(); + TC_LOG_TRACE("scripts.hotswap", ">> Registered all scripts of module %s.", module_name.c_str()); + + if (swap_context) + sScriptMgr->SwapScriptContext(); } void ProcessReloadScriptModule(fs::path const& path) @@ -1435,6 +1443,26 @@ private: fs::path temporary_cache_path_; }; +class ScriptModuleDeleteMessage +{ +public: + explicit ScriptModuleDeleteMessage(ScriptModule* module) + : module_(module) { } + + void operator() (HotSwapScriptReloadMgr*) + { + module_.reset(); + } + +private: + std::unique_ptr<ScriptModule> module_; +}; + +void ScriptModule::ScheduleDelayedDelete(ScriptModule* module) +{ + sScriptReloadMgr->QueueMessage(ScriptModuleDeleteMessage(module)); +} + /// Maps efsw actions to strings static char const* ActionToString(efsw::Action action) { @@ -1592,11 +1620,15 @@ void SourceUpdateListener::handleFileAction(efsw::WatchID watchid, std::string c std::shared_ptr<ModuleReference> ScriptReloadMgr::AcquireModuleReferenceOfContext(std::string const& context) { - auto const itr = sScriptReloadMgr->_running_script_modules.find(context); - if (itr != sScriptReloadMgr->_running_script_modules.end()) - return itr->second.first; - else + // Return empty references for the static context exported by the worldserver + if (context == ScriptMgr::GetNameOfStaticContext()) return { }; + + auto const itr = sScriptReloadMgr->_running_script_modules.find(context); + ASSERT(itr != sScriptReloadMgr->_running_script_modules.end() + && "Requested a reference to a non existent script context!"); + + return itr->second.first; } // Returns the full hot swap implemented ScriptReloadMgr |