Fix various problems with unloading ClientPrefs and SourceMod (bug 5874, r=ds).

--HG--
extra : rebase_source : 0a35f8380d651ca65fac9dd402c5cd3625e3105c
This commit is contained in:
David Anderson 2013-08-22 14:05:44 -07:00
parent d79b41e4a7
commit 94d33a4ef1
17 changed files with 195 additions and 183 deletions

View File

@ -775,25 +775,21 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num)
bool CExtensionManager::UnloadExtension(IExtension *_pExt) bool CExtensionManager::UnloadExtension(IExtension *_pExt)
{ {
if (!_pExt) if (!_pExt)
{
return false; return false;
}
CExtension *pExt = (CExtension *)_pExt; CExtension *pExt = (CExtension *)_pExt;
if (m_Libs.find(pExt) == m_Libs.end()) if (m_Libs.find(pExt) == m_Libs.end())
{
return false; return false;
}
/* Tell it to unload */ /* Tell it to unload */
if (pExt->IsLoaded()) if (pExt->IsLoaded())
{ pExt->GetAPI()->OnExtensionUnload();
IExtensionInterface *pAPI = pExt->GetAPI();
pAPI->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); g_ShareSys.RemoveInterfaces(_pExt);
m_Libs.remove(pExt); m_Libs.remove(pExt);
@ -827,13 +823,9 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
{ {
pDep = (*c_iter); pDep = (*c_iter);
if ((pAPI=pDep->GetAPI()) == NULL) if ((pAPI=pDep->GetAPI()) == NULL)
{
continue; continue;
}
if (pDep == pExt) if (pDep == pExt)
{
continue; continue;
}
/* Now, get its dependency list */ /* Now, get its dependency list */
bool dropped = false; bool dropped = false;
List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin(); List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
@ -862,15 +854,11 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
while (i_iter != pDep->m_ChildDeps.end()) while (i_iter != pDep->m_ChildDeps.end())
{ {
if ((*i_iter).owner == pExt) if ((*i_iter).owner == pExt)
{
i_iter = pDep->m_ChildDeps.erase(i_iter); i_iter = pDep->m_ChildDeps.erase(i_iter);
}
else else
{
i_iter++; i_iter++;
} }
} }
}
/* Unbind our natives from Core */ /* Unbind our natives from Core */
pExt->DropEverything(); pExt->DropEverything();
@ -887,6 +875,11 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
} }
} }
// 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(); pExt->Unload();
delete pExt; delete pExt;

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 sw=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -147,6 +147,7 @@ static void logic_init(const sm_core_t* core, sm_logic_t* _logic)
gamehelpers = core->gamehelpers; gamehelpers = core->gamehelpers;
g_pSourcePawn = *core->spe1; g_pSourcePawn = *core->spe1;
g_pSourcePawn2 = *core->spe2; g_pSourcePawn2 = *core->spe2;
SMGlobalClass::head = core->listeners;
g_ShareSys.Initialize(); g_ShareSys.Initialize();
g_pCoreIdent = g_ShareSys.CreateCoreIdentity(); g_pCoreIdent = g_ShareSys.CreateCoreIdentity();

View File

@ -49,7 +49,7 @@ using namespace SourceHook;
* Add 1 to the RHS of this expression to bump the intercom file * Add 1 to the RHS of this expression to bump the intercom file
* This is to prevent mismatching core/logic binaries * This is to prevent mismatching core/logic binaries
*/ */
#define SM_LOGIC_MAGIC (0x0F47C0DE - 22) #define SM_LOGIC_MAGIC (0x0F47C0DE - 23)
#if defined SM_LOGIC #if defined SM_LOGIC
class IVEngineServer class IVEngineServer
@ -270,6 +270,7 @@ struct sm_core_t
void * serverFactory; void * serverFactory;
void * engineFactory; void * engineFactory;
void * matchmakingDSFactory; void * matchmakingDSFactory;
SMGlobalClass * listeners;
}; };
struct sm_logic_t struct sm_logic_t

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 sw=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
@ -406,6 +406,7 @@ void InitLogicBridge()
core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false); core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false); core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false);
core_bridge.listeners = SMGlobalClass::head;
ILibrary *mmlib; ILibrary *mmlib;
char path[PLATFORM_MAX_PATH]; char path[PLATFORM_MAX_PATH];

View File

