Add HookPluginUnload() and UnhookPluginUnload() functions

This commit is contained in:
Vladimir 2021-04-03 14:25:52 +03:00 committed by David Anderson
parent e6129ab2d9
commit c874703136
5 changed files with 152 additions and 0 deletions

View File

@ -75,6 +75,8 @@ public:
virtual IPluginIterator *GetPluginIterator() = 0; virtual IPluginIterator *GetPluginIterator() = 0;
virtual void OnLibraryAction(const char *name, LibraryAction action) = 0; virtual void OnLibraryAction(const char *name, LibraryAction action) = 0;
virtual bool LibraryExists(const char *name) = 0; virtual bool LibraryExists(const char *name) = 0;
virtual bool HookPluginUnload(IPlugin *pl, IPluginFunction *fwd) = 0;
virtual bool UnhookPluginUnload(IPlugin *pl, IPluginFunction *fwd) = 0;
virtual SMPlugin *FindPluginByOrder(unsigned num) = 0; virtual SMPlugin *FindPluginByOrder(unsigned num) = 0;
virtual SMPlugin *FindPluginByIdentity(IdentityToken_t *ident) = 0; virtual SMPlugin *FindPluginByIdentity(IdentityToken_t *ident) = 0;
virtual SMPlugin *FindPluginByContext(IPluginContext *ctx) = 0; virtual SMPlugin *FindPluginByContext(IPluginContext *ctx) = 0;

View File

@ -1505,6 +1505,8 @@ void CPluginManager::Purge(CPlugin *plugin)
(*iter)->OnPluginUnloaded(plugin); (*iter)->OnPluginUnloaded(plugin);
} }
CallUnloadHooks(plugin);
plugin->DropEverything(); plugin->DropEverything();
for (ListenerIter iter(m_listeners); !iter.done(); iter.next()) for (ListenerIter iter(m_listeners); !iter.done(); iter.next())
@ -1601,6 +1603,19 @@ void CPluginManager::OnSourceModShutdown()
forwardsys->ReleaseForward(m_pOnLibraryAdded); forwardsys->ReleaseForward(m_pOnLibraryAdded);
forwardsys->ReleaseForward(m_pOnLibraryRemoved); forwardsys->ReleaseForward(m_pOnLibraryRemoved);
{
std::list<PluginUnloadHookInfo>::iterator iter = m_PluginUnloadHooks.begin();
while (iter!=m_PluginUnloadHooks.end())
{
forwardsys->ReleaseForward(iter->pForward);
iter++;
}
m_PluginUnloadHooks.clear();
}
} }
ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key, ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
@ -2202,6 +2217,72 @@ bool CPluginManager::LibraryExists(const char *lib)
return false; return false;
} }
bool CPluginManager::HookPluginUnload(IPlugin *pPluginToHook, IPluginFunction *pHookFunction)
{
{
std::list<PluginUnloadHookInfo>::iterator iter = m_PluginUnloadHooks.begin();
while (iter!=m_PluginUnloadHooks.end())
{
if(iter->pPluginTarget == pPluginToHook)
{
return iter->pForward->AddFunction(pHookFunction);
}
iter++;
}
}
IChangeableForward *pForward = forwardsys->CreateForwardEx(nullptr, ET_Hook, 1, nullptr, Param_Cell);
m_PluginUnloadHooks.push_back({pPluginToHook, pForward});
return pForward->AddFunction(pHookFunction);
}
bool CPluginManager::UnhookPluginUnload(IPlugin *pPluginToUnhook, IPluginFunction *pHookFunction)
{
std::list<PluginUnloadHookInfo>::iterator iter = m_PluginUnloadHooks.begin();
while (iter!=m_PluginUnloadHooks.end())
{
if(iter->pPluginTarget == pPluginToUnhook)
{
return iter->pForward->RemoveFunction(pHookFunction);
}
iter++;
}
return false;
}
void CPluginManager::CallUnloadHooks(IPlugin *pTarget)
{
std::list<PluginUnloadHookInfo>::iterator iter = m_PluginUnloadHooks.begin();
IChangeableForward *pForwardToCall;
while (iter!=m_PluginUnloadHooks.end())
{
// There can only be one unique
if(iter->pPluginTarget == pTarget)
{
pForwardToCall = iter->pForward;
pForwardToCall->PushCell((cell_t)pTarget);
pForwardToCall->Execute();
pForwardToCall->Cancel();
m_PluginUnloadHooks.erase(iter);
return;
}
iter++;
}
}
void CPluginManager::AllPluginsLoaded() void CPluginManager::AllPluginsLoaded()
{ {
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) for (PluginIter iter(m_plugins); !iter.done(); iter.next())

View File

@ -425,6 +425,12 @@ public:
bool LibraryExists(const char *lib); bool LibraryExists(const char *lib);
bool HookPluginUnload(IPlugin *pPluginToHook, IPluginFunction *pHookFunction);
bool UnhookPluginUnload(IPlugin *pPluginToUnhook, IPluginFunction *pHookFunction);
void CallUnloadHooks(IPlugin *pTarget);
bool ReloadPlugin(CPlugin *pl, bool print=false); bool ReloadPlugin(CPlugin *pl, bool print=false);
void UnloadAll(); void UnloadAll();
@ -523,6 +529,12 @@ private:
// Forwards // Forwards
IForward *m_pOnLibraryAdded; IForward *m_pOnLibraryAdded;
IForward *m_pOnLibraryRemoved; IForward *m_pOnLibraryRemoved;
struct PluginUnloadHookInfo
{
IPlugin *pPluginTarget;
IChangeableForward *pForward;
};
std::list<PluginUnloadHookInfo> m_PluginUnloadHooks;
}; };
extern CPluginManager g_PluginSys; extern CPluginManager g_PluginSys;

