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
|
LogicParrot
|
||||||
Luksor
|
Luksor
|
||||||
M10360
|
M10360
|
||||||
maxluchterhand1
|
|
||||||
marmot21
|
marmot21
|
||||||
Masy98
|
Masy98
|
||||||
mathiascode
|
mathiascode
|
||||||
|
maxluchterhand1
|
||||||
MaxwellScroggs
|
MaxwellScroggs
|
||||||
mborland
|
mborland
|
||||||
mBornand
|
mBornand
|
||||||
@ -53,6 +53,7 @@ nesco
|
|||||||
NiLSPACE (formerly STR_Warrior)
|
NiLSPACE (formerly STR_Warrior)
|
||||||
p-mcgowan
|
p-mcgowan
|
||||||
pokechu22
|
pokechu22
|
||||||
|
pwnOrbitals
|
||||||
rs2k
|
rs2k
|
||||||
SamJBarney
|
SamJBarney
|
||||||
Schwertspize
|
Schwertspize
|
||||||
@ -64,8 +65,8 @@ structinf (xdot)
|
|||||||
sweetgiorni
|
sweetgiorni
|
||||||
Sxw1212
|
Sxw1212
|
||||||
Taugeshtu
|
Taugeshtu
|
||||||
tigerw (Tiger Wang)
|
|
||||||
theophriene
|
theophriene
|
||||||
|
tigerw (Tiger Wang)
|
||||||
tonibm19
|
tonibm19
|
||||||
TooAngel
|
TooAngel
|
||||||
UltraCoderRU
|
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.",
|
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 =
|
Constants =
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,7 @@ void cPlugin::Unload(void)
|
|||||||
|
|
||||||
AString cPlugin::GetLocalFolder(void) const
|
AString cPlugin::GetLocalFolder(void) const
|
||||||
{
|
{
|
||||||
return std::string("Plugins/") + m_FolderName;
|
return "Plugins" + cFile::GetPathSeparator() + m_FolderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,36 +164,55 @@ void cPluginManager::InsertDefaultPlugins(cSettingsRepositoryInterface & a_Setti
|
|||||||
|
|
||||||
|
|
||||||
void cPluginManager::Tick(float a_Dt)
|
void cPluginManager::Tick(float a_Dt)
|
||||||
|
{
|
||||||
|
decltype(m_PluginsNeedAction) PluginsNeedAction;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSPluginsNeedAction);
|
||||||
|
std::swap(m_PluginsNeedAction, PluginsNeedAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process deferred actions:
|
||||||
|
for (auto & CurrentPlugin : PluginsNeedAction)
|
||||||
|
{
|
||||||
|
auto & Action = CurrentPlugin.first;
|
||||||
|
auto & Folder = CurrentPlugin.second;
|
||||||
|
|
||||||
|
bool WasLoaded = false;
|
||||||
|
bool WasFound = false;
|
||||||
|
for (auto & Plugin: m_Plugins)
|
||||||
|
{
|
||||||
|
if (Plugin->GetFolderName() == Folder)
|
||||||
|
{
|
||||||
|
WasFound = true;
|
||||||
|
if (Plugin->IsLoaded())
|
||||||
|
{
|
||||||
|
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:
|
// Unload plugins that have been scheduled for unloading:
|
||||||
AStringVector PluginsToUnload;
|
Plugin->Unload();
|
||||||
{
|
break;
|
||||||
cCSLock Lock(m_CSPluginsToUnload);
|
|
||||||
std::swap(m_PluginsToUnload, PluginsToUnload);
|
|
||||||
}
|
}
|
||||||
for (auto & folder: PluginsToUnload)
|
}
|
||||||
{
|
WasLoaded = true;
|
||||||
bool HasUnloaded = false;
|
|
||||||
bool HasFound = false;
|
|
||||||
for (auto & plugin: m_Plugins)
|
|
||||||
{
|
|
||||||
if (plugin->GetFolderName() == folder)
|
|
||||||
{
|
|
||||||
HasFound = true;
|
|
||||||
if (plugin->IsLoaded())
|
|
||||||
{
|
|
||||||
plugin->Unload();
|
|
||||||
HasUnloaded = 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[]
|
} // for plugin - m_Plugins[]
|
||||||
|
|
||||||
@ -1317,8 +1336,18 @@ void cPluginManager::UnloadPluginsNow()
|
|||||||
|
|
||||||
void cPluginManager::UnloadPlugin(const AString & a_PluginFolder)
|
void cPluginManager::UnloadPlugin(const AString & a_PluginFolder)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSPluginsToUnload);
|
cCSLock Lock(m_CSPluginsNeedAction);
|
||||||
m_PluginsToUnload.push_back(a_PluginFolder);
|
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
|
} ; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
/** Defines the deferred actions needed for a plugin */
|
||||||
|
enum class PluginAction
|
||||||
|
{
|
||||||
|
Reload,
|
||||||
|
Unload
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Used as a callback for enumerating bound commands */
|
/** Used as a callback for enumerating bound commands */
|
||||||
class cCommandEnumCallback
|
class cCommandEnumCallback
|
||||||
{
|
{
|
||||||
@ -303,6 +311,10 @@ public:
|
|||||||
Note that this function returns before the plugin is unloaded, to avoid deadlocks. */
|
Note that this function returns before the plugin is unloaded, to avoid deadlocks. */
|
||||||
void UnloadPlugin(const AString & a_PluginFolder); // tolua_export
|
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.
|
/** Loads the plugin from the specified plugin folder.
|
||||||
Returns true if the plugin was loaded successfully or was already loaded before, false otherwise. */
|
Returns true if the plugin was loaded successfully or was already loaded before, false otherwise. */
|
||||||
bool LoadPlugin(const AString & a_PluginFolder); // tolua_export
|
bool LoadPlugin(const AString & a_PluginFolder); // tolua_export
|
||||||
@ -408,13 +420,13 @@ private:
|
|||||||
typedef std::map<AString, cCommandReg> CommandMap;
|
typedef std::map<AString, cCommandReg> CommandMap;
|
||||||
|
|
||||||
|
|
||||||
/** FolderNames of plugins that should be unloaded.
|
/** FolderNames of plugins that need an action (unload, reload, ...).
|
||||||
The plugins will be unloaded within the next call to Tick(), to avoid multithreading issues.
|
The plugins will be acted upon within the next call to Tick(), to avoid multithreading issues.
|
||||||
Protected against multithreaded access by m_CSPluginsToUnload. */
|
Protected against multithreaded access by m_CSPluginsNeedAction. */
|
||||||
AStringVector m_PluginsToUnload;
|
std::vector<std::pair<PluginAction, AString>> m_PluginsNeedAction;
|
||||||
|
|
||||||
/** Protects m_PluginsToUnload against multithreaded access. */
|
/** Protects m_PluginsToUnload against multithreaded access. */
|
||||||
mutable cCriticalSection m_CSPluginsToUnload;
|
mutable cCriticalSection m_CSPluginsNeedAction;
|
||||||
|
|
||||||
/** All plugins that have been found in the Plugins folder. */
|
/** All plugins that have been found in the Plugins folder. */
|
||||||
cPluginPtrs m_Plugins;
|
cPluginPtrs m_Plugins;
|
||||||
|
@ -462,8 +462,16 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (split[0] == "reload")
|
else if (split[0] == "reload")
|
||||||
|
{
|
||||||
|
if (split.size() > 1)
|
||||||
|
{
|
||||||
|
cPluginManager::Get()->ReloadPlugin(split[1]);
|
||||||
|
a_Output.Out("Plugin reload scheduled");
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
cPluginManager::Get()->ReloadPlugins();
|
cPluginManager::Get()->ReloadPlugins();
|
||||||
|
}
|
||||||
a_Output.Finished();
|
a_Output.Finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user