@ -129,6 +129,8 @@ ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key,
return ConfigResult_Ignore; return ConfigResult_Ignore;
} }
static bool sSourceModInitialized = false;
bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late) bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late)
{ {
const char *gamepath = g_SMAPI->GetBaseDir(); const char *gamepath = g_SMAPI->GetBaseDir();
@ -240,6 +242,8 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
g_pSourcePawn2->SetDebugListener(logicore.debugger); g_pSourcePawn2->SetDebugListener(logicore.debugger);
sSourceModInitialized = true;
/* Hook this now so we can detect startup without calling StartSourceMod() */ /* Hook this now so we can detect startup without calling StartSourceMod() */
SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false); SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
@ -474,24 +478,34 @@ size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, c
} }
void SourceModBase::CloseSourceMod() void SourceModBase::CloseSourceMod()
{
if (!sSourceModInitialized)
return;
SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
if (g_Loaded)
{ {
/* Force a level end */ /* Force a level end */
LevelShutdown(); LevelShutdown();
ShutdownServices();
}
/* Rest In Peace */
ShutdownLogicBridge();
ShutdownJIT();
}
void SourceModBase::ShutdownServices()
{
/* Unload plugins */ /* Unload plugins */
scripts->Shutdown(); scripts->Shutdown();
/* Unload extensions */ /* Unload extensions */
extsys->Shutdown(); extsys->Shutdown();
SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
if (g_Loaded)
{
if (g_pOnMapEnd) if (g_pOnMapEnd)
{
g_Forwards.ReleaseForward(g_pOnMapEnd); g_Forwards.ReleaseForward(g_pOnMapEnd);
}
/* Notify! */ /* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head; SMGlobalClass *pBase = SMGlobalClass::head;
@ -535,11 +549,6 @@ void SourceModBase::CloseSourceMod()
SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false); SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
} }
/* Rest In Peace */
ShutdownLogicBridge();
ShutdownJIT();
}
void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...) void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
{ {
IExtensionInterface *pAPI = pExt->GetAPI(); IExtensionInterface *pAPI = pExt->GetAPI();

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
@ -136,6 +136,8 @@ public: // ISourceMod
int GetPluginId(); int GetPluginId();
int GetShApiVersion(); int GetShApiVersion();
bool IsMapRunning(); bool IsMapRunning();
private:
void ShutdownServices();
private: private:
CStack<CDataPack *> m_freepacks; CStack<CDataPack *> m_freepacks;
char m_SMBaseDir[PLATFORM_MAX_PATH]; char m_SMBaseDir[PLATFORM_MAX_PATH];

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod Client Preferences Extension * SourceMod Client Preferences Extension
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -55,35 +55,12 @@ void CookieManager::Unload()
for (int i = playerhelpers->GetMaxClients()+1; --i > 0;) for (int i = playerhelpers->GetMaxClients()+1; --i > 0;)
{ {
if (connected[i]) if (connected[i])
{
OnClientDisconnecting(i); OnClientDisconnecting(i);
} }
}
/* Find all cookies and delete them */ /* Find all cookies and delete them */
Cookie *current;
for (SourceHook::List<Cookie *>::iterator _iter = cookieList.begin(); _iter != cookieList.end(); _iter++) for (SourceHook::List<Cookie *>::iterator _iter = cookieList.begin(); _iter != cookieList.end(); _iter++)
{ delete (*_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;
}
}
cookieList.clear(); cookieList.clear();
} }
@ -93,9 +70,7 @@ Cookie *CookieManager::FindCookie(const char *name)
Cookie **pCookie = cookieTrie.retrieve(name); Cookie **pCookie = cookieTrie.retrieve(name);
if (pCookie == NULL) if (pCookie == NULL)
{
return NULL; return NULL;
}
return *pCookie; return *pCookie;
} }
@ -116,7 +91,6 @@ Cookie *CookieManager::CreateCookie(const char *name, const char *description, C
/* First time cookie - Create from scratch */ /* First time cookie - Create from scratch */
pCookie = new Cookie(name, description, access); pCookie = new Cookie(name, description, access);
pCookie->usedInQuery++;
/* Attempt to insert cookie into the db and get its ID num */ /* Attempt to insert cookie into the db and get its ID num */
TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie); TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie);

View File

