Plugin reload <plugin_name> feature (#4942)
+ Add `reload <pluginname>` * Fixes #365 Co-authored-by: Alexander Harkness <me@bearbin.net> Co-authored-by: pwnOrbitals <c.de-claverie@pm.me> Co-authored-by: Tiger Wang <ziwei.tiger@outlook.com>
This commit is contained in:
parent
410d6c0045
commit
9a548b3b3e
@ -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
|
||||
|
@ -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 =
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<AString, cCommandReg> 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<std::pair<PluginAction, AString>> 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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user