diff --git a/CONTRIBUTORS b/CONTRIBUTORS index cf9841ff4..2eb5b05bb 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -37,10 +37,10 @@ lkolbly LogicParrot Luksor M10360 -maxluchterhand1 marmot21 Masy98 mathiascode +maxluchterhand1 MaxwellScroggs mborland mBornand @@ -53,6 +53,7 @@ nesco NiLSPACE (formerly STR_Warrior) p-mcgowan pokechu22 +pwnOrbitals rs2k SamJBarney Schwertspize @@ -64,8 +65,8 @@ structinf (xdot) sweetgiorni Sxw1212 Taugeshtu -tigerw (Tiger Wang) theophriene +tigerw (Tiger Wang) tonibm19 TooAngel UltraCoderRU diff --git a/Server/Plugins/APIDump/Classes/Plugins.lua b/Server/Plugins/APIDump/Classes/Plugins.lua index 63f4172e6..adc6bf0b3 100644 --- a/Server/Plugins/APIDump/Classes/Plugins.lua +++ b/Server/Plugins/APIDump/Classes/Plugins.lua @@ -675,6 +675,17 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); }, Notes = "Queues the specified plugin to be unloaded. To avoid deadlocks, the unloading happens in the main tick thread asynchronously.", }, + ReloadPlugin = + { + Params = + { + { + Name = "PluginName", + Type = "string", + }, + }, + Notes = "Queues the specified plugin to be reloaded. To avoid deadlocks, the reloading happens in the main tick thread asynchronously.", + } }, Constants = { diff --git a/src/Bindings/Plugin.cpp b/src/Bindings/Plugin.cpp index de82fbca2..3f1645188 100644 --- a/src/Bindings/Plugin.cpp +++ b/src/Bindings/Plugin.cpp @@ -45,7 +45,7 @@ void cPlugin::Unload(void) AString cPlugin::GetLocalFolder(void) const { - return std::string("Plugins/") + m_FolderName; + return "Plugins" + cFile::GetPathSeparator() + m_FolderName; } diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 6593097dd..310a3968b 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -165,35 +165,54 @@ void cPluginManager::InsertDefaultPlugins(cSettingsRepositoryInterface & a_Setti void cPluginManager::Tick(float a_Dt) { - // Unload plugins that have been scheduled for unloading: - AStringVector PluginsToUnload; + decltype(m_PluginsNeedAction) PluginsNeedAction; { - cCSLock Lock(m_CSPluginsToUnload); - std::swap(m_PluginsToUnload, PluginsToUnload); + cCSLock Lock(m_CSPluginsNeedAction); + std::swap(m_PluginsNeedAction, PluginsNeedAction); } - for (auto & folder: PluginsToUnload) + + // Process deferred actions: + for (auto & CurrentPlugin : PluginsNeedAction) { - bool HasUnloaded = false; - bool HasFound = false; - for (auto & plugin: m_Plugins) + auto & Action = CurrentPlugin.first; + auto & Folder = CurrentPlugin.second; + + bool WasLoaded = false; + bool WasFound = false; + for (auto & Plugin: m_Plugins) { - if (plugin->GetFolderName() == folder) + if (Plugin->GetFolderName() == Folder) { - HasFound = true; - if (plugin->IsLoaded()) + WasFound = true; + if (Plugin->IsLoaded()) { - plugin->Unload(); - HasUnloaded = true; + switch (Action) + { + case PluginAction::Reload : + { + // Reload plugins by unloading, then loading: + Plugin->Unload(); + Plugin->Load(); + break; + } + case PluginAction::Unload : + { + // Unload plugins that have been scheduled for unloading: + Plugin->Unload(); + break; + } + } + WasLoaded = true; } } } - if (!HasFound) + if (!WasFound) { - LOG("Cannot unload plugin in folder \"%s\", there's no such plugin folder", folder.c_str()); + LOG("Cannot act on plugin in folder \"%s\", there's no such plugin folder", Folder.c_str()); } - else if (!HasUnloaded) + else if (!WasLoaded) { - LOG("Cannot unload plugin in folder \"%s\", it has not been loaded.", folder.c_str()); + LOG("Cannot act on plugin in folder \"%s\", it has not been loaded.", Folder.c_str()); } } // for plugin - m_Plugins[] @@ -1317,8 +1336,18 @@ void cPluginManager::UnloadPluginsNow() void cPluginManager::UnloadPlugin(const AString & a_PluginFolder) { - cCSLock Lock(m_CSPluginsToUnload); - m_PluginsToUnload.push_back(a_PluginFolder); + cCSLock Lock(m_CSPluginsNeedAction); + m_PluginsNeedAction.emplace_back(PluginAction::Unload, a_PluginFolder); +} + + + + + +void cPluginManager::ReloadPlugin(const AString & a_PluginFolder) +{ + cCSLock Lock(m_CSPluginsNeedAction); + m_PluginsNeedAction.emplace_back(PluginAction::Reload, a_PluginFolder); } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 353950f18..8d75509a1 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -162,6 +162,14 @@ public: } ; // tolua_export + /** Defines the deferred actions needed for a plugin */ + enum class PluginAction + { + Reload, + Unload + }; + + /** Used as a callback for enumerating bound commands */ class cCommandEnumCallback { @@ -303,6 +311,10 @@ public: Note that this function returns before the plugin is unloaded, to avoid deadlocks. */ void UnloadPlugin(const AString & a_PluginFolder); // tolua_export + /** Queues the specified plugin to be reloaded in the next call to Tick(). + Note that this function returns before the plugin is unloaded, to avoid deadlocks. */ + void ReloadPlugin(const AString & a_PluginFolder); // tolua_export + /** Loads the plugin from the specified plugin folder. Returns true if the plugin was loaded successfully or was already loaded before, false otherwise. */ bool LoadPlugin(const AString & a_PluginFolder); // tolua_export @@ -408,13 +420,13 @@ private: typedef std::map CommandMap; - /** FolderNames of plugins that should be unloaded. - The plugins will be unloaded within the next call to Tick(), to avoid multithreading issues. - Protected against multithreaded access by m_CSPluginsToUnload. */ - AStringVector m_PluginsToUnload; + /** FolderNames of plugins that need an action (unload, reload, ...). + The plugins will be acted upon within the next call to Tick(), to avoid multithreading issues. + Protected against multithreaded access by m_CSPluginsNeedAction. */ + std::vector> m_PluginsNeedAction; /** Protects m_PluginsToUnload against multithreaded access. */ - mutable cCriticalSection m_CSPluginsToUnload; + mutable cCriticalSection m_CSPluginsNeedAction; /** All plugins that have been found in the Plugins folder. */ cPluginPtrs m_Plugins; diff --git a/src/Server.cpp b/src/Server.cpp index 67629ef2c..2730d3511 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -463,7 +463,15 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac } else if (split[0] == "reload") { - cPluginManager::Get()->ReloadPlugins(); + if (split.size() > 1) + { + cPluginManager::Get()->ReloadPlugin(split[1]); + a_Output.Out("Plugin reload scheduled"); + } + else + { + cPluginManager::Get()->ReloadPlugins(); + } a_Output.Finished(); return; }