@ -75,34 +75,23 @@ struct Cookie
dbid = -1; dbid = -1;
for (int i=0; i<=MAXCLIENTS; i++) for (int i=0; i<=MAXCLIENTS; i++)
{
data[i] = NULL; data[i] = NULL;
} }
shouldDelete = false;
usedInQuery = 0;
}
~Cookie() ~Cookie()
{ {
for (int i=0; i<=MAXCLIENTS; i++) for (int i=0; i<=MAXCLIENTS; i++)
{ {
if (data[i] != NULL) if (data[i] != NULL)
{
delete data[i]; delete data[i];
} }
} }
}
char name[MAX_NAME_LENGTH+1]; char name[MAX_NAME_LENGTH+1];
char description[MAX_DESC_LENGTH+1]; char description[MAX_DESC_LENGTH+1];
int dbid; int dbid;
CookieData *data[MAXCLIENTS+1]; CookieData *data[MAXCLIENTS+1];
CookieAccess access; CookieAccess access;
/* Reference counting stuff */
bool shouldDelete;
int usedInQuery;
}; };
class CookieManager : public IClientListener, public IPluginsListener class CookieManager : public IClientListener, public IPluginsListener

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod Client Preferences Extension * SourceMod Client Preferences Extension
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -50,9 +50,6 @@ DbDriver g_DriverType;
bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late) bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
{ {
queryMutex = threader->MakeMutex();
cookieMutex = threader->MakeMutex();
DBInfo = dbi->FindDatabaseConf("clientprefs"); DBInfo = dbi->FindDatabaseConf("clientprefs");
if (DBInfo == NULL) if (DBInfo == NULL)
@ -155,13 +152,15 @@ void ClientPrefs::NotifyInterfaceDrop(SMInterface *pInterface)
} }
} }
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_CookieType, myself->GetIdentity());
handlesys->RemoveType(g_CookieIterator, myself->GetIdentity()); handlesys->RemoveType(g_CookieIterator, myself->GetIdentity());
g_CookieManager.Unload();
if (Database != NULL) if (Database != NULL)
{ {
Database->Close(); Database->Close();
@ -199,9 +198,6 @@ void ClientPrefs::SDK_OnUnload()
plsys->RemovePluginsListener(&g_CookieManager); plsys->RemovePluginsListener(&g_CookieManager);
playerhelpers->RemoveClientListener(&g_CookieManager); playerhelpers->RemoveClientListener(&g_CookieManager);
queryMutex->DestroyThis();
cookieMutex->DestroyThis();
} }
void ClientPrefs::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) void ClientPrefs::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
@ -312,7 +308,11 @@ void ClientPrefs::DatabaseConnect()
databaseLoading = false; databaseLoading = false;
// Need a new scope because of the goto above.
{
ke::AutoLock lock(&queryLock);
this->ProcessQueryCache(); this->ProcessQueryCache();
}
return; return;
fatal_fail: fatal_fail:
@ -323,23 +323,17 @@ fatal_fail:
bool ClientPrefs::AddQueryToQueue(TQueryOp *query) bool ClientPrefs::AddQueryToQueue(TQueryOp *query)
{ {
queryMutex->Lock(); {
ke::AutoLock lock(&queryLock);
if (Database == NULL) if (Database == NULL)
{ {
cachedQueries.push_back(query); cachedQueries.push_back(query);
queryMutex->Unlock();
return false; return false;
} }
if (!cachedQueries.empty()) if (!cachedQueries.empty())
{
queryMutex->Unlock();
this->ProcessQueryCache(); this->ProcessQueryCache();
} }
else
{
queryMutex->Unlock();
}
query->SetDatabase(Database); query->SetDatabase(Database);
dbi->AddToThreadQueue(query, PrioQueue_Normal); dbi->AddToThreadQueue(query, PrioQueue_Normal);
@ -348,12 +342,11 @@ bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
void ClientPrefs::ProcessQueryCache() void ClientPrefs::ProcessQueryCache()
{ {
if (Database == NULL) queryLock.AssertCurrentThreadOwns();
{
return; if (Database == NULL)
} return;
queryMutex->Lock();
TQueryOp *op; TQueryOp *op;
for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end(); iter++) for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end(); iter++)
{ {
@ -363,7 +356,6 @@ void ClientPrefs::ProcessQueryCache()
} }
cachedQueries.clear(); cachedQueries.clear();
queryMutex->Unlock();
} }
size_t IsAuthIdConnected(char *authID) size_t IsAuthIdConnected(char *authID)
@ -417,8 +409,7 @@ void ClientPrefs::CatchLateLoadClients()
void ClientPrefs::ClearQueryCache(int serial) void ClientPrefs::ClearQueryCache(int serial)
{ {
queryMutex->Lock(); ke::AutoLock lock(&queryLock);
for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end();) for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end();)
{ {
TQueryOp *op = *iter; TQueryOp *op = *iter;
@ -432,7 +423,6 @@ void ClientPrefs::ClearQueryCache(int serial)
iter++; iter++;
} }
} }
queryMutex->Unlock();
} }
bool Translate(char *buffer, bool Translate(char *buffer,
@ -530,7 +520,5 @@ ClientPrefs::ClientPrefs()
phrases = NULL; phrases = NULL;
DBInfo = NULL; DBInfo = NULL;
cookieMutex = NULL;
queryMutex = NULL;
identity = NULL; identity = NULL;
} }

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod Client Preferences Extension * SourceMod Client Preferences Extension
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -39,6 +39,8 @@
#include "smsdk_ext.h" #include "smsdk_ext.h"
#include "sh_list.h" #include "sh_list.h"
#include <ke_thread_utils.h>
char * UTIL_strncpy(char * destination, const char * source, size_t num); char * UTIL_strncpy(char * destination, const char * source, size_t num);
#include "cookie.h" #include "cookie.h"
@ -74,10 +76,7 @@ public:
*/ */
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
/** virtual void SDK_OnDependenciesDropped();
* @brief This is called right before the extension is unloaded.
*/
virtual void SDK_OnUnload();
/** /**
* @brief This is called once all known extensions have been loaded. * @brief This is called once all known extensions have been loaded.
@ -162,7 +161,7 @@ public:
private: private:
SourceHook::List<TQueryOp *> cachedQueries; SourceHook::List<TQueryOp *> cachedQueries;
IMutex *queryMutex; ke::Mutex queryLock;
IdentityToken_t *identity; IdentityToken_t *identity;
}; };

View File

@ -303,23 +303,6 @@ int TQueryOp::PullQuerySerial()
ParamData::~ParamData() 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) if (data)
{ {
/* Data is only ever passed in a client disconnect query and always needs to be deleted */ /* Data is only ever passed in a client disconnect query and always needs to be deleted */

