Fix various problems with unloading ClientPrefs and SourceMod (bug 5874, r=ds).
--HG-- extra : rebase_source : 0a35f8380d651ca65fac9dd402c5cd3625e3105c
This commit is contained in:
parent
d79b41e4a7
commit
94d33a4ef1
@ -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,13 +854,9 @@ 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++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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];
|
||||||
|
@ -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);
|
||||||
|
|
||||||
@ -475,69 +479,74 @@ size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, c
|
|||||||
|
|
||||||
void SourceModBase::CloseSourceMod()
|
void SourceModBase::CloseSourceMod()
|
||||||
{
|
{
|
||||||
/* Force a level end */
|
if (!sSourceModInitialized)
|
||||||
LevelShutdown();
|
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 */
|
/* 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_pOnMapEnd)
|
||||||
|
g_Forwards.ReleaseForward(g_pOnMapEnd);
|
||||||
|
|
||||||
if (g_Loaded)
|
/* Notify! */
|
||||||
|
SMGlobalClass *pBase = SMGlobalClass::head;
|
||||||
|
while (pBase)
|
||||||
{
|
{
|
||||||
if (g_pOnMapEnd)
|
pBase->OnSourceModShutdown();
|
||||||
{
|
pBase = pBase->m_pGlobalClassNext;
|
||||||
g_Forwards.ReleaseForward(g_pOnMapEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Notify! */
|
|
||||||
SMGlobalClass *pBase = SMGlobalClass::head;
|
|
||||||
while (pBase)
|
|
||||||
{
|
|
||||||
pBase->OnSourceModShutdown();
|
|
||||||
pBase = pBase->m_pGlobalClassNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete all data packs */
|
|
||||||
CStack<CDataPack *>::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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rest In Peace */
|
/* Delete all data packs */
|
||||||
ShutdownLogicBridge();
|
CStack<CDataPack *>::iterator iter;
|
||||||
ShutdownJIT();
|
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, ...)
|
void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
|
||||||
|
@ -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];
|
||||||
|
@ -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);
|
||||||
|
@ -75,12 +75,7 @@ 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()
|
||||||
@ -88,9 +83,7 @@ struct 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];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,10 +92,6 @@ struct Cookie
|
|||||||
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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
this->ProcessQueryCache();
|
// Need a new scope because of the goto above.
|
||||||
|
{
|
||||||
|
ke::AutoLock lock(&queryLock);
|
||||||
|
this->ProcessQueryCache();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fatal_fail:
|
fatal_fail:
|
||||||
@ -321,24 +321,18 @@ fatal_fail:
|
|||||||
databaseLoading = false;
|
databaseLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
|
bool ClientPrefs::AddQueryToQueue(TQueryOp *query)
|
||||||
{
|
{
|
||||||
queryMutex->Lock();
|
|
||||||
if (Database == NULL)
|
|
||||||
{
|
{
|
||||||
cachedQueries.push_back(query);
|
ke::AutoLock lock(&queryLock);
|
||||||
queryMutex->Unlock();
|
if (Database == NULL)
|
||||||
return false;
|
{
|
||||||
}
|
cachedQueries.push_back(query);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cachedQueries.empty())
|
if (!cachedQueries.empty())
|
||||||
{
|
this->ProcessQueryCache();
|
||||||
queryMutex->Unlock();
|
|
||||||
this->ProcessQueryCache();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
queryMutex->Unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query->SetDatabase(Database);
|
query->SetDatabase(Database);
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
|
@ -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();
|
||||||
|
@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 */
|
||||||
|
@ -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. */
|
||||||
|
Loading…
Reference in New Issue
Block a user