diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index ccd33c69..7cf0461b 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -5,6 +5,7 @@ #include "sourcemm_api.h" #include "PluginSys.h" #include "sm_srvcmds.h" +#include CExtensionManager g_Extensions; IdentityType_t g_ExtType; @@ -15,6 +16,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max) m_pAPI = NULL; m_pIdentToken = NULL; m_PlId = 0; + unload_code = 0; char path[PLATFORM_MAX_PATH+1]; g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename); @@ -349,6 +351,27 @@ void CExtensionManager::OnPluginDestroyed(IPlugin *plugin) } } +CExtension *CExtensionManager::FindByOrder(unsigned int num) +{ + if (num < 1 || num > m_Libs.size()) + { + return NULL; + } + + List::iterator iter = m_Libs.begin(); + + while (iter != m_Libs.end()) + { + if (--num == 0) + { + return (*iter); + } + iter++; + } + + return NULL; +} + bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) @@ -376,9 +399,9 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) List::iterator p_iter = pExt->m_Plugins.begin(); while (p_iter != pExt->m_Plugins.end()) { + /* We have to manually unlink ourselves here, since we're no longer being managed */ g_PluginSys.UnloadPlugin((*p_iter)); - /* It should already have been removed! */ - assert(pExt->m_Plugins.find((*p_iter)) != pExt->m_Plugins.end()); + p_iter = pExt->m_Plugins.erase(p_iter); } /* Notify and/or unload all dependencies */ @@ -392,6 +415,10 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) { continue; } + if (pDep == pExt) + { + continue; + } /* Now, get its dependency list */ bool dropped = false; List::iterator i_iter = pDep->m_Deps.begin(); @@ -524,10 +551,122 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no"); } return; + } else if (strcmp(cmd, "unload") == 0) { + if (argcount < 4) + { + g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]"); + return; + } + + const char *arg = g_RootMenu.GetArgument(3); + unsigned int num = atoi(arg); + CExtension *pExt = FindByOrder(num); + + if (!pExt) + { + g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num); + return; + } + + if (argcount > 4 && pExt->unload_code) + { + const char *unload = g_RootMenu.GetArgument(4); + if (pExt->unload_code == atoi(unload)) + { + char filename[PLATFORM_MAX_PATH+1]; + snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); + UnloadExtension(pExt); + g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename); + } else { + g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code); + } + return; + } + + if (!pExt->IsLoaded() + || (!pExt->m_Deps.size() && !pExt->m_Plugins.size())) + { + char filename[PLATFORM_MAX_PATH+1]; + snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); + UnloadExtension(pExt); + g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename); + return; + } else { + List plugins; + if (pExt->m_Deps.size()) + { + g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename()); + List::iterator iter; + CExtension *pOther; + /* Get list of all extensions */ + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + { + List::iterator i_iter; + pOther = (*iter); + if (!pOther->IsLoaded() || pOther == pExt) + { + continue; + } + /* Get their dependencies */ + for (i_iter=pOther->m_Deps.begin(); + i_iter!=pOther->m_Deps.end(); + i_iter++) + { + /* Is this dependency to us? */ + if ((*i_iter).owner != pExt) + { + continue; + } + /* Will our dependent care? */ + if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface)) + { + g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename()); + /* Add to plugin unload list */ + List::iterator p_iter; + for (p_iter=pOther->m_Plugins.begin(); + p_iter!=pOther->m_Plugins.end(); + p_iter++) + { + if (plugins.find((*p_iter)) == plugins.end()) + { + plugins.push_back((*p_iter)); + } + } + } + } + } + } + if (pExt->m_Plugins.size()) + { + g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename()); + List::iterator iter; + IPlugin *pPlugin; + for (iter = pExt->m_Plugins.begin(); iter != pExt->m_Plugins.end(); iter++) + { + pPlugin = (*iter); + if (plugins.find(pPlugin) == plugins.end()) + { + plugins.push_back(pPlugin); + } + } + for (iter = plugins.begin(); iter != plugins.end(); iter++) + { + pPlugin = (*iter); + g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename()); + } + } + srand(static_cast(time(NULL))); + pExt->unload_code = (rand() % 877) + 123; //123 to 999 + g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename()); + g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code); + + return; + } } } g_RootMenu.ConsolePrint("SourceMod Extensions Menu:"); g_RootMenu.DrawGenericOption("info", "Extra extension information"); g_RootMenu.DrawGenericOption("list", "List extensions"); + g_RootMenu.DrawGenericOption("unload", "Unload an extension"); } diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index b56da392..ec3d9a05 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -44,6 +44,7 @@ private: List m_Interfaces; List m_Plugins; PluginId m_PlId; + unsigned int unload_code; }; class CExtensionManager : @@ -72,6 +73,8 @@ public: void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); void AddInterface(IExtension *pOwner, SMInterface *pInterface); void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin); +private: + CExtension *FindByOrder(unsigned int num); private: List m_Libs; }; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index dc43ca22..aaef6ef7 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -966,7 +966,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) List::iterator iter; IPluginsListener *pListener; - if (pPlugin->GetStatus() >= Plugin_Error) + if (pPlugin->GetStatus() <= Plugin_Error) { /* Notify listeners of unloading */ for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 4d96b3f8..54789628 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -113,7 +113,7 @@ bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface) bool ShareSystem::RequestInterface(const char *iface_name, unsigned int iface_vers, - IExtension *mysql, + IExtension *myself, SMInterface **pIface) { /* See if the interface exists */ @@ -148,7 +148,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, IfaceInfo info; info.iface = iface; info.owner = iface_owner; - g_Extensions.BindDependency(iface_owner, &info); + g_Extensions.BindDependency(myself, &info); } if (pIface)