View File

@ -67,7 +67,7 @@
//#define SMEXT_ENABLE_MEMUTILS //#define SMEXT_ENABLE_MEMUTILS
#define SMEXT_ENABLE_GAMEHELPERS #define SMEXT_ENABLE_GAMEHELPERS
//#define SMEXT_ENABLE_TIMERSYS //#define SMEXT_ENABLE_TIMERSYS
#define SMEXT_ENABLE_THREADER //#define SMEXT_ENABLE_THREADER
//#define SMEXT_ENABLE_LIBSYS //#define SMEXT_ENABLE_LIBSYS
#define SMEXT_ENABLE_MENUS #define SMEXT_ENABLE_MENUS
//#define SMEXT_ENABLE_ADTFACTORY //#define SMEXT_ENABLE_ADTFACTORY

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod Base Extension Code * SourceMod Base Extension Code
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -97,6 +97,12 @@ IUserMessages *usermsgs = NULL;
#if defined SMEXT_ENABLE_TRANSLATOR #if defined SMEXT_ENABLE_TRANSLATOR
ITranslator *translator = NULL; ITranslator *translator = NULL;
#endif #endif
#if defined SMEXT_ENABLE_NINVOKE
INativeInterface *ninvoke = NULL;
#endif
#if defined SMEXT_ENABLE_ROOTCONSOLEMENU
IRootConsole *rootconsole = NULL;
#endif
/** Exports the main interface */ /** Exports the main interface */
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
@ -185,6 +191,12 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error,
#if defined SMEXT_ENABLE_TRANSLATOR #if defined SMEXT_ENABLE_TRANSLATOR
SM_GET_IFACE(TRANSLATOR, translator); SM_GET_IFACE(TRANSLATOR, translator);
#endif #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)) if (SDK_OnLoad(error, maxlength, late))
{ {
@ -227,6 +239,11 @@ void SDKExtension::OnExtensionUnload()
SDK_OnUnload(); SDK_OnUnload();
} }
void SDKExtension::OnDependenciesDropped()
{
SDK_OnDependenciesDropped();
}
const char *SDKExtension::GetExtensionAuthor() const char *SDKExtension::GetExtensionAuthor()
{ {
return SMEXT_CONF_AUTHOR; return SMEXT_CONF_AUTHOR;
@ -279,6 +296,10 @@ void SDKExtension::SDK_OnAllLoaded()
{ {
} }
void SDKExtension::SDK_OnDependenciesDropped()
{
}
#if defined SMEXT_CONF_METAMOD #if defined SMEXT_CONF_METAMOD
PluginId g_PLID = 0; /**< Metamod plugin ID */ PluginId g_PLID = 0; /**< Metamod plugin ID */

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod Base Extension Code * SourceMod Base Extension Code
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -91,6 +91,12 @@
#if defined SMEXT_ENABLE_TRANSLATOR #if defined SMEXT_ENABLE_TRANSLATOR
#include <ITranslator.h> #include <ITranslator.h>
#endif #endif
#if defined SMEXT_ENABLE_NINVOKE
#include <INativeInvoker.h>
#endif
#if defined SMEXT_ENABLE_ROOTCONSOLEMENU
#include <IRootConsoleMenu.h>
#endif
#if defined SMEXT_CONF_METAMOD #if defined SMEXT_CONF_METAMOD
#include <ISmmPlugin.h> #include <ISmmPlugin.h>
@ -121,7 +127,7 @@ public:
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); 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(); virtual void SDK_OnUnload();
@ -135,6 +141,12 @@ public:
*/ */
virtual void SDK_OnPauseChange(bool paused); 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 #if defined SMEXT_CONF_METAMOD
/** /**
* @brief Called when Metamod is attached, before the extension version is called. * @brief Called when Metamod is attached, before the extension version is called.
@ -197,6 +209,9 @@ public: //IExtensionInterface
virtual const char *GetExtensionDescription(); virtual const char *GetExtensionDescription();
/** Returns date string */ /** Returns date string */
virtual const char *GetExtensionDateString(); virtual const char *GetExtensionDateString();
/** Called after OnExtensionUnload, once dependencies have been dropped. */
virtual void OnDependenciesDropped();
#if defined SMEXT_CONF_METAMOD #if defined SMEXT_CONF_METAMOD
public: //ISmmPlugin public: //ISmmPlugin
/** Called when the extension is attached to Metamod. */ /** Called when the extension is attached to Metamod. */
@ -289,6 +304,12 @@ extern IUserMessages *usermsgs;
#if defined SMEXT_ENABLE_TRANSLATOR #if defined SMEXT_ENABLE_TRANSLATOR
extern ITranslator *translator; extern ITranslator *translator;
#endif #endif
#if defined SMEXT_ENABLE_NINVOKE
extern INativeInterface *ninvoke;
#endif
#if defined SMEXT_ENABLE_ROOTCONSOLEMENU
extern IRootConsole *rootconsole;
#endif
#if defined SMEXT_CONF_METAMOD #if defined SMEXT_CONF_METAMOD
PLUGIN_GLOBALVARS(); PLUGIN_GLOBALVARS();

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -134,8 +134,9 @@ namespace SourceMod
* itself is not versioned. * itself is not versioned.
* *
* V6 - added TestFeature() to IShareSys. * 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. * @brief The interface an extension must expose.
@ -313,6 +314,17 @@ namespace SourceMod
virtual void OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) 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()
{
}
}; };
/** /**

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod Base Extension Code * SourceMod Base Extension Code
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -239,6 +239,11 @@ void SDKExtension::OnExtensionUnload()
SDK_OnUnload(); SDK_OnUnload();
} }
void SDKExtension::OnDependenciesDropped()
{
SDK_OnDependenciesDropped();
}
const char *SDKExtension::GetExtensionAuthor() const char *SDKExtension::GetExtensionAuthor()
{ {
return SMEXT_CONF_AUTHOR; return SMEXT_CONF_AUTHOR;
@ -291,6 +296,10 @@ void SDKExtension::SDK_OnAllLoaded()
{ {
} }
void SDKExtension::SDK_OnDependenciesDropped()
{
}
#if defined SMEXT_CONF_METAMOD #if defined SMEXT_CONF_METAMOD
PluginId g_PLID = 0; /**< Metamod plugin ID */ PluginId g_PLID = 0; /**< Metamod plugin ID */

