# HG changeset patch # User David Anderson # Date 1377205544 25200 # Node ID cf8bdfcf6503f66ab5e6b8528a4bada23088eb88 # Parent 4b3d323300074353e952f7f10e89aa31de86acff Fix various problems with unloading ClientPrefs and SourceMod (bug 5874, r=ds). diff -r 4b3d32330007 -r cf8bdfcf6503 core/logic/ExtensionSys.cpp --- a/core/logic/ExtensionSys.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/core/logic/ExtensionSys.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -775,25 +775,21 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) - { return false; - } CExtension *pExt = (CExtension *)_pExt; if (m_Libs.find(pExt) == m_Libs.end()) - { return false; - } /* Tell it to unload */ if (pExt->IsLoaded()) - { - IExtensionInterface *pAPI = pExt->GetAPI(); - pAPI->OnExtensionUnload(); - } + pExt->GetAPI()->OnExtensionUnload(); - /* First remove us from internal lists */ + // Remove us from internal lists. Note that because we do this, it's + // possible that our extension could be added back if another plugin + // tries to load during this process. If we ever find this to happen, + // we can just block plugin loading. g_ShareSys.RemoveInterfaces(_pExt); m_Libs.remove(pExt); @@ -827,13 +823,9 @@ { pDep = (*c_iter); if ((pAPI=pDep->GetAPI()) == NULL) - { continue; - } if (pDep == pExt) - { continue; - } /* Now, get its dependency list */ bool dropped = false; List::iterator i_iter = pDep->m_Deps.begin(); @@ -862,13 +854,9 @@ while (i_iter != pDep->m_ChildDeps.end()) { if ((*i_iter).owner == pExt) - { i_iter = pDep->m_ChildDeps.erase(i_iter); - } else - { i_iter++; - } } } @@ -887,6 +875,11 @@ } } + // Everything has been informed that we're unloading, so give the + // extension one last notification. + if (pExt->IsLoaded() && pExt->GetAPI()->GetExtensionVersion() >= 7) + pExt->GetAPI()->OnDependenciesDropped(); + pExt->Unload(); delete pExt; diff -r 4b3d32330007 -r cf8bdfcf6503 core/logic/common_logic.cpp --- a/core/logic/common_logic.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/core/logic/common_logic.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 sw=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -147,6 +147,7 @@ gamehelpers = core->gamehelpers; g_pSourcePawn = *core->spe1; g_pSourcePawn2 = *core->spe2; + SMGlobalClass::head = core->listeners; g_ShareSys.Initialize(); g_pCoreIdent = g_ShareSys.CreateCoreIdentity(); diff -r 4b3d32330007 -r cf8bdfcf6503 core/logic/intercom.h --- a/core/logic/intercom.h Wed Aug 21 10:55:12 2013 -0400 +++ b/core/logic/intercom.h Thu Aug 22 14:05:44 2013 -0700 @@ -49,7 +49,7 @@ * Add 1 to the RHS of this expression to bump the intercom file * This is to prevent mismatching core/logic binaries */ -#define SM_LOGIC_MAGIC (0x0F47C0DE - 22) +#define SM_LOGIC_MAGIC (0x0F47C0DE - 23) #if defined SM_LOGIC class IVEngineServer @@ -270,6 +270,7 @@ void * serverFactory; void * engineFactory; void * matchmakingDSFactory; + SMGlobalClass * listeners; }; struct sm_logic_t diff -r 4b3d32330007 -r cf8bdfcf6503 core/logic_bridge.cpp --- a/core/logic_bridge.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/core/logic_bridge.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 sw=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. @@ -406,6 +406,7 @@ core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false); core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false); + core_bridge.listeners = SMGlobalClass::head; ILibrary *mmlib; char path[PLATFORM_MAX_PATH]; diff -r 4b3d32330007 -r cf8bdfcf6503 core/sourcemod.cpp --- a/core/sourcemod.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/core/sourcemod.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -129,6 +129,8 @@ return ConfigResult_Ignore; } +static bool sSourceModInitialized = false; + bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late) { const char *gamepath = g_SMAPI->GetBaseDir(); @@ -240,6 +242,8 @@ g_pSourcePawn2->SetDebugListener(logicore.debugger); + sSourceModInitialized = true; + /* Hook this now so we can detect startup without calling StartSourceMod() */ SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false); @@ -475,69 +479,74 @@ void SourceModBase::CloseSourceMod() { - /* Force a level end */ - LevelShutdown(); + if (!sSourceModInitialized) + return; + + SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false); + if (g_Loaded) + { + /* Force a level end */ + LevelShutdown(); + ShutdownServices(); + } + + /* Rest In Peace */ + ShutdownLogicBridge(); + ShutdownJIT(); +} + +void SourceModBase::ShutdownServices() +{ /* Unload plugins */ scripts->Shutdown(); /* Unload extensions */ extsys->Shutdown(); - SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false); + if (g_pOnMapEnd) + g_Forwards.ReleaseForward(g_pOnMapEnd); - if (g_Loaded) + /* Notify! */ + SMGlobalClass *pBase = SMGlobalClass::head; + while (pBase) { - if (g_pOnMapEnd) - { - g_Forwards.ReleaseForward(g_pOnMapEnd); - } - - /* Notify! */ - SMGlobalClass *pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModShutdown(); - pBase = pBase->m_pGlobalClassNext; - } - - /* Delete all data packs */ - CStack::iterator iter; - CDataPack *pd; - for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++) - { - pd = (*iter); - delete pd; - } - m_freepacks.popall(); - - /* Notify! */ - pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModAllShutdown(); - pBase = pBase->m_pGlobalClassNext; - } - - if (enginePatch) - { - SH_RELEASE_CALLCLASS(enginePatch); - enginePatch = NULL; - } - - if (gamedllPatch) - { - SH_RELEASE_CALLCLASS(gamedllPatch); - gamedllPatch = NULL; - } - - SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false); - SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false); + pBase->OnSourceModShutdown(); + pBase = pBase->m_pGlobalClassNext; } - /* Rest In Peace */ - ShutdownLogicBridge(); - ShutdownJIT(); + /* Delete all data packs */ + CStack::iterator iter; + CDataPack *pd; + for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++) + { + pd = (*iter); + delete pd; + } + m_freepacks.popall(); + + /* Notify! */ + pBase = SMGlobalClass::head; + while (pBase) + { + pBase->OnSourceModAllShutdown(); + pBase = pBase->m_pGlobalClassNext; + } + + if (enginePatch) + { + SH_RELEASE_CALLCLASS(enginePatch); + enginePatch = NULL; + } + + if (gamedllPatch) + { + SH_RELEASE_CALLCLASS(gamedllPatch); + gamedllPatch = NULL; + } + + SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false); + SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false); } void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...) diff -r 4b3d32330007 -r cf8bdfcf6503 core/sourcemod.h --- a/core/sourcemod.h Wed Aug 21 10:55:12 2013 -0400 +++ b/core/sourcemod.h Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. @@ -137,6 +137,8 @@ int GetShApiVersion(); bool IsMapRunning(); private: + void ShutdownServices(); +private: CStack m_freepacks; char m_SMBaseDir[PLATFORM_MAX_PATH]; char m_SMRelDir[PLATFORM_MAX_PATH]; diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/cookie.cpp --- a/extensions/clientprefs/cookie.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/cookie.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod Client Preferences Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -55,35 +55,12 @@ for (int i = playerhelpers->GetMaxClients()+1; --i > 0;) { if (connected[i]) - { OnClientDisconnecting(i); - } } /* Find all cookies and delete them */ - Cookie *current; - for (SourceHook::List::iterator _iter = cookieList.begin(); _iter != cookieList.end(); _iter++) - { - current = (Cookie *)*_iter; - - if (current == NULL) - { - continue; - } - - g_ClientPrefs.cookieMutex->Lock(); - if (current->usedInQuery) - { - current->shouldDelete = true; - g_ClientPrefs.cookieMutex->Unlock(); - } - else - { - g_ClientPrefs.cookieMutex->Unlock(); - delete current; - } - } + delete (*_iter); cookieList.clear(); } @@ -93,9 +70,7 @@ Cookie **pCookie = cookieTrie.retrieve(name); if (pCookie == NULL) - { return NULL; - } return *pCookie; } @@ -116,7 +91,6 @@ /* First time cookie - Create from scratch */ pCookie = new Cookie(name, description, access); - pCookie->usedInQuery++; /* Attempt to insert cookie into the db and get its ID num */ TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie); diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/cookie.h --- a/extensions/clientprefs/cookie.h Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/cookie.h Thu Aug 22 14:05:44 2013 -0700 @@ -75,12 +75,7 @@ dbid = -1; for (int i=0; i<=MAXCLIENTS; i++) - { data[i] = NULL; - } - - shouldDelete = false; - usedInQuery = 0; } ~Cookie() @@ -88,9 +83,7 @@ for (int i=0; i<=MAXCLIENTS; i++) { if (data[i] != NULL) - { delete data[i]; - } } } @@ -99,10 +92,6 @@ int dbid; CookieData *data[MAXCLIENTS+1]; CookieAccess access; - - /* Reference counting stuff */ - bool shouldDelete; - int usedInQuery; }; class CookieManager : public IClientListener, public IPluginsListener diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/extension.cpp --- a/extensions/clientprefs/extension.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/extension.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod Client Preferences Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -50,9 +50,6 @@ bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late) { - queryMutex = threader->MakeMutex(); - cookieMutex = threader->MakeMutex(); - DBInfo = dbi->FindDatabaseConf("clientprefs"); if (DBInfo == NULL) @@ -155,13 +152,15 @@ } } -void ClientPrefs::SDK_OnUnload() +void ClientPrefs::SDK_OnDependenciesDropped() { + // At this point, we're guaranteed that DBI has flushed the worker thread + // for us, so no cookies should have outstanding queries. + g_CookieManager.Unload(); + handlesys->RemoveType(g_CookieType, myself->GetIdentity()); handlesys->RemoveType(g_CookieIterator, myself->GetIdentity()); - g_CookieManager.Unload(); - if (Database != NULL) { Database->Close(); @@ -199,9 +198,6 @@ plsys->RemovePluginsListener(&g_CookieManager); playerhelpers->RemoveClientListener(&g_CookieManager); - - queryMutex->DestroyThis(); - cookieMutex->DestroyThis(); } void ClientPrefs::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) @@ -312,7 +308,11 @@ databaseLoading = false; - this->ProcessQueryCache(); + // Need a new scope because of the goto above. + { + ke::AutoLock lock(&queryLock); + this->ProcessQueryCache(); + } return; fatal_fail: @@ -321,24 +321,18 @@ databaseLoading = false; } -bool ClientPrefs::AddQueryToQueue( TQueryOp *query ) +bool ClientPrefs::AddQueryToQueue(TQueryOp *query) { - queryMutex->Lock(); - if (Database == NULL) { - cachedQueries.push_back(query); - queryMutex->Unlock(); - return false; - } - - if (!cachedQueries.empty()) - { - queryMutex->Unlock(); - this->ProcessQueryCache(); - } - else - { - queryMutex->Unlock(); + ke::AutoLock lock(&queryLock); + if (Database == NULL) + { + cachedQueries.push_back(query); + return false; + } + + if (!cachedQueries.empty()) + this->ProcessQueryCache(); } query->SetDatabase(Database); @@ -348,12 +342,11 @@ void ClientPrefs::ProcessQueryCache() { + queryLock.AssertCurrentThreadOwns(); + if (Database == NULL) - { return; - } - queryMutex->Lock(); TQueryOp *op; for (SourceHook::List::iterator iter = cachedQueries.begin(); iter != cachedQueries.end(); iter++) { @@ -363,7 +356,6 @@ } cachedQueries.clear(); - queryMutex->Unlock(); } size_t IsAuthIdConnected(char *authID) @@ -417,8 +409,7 @@ void ClientPrefs::ClearQueryCache(int serial) { - queryMutex->Lock(); - + ke::AutoLock lock(&queryLock); for (SourceHook::List::iterator iter = cachedQueries.begin(); iter != cachedQueries.end();) { TQueryOp *op = *iter; @@ -432,7 +423,6 @@ iter++; } } - queryMutex->Unlock(); } bool Translate(char *buffer, @@ -530,7 +520,5 @@ phrases = NULL; DBInfo = NULL; - cookieMutex = NULL; - queryMutex = NULL; identity = NULL; } diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/extension.h --- a/extensions/clientprefs/extension.h Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/extension.h Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod Client Preferences Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -39,6 +39,8 @@ #include "smsdk_ext.h" #include "sh_list.h" +#include + char * UTIL_strncpy(char * destination, const char * source, size_t num); #include "cookie.h" @@ -73,11 +75,8 @@ * @return True to succeed loading, false to fail. */ virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); - - /** - * @brief This is called right before the extension is unloaded. - */ - virtual void SDK_OnUnload(); + + virtual void SDK_OnDependenciesDropped(); /** * @brief This is called once all known extensions have been loaded. @@ -162,7 +161,7 @@ private: SourceHook::List cachedQueries; - IMutex *queryMutex; + ke::Mutex queryLock; IdentityToken_t *identity; }; diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/query.cpp --- a/extensions/clientprefs/query.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/query.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -303,23 +303,6 @@ ParamData::~ParamData() { - if (cookie) - { - g_ClientPrefs.cookieMutex->Lock(); - cookie->usedInQuery--; - - if (cookie->shouldDelete && cookie->usedInQuery <= 0) - { - g_ClientPrefs.cookieMutex->Unlock(); - delete cookie; - cookie = NULL; - } - else - { - g_ClientPrefs.cookieMutex->Unlock(); - } - } - if (data) { /* Data is only ever passed in a client disconnect query and always needs to be deleted */ diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/sdk/smsdk_config.h --- a/extensions/clientprefs/sdk/smsdk_config.h Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/sdk/smsdk_config.h Thu Aug 22 14:05:44 2013 -0700 @@ -67,7 +67,7 @@ //#define SMEXT_ENABLE_MEMUTILS #define SMEXT_ENABLE_GAMEHELPERS //#define SMEXT_ENABLE_TIMERSYS -#define SMEXT_ENABLE_THREADER +//#define SMEXT_ENABLE_THREADER //#define SMEXT_ENABLE_LIBSYS #define SMEXT_ENABLE_MENUS //#define SMEXT_ENABLE_ADTFACTORY diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/sdk/smsdk_ext.cpp --- a/extensions/clientprefs/sdk/smsdk_ext.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/sdk/smsdk_ext.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod Base Extension Code * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -97,6 +97,12 @@ #if defined SMEXT_ENABLE_TRANSLATOR ITranslator *translator = NULL; #endif +#if defined SMEXT_ENABLE_NINVOKE +INativeInterface *ninvoke = NULL; +#endif +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU +IRootConsole *rootconsole = NULL; +#endif /** Exports the main interface */ PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() @@ -185,6 +191,12 @@ #if defined SMEXT_ENABLE_TRANSLATOR SM_GET_IFACE(TRANSLATOR, translator); #endif +#if defined SMEXT_ENABLE_NINVOKE + SM_GET_IFACE(NINVOKE, ninvoke); +#endif +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU + SM_GET_IFACE(ROOTCONSOLE, rootconsole); +#endif if (SDK_OnLoad(error, maxlength, late)) { @@ -227,6 +239,11 @@ SDK_OnUnload(); } +void SDKExtension::OnDependenciesDropped() +{ + SDK_OnDependenciesDropped(); +} + const char *SDKExtension::GetExtensionAuthor() { return SMEXT_CONF_AUTHOR; @@ -279,6 +296,10 @@ { } +void SDKExtension::SDK_OnDependenciesDropped() +{ +} + #if defined SMEXT_CONF_METAMOD PluginId g_PLID = 0; /**< Metamod plugin ID */ diff -r 4b3d32330007 -r cf8bdfcf6503 extensions/clientprefs/sdk/smsdk_ext.h --- a/extensions/clientprefs/sdk/smsdk_ext.h Wed Aug 21 10:55:12 2013 -0400 +++ b/extensions/clientprefs/sdk/smsdk_ext.h Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod Base Extension Code * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -91,6 +91,12 @@ #if defined SMEXT_ENABLE_TRANSLATOR #include #endif +#if defined SMEXT_ENABLE_NINVOKE +#include +#endif +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU +#include +#endif #if defined SMEXT_CONF_METAMOD #include @@ -121,7 +127,7 @@ virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** - * @brief This is called right before the extension is unloaded. + * @brief This is called once the extension unloading process begins. */ virtual void SDK_OnUnload(); @@ -135,6 +141,12 @@ */ virtual void SDK_OnPauseChange(bool paused); + /** + * @brief Called after SDK_OnUnload, once all dependencies have been + * removed, and the extension is about to be removed from memory. + */ + virtual void SDK_OnDependenciesDropped(); + #if defined SMEXT_CONF_METAMOD /** * @brief Called when Metamod is attached, before the extension version is called. @@ -197,6 +209,9 @@ virtual const char *GetExtensionDescription(); /** Returns date string */ virtual const char *GetExtensionDateString(); + + /** Called after OnExtensionUnload, once dependencies have been dropped. */ + virtual void OnDependenciesDropped(); #if defined SMEXT_CONF_METAMOD public: //ISmmPlugin /** Called when the extension is attached to Metamod. */ @@ -289,6 +304,12 @@ #if defined SMEXT_ENABLE_TRANSLATOR extern ITranslator *translator; #endif +#if defined SMEXT_ENABLE_NINVOKE +extern INativeInterface *ninvoke; +#endif +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU +extern IRootConsole *rootconsole; +#endif #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS(); diff -r 4b3d32330007 -r cf8bdfcf6503 public/IExtensionSys.h --- a/public/IExtensionSys.h Wed Aug 21 10:55:12 2013 -0400 +++ b/public/IExtensionSys.h Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -134,8 +134,9 @@ * itself is not versioned. * * V6 - added TestFeature() to IShareSys. + * V7 - added OnDependenciesDropped() to IExtensionInterface. */ - #define SMINTERFACE_EXTENSIONAPI_VERSION 6 + #define SMINTERFACE_EXTENSIONAPI_VERSION 7 /** * @brief The interface an extension must expose. @@ -313,6 +314,17 @@ virtual void OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) { } + + /** + * @brief Called once all dependencies have been unloaded. This is + * called AFTER OnExtensionUnload(), but before the extension library + * has been unloaded. It can be used as an alternate unload hook for + * cases where having no dependent plugins would make shutdown much + * simplier. + */ + virtual void OnDependenciesDropped() + { + } }; /** diff -r 4b3d32330007 -r cf8bdfcf6503 public/sample_ext/sdk/smsdk_ext.cpp --- a/public/sample_ext/sdk/smsdk_ext.cpp Wed Aug 21 10:55:12 2013 -0400 +++ b/public/sample_ext/sdk/smsdk_ext.cpp Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod Base Extension Code * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -239,6 +239,11 @@ SDK_OnUnload(); } +void SDKExtension::OnDependenciesDropped() +{ + SDK_OnDependenciesDropped(); +} + const char *SDKExtension::GetExtensionAuthor() { return SMEXT_CONF_AUTHOR; @@ -291,6 +296,10 @@ { } +void SDKExtension::SDK_OnDependenciesDropped() +{ +} + #if defined SMEXT_CONF_METAMOD PluginId g_PLID = 0; /**< Metamod plugin ID */ diff -r 4b3d32330007 -r cf8bdfcf6503 public/sample_ext/sdk/smsdk_ext.h --- a/public/sample_ext/sdk/smsdk_ext.h Wed Aug 21 10:55:12 2013 -0400 +++ b/public/sample_ext/sdk/smsdk_ext.h Thu Aug 22 14:05:44 2013 -0700 @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=4 sw=4 tw=99 noet: * ============================================================================= * SourceMod Base Extension Code * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -127,7 +127,7 @@ virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** - * @brief This is called right before the extension is unloaded. + * @brief This is called once the extension unloading process begins. */ virtual void SDK_OnUnload(); @@ -141,6 +141,12 @@ */ virtual void SDK_OnPauseChange(bool paused); + /** + * @brief Called after SDK_OnUnload, once all dependencies have been + * removed, and the extension is about to be removed from memory. + */ + virtual void SDK_OnDependenciesDropped(); + #if defined SMEXT_CONF_METAMOD /** * @brief Called when Metamod is attached, before the extension version is called. @@ -203,6 +209,9 @@ virtual const char *GetExtensionDescription(); /** Returns date string */ virtual const char *GetExtensionDateString(); + + /** Called after OnExtensionUnload, once dependencies have been dropped. */ + virtual void OnDependenciesDropped(); #if defined SMEXT_CONF_METAMOD public: //ISmmPlugin /** Called when the extension is attached to Metamod. */