View File

@ -637,6 +637,34 @@ static cell_t FindPluginByNumber(IPluginContext *pContext, const cell_t *params)
return pPlugin->GetMyHandle(); return pPlugin->GetMyHandle();
} }
static cell_t HookPluginUnload(IPluginContext *pContext, const cell_t *params)
{
IPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
if (!pPlugin)
{
return false;
}
IPluginFunction *pCallback = pContext->GetFunctionById(params[3]);
return scripts->HookPluginUnload(pPlugin, pCallback);
}
static cell_t UnhookPluginUnload(IPluginContext *pContext, const cell_t *params)
{
IPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
if (!pPlugin)
{
return false;
}
IPluginFunction *pCallback = pContext->GetFunctionById(params[3]);
return scripts->UnhookPluginUnload(pPlugin, pCallback);
}
static cell_t VerifyCoreVersion(IPluginContext *pContext, const cell_t *params) static cell_t VerifyCoreVersion(IPluginContext *pContext, const cell_t *params)
{ {
return 4; return 4;
@ -969,6 +997,8 @@ REGISTER_NATIVES(coreNatives)
{"LogToFileEx", LogToFileEx}, {"LogToFileEx", LogToFileEx},
{"GetExtensionFileStatus", GetExtensionFileStatus}, {"GetExtensionFileStatus", GetExtensionFileStatus},
{"FindPluginByNumber", FindPluginByNumber}, {"FindPluginByNumber", FindPluginByNumber},
{"HookPluginUnload", HookPluginUnload},
{"UnhookPluginUnload", UnhookPluginUnload},
{"VerifyCoreVersion", VerifyCoreVersion}, {"VerifyCoreVersion", VerifyCoreVersion},
{"GetFeatureStatus", GetFeatureStatus}, {"GetFeatureStatus", GetFeatureStatus},
{"RequireFeature", RequireFeature}, {"RequireFeature", RequireFeature},

View File

@ -84,6 +84,13 @@ enum APLRes
APLRes_SilentFailure /**< Plugin shouldn't load but do so silently */ APLRes_SilentFailure /**< Plugin shouldn't load but do so silently */
}; };
/**
* Called when a plugin unloaded.
*
* @param plugin Plugin Handle who unloaded.
*/
typedef PluginUnloaded = function void (Handle plugin);
methodmap GameData < Handle methodmap GameData < Handle
{ {
// Loads a game config file. // Loads a game config file.
@ -319,6 +326,26 @@ native bool GetPluginInfo(Handle plugin, PluginInfo info, char[] buffer, int max
*/ */
native Handle FindPluginByNumber(int order_num); native Handle FindPluginByNumber(int order_num);
/**
* Creates a hook for when a plugin unloaded.
*
* @param plugin Plugin Handle to hook.
* @param callback An PluginUnloaded function pointer.
*
* @return True on success, false otherwise.
*/
native bool HookPluginUnload(Handle plugin, PluginUnloaded callback);
/**
* Removes a hook for when a plugin unloaded.
*
* @param plugin Plugin Handle to hook.
* @param callback An PluginUnloaded function pointer.
*
* @return True on success, false otherwise.
*/
native bool UnhookPluginUnload(Handle plugin, PluginUnloaded callback);
/** /**
* Causes the plugin to enter a failed state. An error will be thrown and * Causes the plugin to enter a failed state. An error will be thrown and
* the plugin will be paused until it is unloaded or reloaded. * the plugin will be paused until it is unloaded or reloaded.