View File

@ -1,5 +1,5 @@
/** /**
* vim: set ts=4 : * vim: set ts=4 sw=4 tw=99 noet:
* ============================================================================= * =============================================================================
* SourceMod Base Extension Code * SourceMod Base Extension Code
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@ -127,7 +127,7 @@ public:
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); 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(); virtual void SDK_OnUnload();
@ -141,6 +141,12 @@ public:
*/ */
virtual void SDK_OnPauseChange(bool paused); 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 #if defined SMEXT_CONF_METAMOD
/** /**
* @brief Called when Metamod is attached, before the extension version is called. * @brief Called when Metamod is attached, before the extension version is called.
@ -203,6 +209,9 @@ public: //IExtensionInterface
virtual const char *GetExtensionDescription(); virtual const char *GetExtensionDescription();
/** Returns date string */ /** Returns date string */
virtual const char *GetExtensionDateString(); virtual const char *GetExtensionDateString();
/** Called after OnExtensionUnload, once dependencies have been dropped. */
virtual void OnDependenciesDropped();
#if defined SMEXT_CONF_METAMOD #if defined SMEXT_CONF_METAMOD
public: //ISmmPlugin public: //ISmmPlugin
/** Called when the extension is attached to Metamod. */ /** Called when the extension is attached to Metamod. */