Added extension loading/unloading
Extended SDK for interface sharing Completed Metamod extension support --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40309
This commit is contained in:
parent
b7e10b111f
commit
1857f29efc
@ -7,6 +7,7 @@
|
|||||||
namespace SourceMod
|
namespace SourceMod
|
||||||
{
|
{
|
||||||
class IExtensionInterface;
|
class IExtensionInterface;
|
||||||
|
typedef void * ITERATOR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encapsulates an IExtension.
|
* @brief Encapsulates an IExtension.
|
||||||
@ -40,6 +41,32 @@ namespace SourceMod
|
|||||||
* @return An IdentityToken_t pointer.
|
* @return An IdentityToken_t pointer.
|
||||||
*/
|
*/
|
||||||
virtual IdentityToken_t *GetIdentity() =0;
|
virtual IdentityToken_t *GetIdentity() =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the extension dependency list for this extension.
|
||||||
|
*
|
||||||
|
* @param pOwner Optional pointer to store the first interface's owner.
|
||||||
|
* @param pInterface Optional pointer to store the first interface.
|
||||||
|
* @return An ITERATOR pointer for the results, or NULL if no results at all.
|
||||||
|
*/
|
||||||
|
virtual ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finds the next dependency in the dependency list.
|
||||||
|
*
|
||||||
|
* @param iter Pointer to iterator from FindFirstDependency.
|
||||||
|
* @param pOwner Optional pointer to store the interface's owner.
|
||||||
|
* @param pInterface Optional pointer to store the interface.
|
||||||
|
* @return True if there are more results after this, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Frees an ITERATOR handle from FindFirstDependency.
|
||||||
|
*
|
||||||
|
* @param iter Pointer to iterator to free.
|
||||||
|
*/
|
||||||
|
virtual void FreeDependencyIterator(ITERATOR *iter) =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SMINTERFACE_EXTENSIONAPI_VERSION 1
|
#define SMINTERFACE_EXTENSIONAPI_VERSION 1
|
||||||
@ -49,6 +76,11 @@ namespace SourceMod
|
|||||||
*/
|
*/
|
||||||
class IExtensionInterface
|
class IExtensionInterface
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
virtual unsigned int GetExtensionVersion()
|
||||||
|
{
|
||||||
|
return SMINTERFACE_EXTENSIONAPI_VERSION;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Called when the extension is loaded.
|
* @brief Called when the extension is loaded.
|
||||||
@ -84,16 +116,29 @@ namespace SourceMod
|
|||||||
*/
|
*/
|
||||||
virtual void OnExtensionPauseChange(bool pause) =0;
|
virtual void OnExtensionPauseChange(bool pause) =0;
|
||||||
|
|
||||||
virtual unsigned int GetExtensionVersion()
|
/**
|
||||||
|
* @brief Asks the extension whether it's safe to remove an external interface it's using.
|
||||||
|
* If it's not safe, return false, and the extension will be unloaded afterwards.
|
||||||
|
* NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean up resources.
|
||||||
|
*
|
||||||
|
* @param pInterface Pointer to interface being dropped.
|
||||||
|
* @return True to continue, false to unload this extension afterwards.
|
||||||
|
*/
|
||||||
|
virtual bool QueryInterfaceDrop(SMInterface *pInterface)
|
||||||
{
|
{
|
||||||
return SMINTERFACE_EXTENSIONAPI_VERSION;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true if the extension is Metamod-dependent.
|
* @brief Notifies the extension that an external interface it uses is being removed.
|
||||||
|
*
|
||||||
|
* @param pInterface Pointer to interface being dropped.
|
||||||
*/
|
*/
|
||||||
virtual bool IsMetamodExtension() =0;
|
virtual void NotifyInterfaceDrop(SMInterface *pInterface)
|
||||||
|
{
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
|
virtual bool IsMetamodExtension() =0;
|
||||||
virtual const char *GetExtensionName() =0;
|
virtual const char *GetExtensionName() =0;
|
||||||
virtual const char *GetExtensionURL() =0;
|
virtual const char *GetExtensionURL() =0;
|
||||||
virtual const char *GetExtensionTag() =0;
|
virtual const char *GetExtensionTag() =0;
|
||||||
@ -138,25 +183,6 @@ namespace SourceMod
|
|||||||
char *error,
|
char *error,
|
||||||
size_t err_max) =0;
|
size_t err_max) =0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the number of plugins that will be unloaded when this
|
|
||||||
* module is unloaded.
|
|
||||||
*
|
|
||||||
* @param pExt IExtension pointer.
|
|
||||||
* @param optional Optional pointer to be filled with # of plugins that
|
|
||||||
* are dependent, but will continue safely. NOT YET USED.
|
|
||||||
* @return Total number of dependent plugins.
|
|
||||||
*/
|
|
||||||
virtual unsigned int NumberOfPluginDependents(IExtension *pExt, unsigned int *optional) =0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns whether or not the extension can be unloaded.
|
|
||||||
*
|
|
||||||
* @param pExt IExtension pointer.
|
|
||||||
* @return True if unloading is possible, false otherwise.
|
|
||||||
*/
|
|
||||||
virtual bool IsExtensionUnloadable(IExtension *pExtension) =0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Attempts to unload a module.
|
* @brief Attempts to unload a module.
|
||||||
*
|
*
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
namespace SourceMod
|
namespace SourceMod
|
||||||
{
|
{
|
||||||
|
class IExtension;
|
||||||
struct IdentityToken_t;
|
struct IdentityToken_t;
|
||||||
typedef unsigned int HandleType_t;
|
typedef unsigned int HandleType_t;
|
||||||
typedef HandleType_t IdentityType_t;
|
typedef HandleType_t IdentityType_t;
|
||||||
@ -53,11 +54,11 @@ namespace SourceMod
|
|||||||
/**
|
/**
|
||||||
* @brief Adds an interface to the global interface system.
|
* @brief Adds an interface to the global interface system.
|
||||||
*
|
*
|
||||||
|
* @param myself Object adding this interface, in order to track dependencies.
|
||||||
* @param iface Interface pointer (must be unique).
|
* @param iface Interface pointer (must be unique).
|
||||||
* @param token Parent token of the module/interface.
|
|
||||||
* @return True on success, false otherwise.
|
* @return True on success, false otherwise.
|
||||||
*/
|
*/
|
||||||
virtual bool AddInterface(SMInterface *iface, IdentityToken_t *token) =0;
|
virtual bool AddInterface(IExtension *myself, SMInterface *iface) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Requests an interface from the global interface system.
|
* @brief Requests an interface from the global interface system.
|
||||||
@ -65,12 +66,12 @@ namespace SourceMod
|
|||||||
*
|
*
|
||||||
* @param iface_name Interface name.
|
* @param iface_name Interface name.
|
||||||
* @param iface_vers Interface version to attempt to match.
|
* @param iface_vers Interface version to attempt to match.
|
||||||
* @param token Object requesting this interface, in order to track dependencies.
|
* @param myself Object requesting this interface, in order to track dependencies.
|
||||||
* @param pIface Pointer to store the return value in.
|
* @param pIface Pointer to store the return value in.
|
||||||
*/
|
*/
|
||||||
virtual bool RequestInterface(const char *iface_name,
|
virtual bool RequestInterface(const char *iface_name,
|
||||||
unsigned int iface_vers,
|
unsigned int iface_vers,
|
||||||
IdentityToken_t *token,
|
IExtension *myself,
|
||||||
SMInterface **pIface) =0;
|
SMInterface **pIface) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,6 +7,7 @@ SourceMod_Core g_SourceMod_Core;
|
|||||||
IVEngineServer *engine = NULL;
|
IVEngineServer *engine = NULL;
|
||||||
IServerGameDLL *gamedll = NULL;
|
IServerGameDLL *gamedll = NULL;
|
||||||
IServerGameClients *serverClients = NULL;
|
IServerGameClients *serverClients = NULL;
|
||||||
|
ISmmPluginManager *g_pMMPlugins = NULL;
|
||||||
|
|
||||||
PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core);
|
PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core);
|
||||||
|
|
||||||
@ -18,6 +19,15 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen
|
|||||||
GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
||||||
GET_V_IFACE_CURRENT(serverFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
|
GET_V_IFACE_CURRENT(serverFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
|
||||||
|
|
||||||
|
if ((g_pMMPlugins = (ISmmPluginManager *)g_SMAPI->MetaFactory(MMIFACE_PLMANAGER, NULL, NULL)) == NULL)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
snprintf(error, maxlen, "Unable to find interface %s", MMIFACE_PLMANAGER);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return g_SourceMod.InitializeSourceMod(error, maxlen, late);
|
return g_SourceMod.InitializeSourceMod(error, maxlen, late);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ extern SourceMod_Core g_SourceMod_Core;
|
|||||||
extern IVEngineServer *engine;
|
extern IVEngineServer *engine;
|
||||||
extern IServerGameDLL *gamedll;
|
extern IServerGameDLL *gamedll;
|
||||||
extern IServerGameClients *serverClients;
|
extern IServerGameClients *serverClients;
|
||||||
|
extern ISmmPluginManager *g_pMMPlugins;
|
||||||
|
|
||||||
PLUGIN_GLOBALVARS();
|
PLUGIN_GLOBALVARS();
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "LibrarySys.h"
|
#include "LibrarySys.h"
|
||||||
#include "ShareSys.h"
|
#include "ShareSys.h"
|
||||||
#include "CLogger.h"
|
#include "CLogger.h"
|
||||||
|
#include "sourcemm_api.h"
|
||||||
|
|
||||||
CExtensionManager g_Extensions;
|
CExtensionManager g_Extensions;
|
||||||
IdentityType_t g_ExtType;
|
IdentityType_t g_ExtType;
|
||||||
@ -11,6 +12,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
|
|||||||
m_File.assign(filename);
|
m_File.assign(filename);
|
||||||
m_pAPI = NULL;
|
m_pAPI = NULL;
|
||||||
m_pIdentToken = NULL;
|
m_pIdentToken = NULL;
|
||||||
|
m_PlId = 0;
|
||||||
|
|
||||||
char path[PLATFORM_MAX_PATH+1];
|
char path[PLATFORM_MAX_PATH+1];
|
||||||
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename);
|
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename);
|
||||||
@ -44,7 +46,8 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
|
|||||||
|
|
||||||
if (m_pAPI->IsMetamodExtension())
|
if (m_pAPI->IsMetamodExtension())
|
||||||
{
|
{
|
||||||
/* :TODO: STUFF */
|
bool already;
|
||||||
|
m_PlId = g_pMMPlugins->Load(path, g_PLID, already, error, err_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType);
|
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType);
|
||||||
@ -53,7 +56,12 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
|
|||||||
{
|
{
|
||||||
if (m_pAPI->IsMetamodExtension())
|
if (m_pAPI->IsMetamodExtension())
|
||||||
{
|
{
|
||||||
/* :TODO: stuff */
|
if (m_PlId)
|
||||||
|
{
|
||||||
|
char dummy[255];
|
||||||
|
g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
|
||||||
|
m_PlId = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_pAPI = NULL;
|
m_pAPI = NULL;
|
||||||
m_pLib->CloseLibrary();
|
m_pLib->CloseLibrary();
|
||||||
@ -69,6 +77,10 @@ CExtension::~CExtension()
|
|||||||
if (m_pAPI)
|
if (m_pAPI)
|
||||||
{
|
{
|
||||||
m_pAPI->OnExtensionUnload();
|
m_pAPI->OnExtensionUnload();
|
||||||
|
if (m_PlId)
|
||||||
|
{
|
||||||
|
g_pMMPlugins->Unload(m_PlId, true, NULL, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pIdentToken)
|
if (m_pIdentToken)
|
||||||
@ -107,6 +119,81 @@ bool CExtension::IsLoaded()
|
|||||||
return (m_pLib != NULL);
|
return (m_pLib != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CExtension::AddDependency(IfaceInfo *pInfo)
|
||||||
|
{
|
||||||
|
m_Deps.push_back(*pInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
|
||||||
|
{
|
||||||
|
List<IfaceInfo>::iterator iter = m_Deps.begin();
|
||||||
|
|
||||||
|
if (iter == m_Deps.end())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pOwner)
|
||||||
|
{
|
||||||
|
*pOwner = (*iter).owner;
|
||||||
|
}
|
||||||
|
if (pInterface)
|
||||||
|
{
|
||||||
|
*pInterface = (*iter).iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
|
||||||
|
|
||||||
|
return (ITERATOR *)pIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
|
||||||
|
{
|
||||||
|
List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
|
||||||
|
List<IfaceInfo>::iterator _iter;
|
||||||
|
|
||||||
|
if (_iter == m_Deps.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_iter++;
|
||||||
|
|
||||||
|
if (pOwner)
|
||||||
|
{
|
||||||
|
*pOwner = (*_iter).owner;
|
||||||
|
}
|
||||||
|
if (pInterface)
|
||||||
|
{
|
||||||
|
*pInterface = (*_iter).iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pIter = _iter;
|
||||||
|
|
||||||
|
if (_iter == m_Deps.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CExtension::FreeDependencyIterator(ITERATOR *iter)
|
||||||
|
{
|
||||||
|
List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
|
||||||
|
|
||||||
|
delete pIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CExtension::AddInterface(SMInterface *pInterface)
|
||||||
|
{
|
||||||
|
m_Interfaces.push_back(pInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* EXTENSION MANAGER *
|
||||||
|
*********************/
|
||||||
|
|
||||||
void CExtensionManager::OnSourceModAllInitialized()
|
void CExtensionManager::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
|
g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
|
||||||
@ -119,6 +206,12 @@ void CExtensionManager::OnSourceModShutdown()
|
|||||||
|
|
||||||
IExtension *CExtensionManager::LoadAutoExtension(const char *path)
|
IExtension *CExtensionManager::LoadAutoExtension(const char *path)
|
||||||
{
|
{
|
||||||
|
IExtension *pAlready;
|
||||||
|
if ((pAlready=FindExtensionByFile(path)) != NULL)
|
||||||
|
{
|
||||||
|
return pAlready;
|
||||||
|
}
|
||||||
|
|
||||||
char error[256];
|
char error[256];
|
||||||
CExtension *p = new CExtension(path, error, sizeof(error));
|
CExtension *p = new CExtension(path, error, sizeof(error));
|
||||||
|
|
||||||
@ -188,6 +281,12 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
|||||||
|
|
||||||
IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t err_max)
|
IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t err_max)
|
||||||
{
|
{
|
||||||
|
IExtension *pAlready;
|
||||||
|
if ((pAlready=FindExtensionByFile(file)) != NULL)
|
||||||
|
{
|
||||||
|
return pAlready;
|
||||||
|
}
|
||||||
|
|
||||||
CExtension *pExt = new CExtension(file, error, err_max);
|
CExtension *pExt = new CExtension(file, error, err_max);
|
||||||
|
|
||||||
/* :NOTE: lifetime is currently ignored */
|
/* :NOTE: lifetime is currently ignored */
|
||||||
@ -203,20 +302,80 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime
|
|||||||
return pExt;
|
return pExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CExtensionManager::UnloadExtension(IExtension *pExt)
|
void CExtensionManager::BindDependency(IExtension *pOwner, IfaceInfo *pInfo)
|
||||||
{
|
{
|
||||||
/* :TODO: implement */
|
CExtension *pExt = (CExtension *)pOwner;
|
||||||
return true;
|
|
||||||
|
pExt->AddDependency(pInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CExtensionManager::NumberOfPluginDependents(IExtension *pExt, unsigned int *optional)
|
void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
|
||||||
{
|
{
|
||||||
/* :TODO: implement */
|
CExtension *pExt = (CExtension *)pOwner;
|
||||||
return 0;
|
|
||||||
|
pExt->AddInterface(pInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CExtensionManager::IsExtensionUnloadable(IExtension *pExtension)
|
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||||
{
|
{
|
||||||
/* :TODO: implement */
|
if (!_pExt)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CExtension *pExt = (CExtension *)_pExt;
|
||||||
|
|
||||||
|
if (m_Libs.find(pExt) == m_Libs.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First remove us from internal lists */
|
||||||
|
g_ShareSys.RemoveInterfaces(_pExt);
|
||||||
|
m_Libs.remove(pExt);
|
||||||
|
|
||||||
|
List<CExtension *> UnloadQueue;
|
||||||
|
|
||||||
|
/* Handle dependencies */
|
||||||
|
if (pExt->IsLoaded())
|
||||||
|
{
|
||||||
|
/* Notify and/or unload all dependencies */
|
||||||
|
List<CExtension *>::iterator c_iter;
|
||||||
|
CExtension *pDep;
|
||||||
|
IExtensionInterface *pAPI;
|
||||||
|
for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
|
||||||
|
{
|
||||||
|
pDep = (*c_iter);
|
||||||
|
if ((pAPI=pDep->GetAPI()) == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Now, get its dependency list */
|
||||||
|
bool dropped = false;
|
||||||
|
List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
|
||||||
|
while (i_iter != pDep->m_Deps.end())
|
||||||
|
{
|
||||||
|
if ((*i_iter).owner == _pExt)
|
||||||
|
{
|
||||||
|
if (!dropped && !pAPI->QueryInterfaceDrop((*i_iter).iface))
|
||||||
|
{
|
||||||
|
dropped = true;
|
||||||
|
}
|
||||||
|
pAPI->NotifyInterfaceDrop((*i_iter).iface);
|
||||||
|
i_iter = pDep->m_Deps.erase(i_iter);
|
||||||
|
} else {
|
||||||
|
i_iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CExtension *>::iterator iter;
|
||||||
|
for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
|
||||||
|
{
|
||||||
|
/* NOTE: This is safe because the unload function backs out of anything not present */
|
||||||
|
UnloadExtension((*iter));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,15 @@
|
|||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
|
#include "ShareSys.h"
|
||||||
|
#include <ISmmAPI.h>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
class CExtension : public IExtension
|
class CExtension : public IExtension
|
||||||
{
|
{
|
||||||
|
friend class CExtensionManager;
|
||||||
public:
|
public:
|
||||||
CExtension(const char *filename, char *error, size_t maxlen);
|
CExtension(const char *filename, char *error, size_t maxlen);
|
||||||
~CExtension();
|
~CExtension();
|
||||||
@ -20,14 +23,22 @@ public: //IExtension
|
|||||||
const char *GetFilename();
|
const char *GetFilename();
|
||||||
IdentityToken_t *GetIdentity();
|
IdentityToken_t *GetIdentity();
|
||||||
bool IsLoaded();
|
bool IsLoaded();
|
||||||
|
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
||||||
|
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
||||||
|
void FreeDependencyIterator(ITERATOR *iter);
|
||||||
public:
|
public:
|
||||||
void SetError(const char *error);
|
void SetError(const char *error);
|
||||||
|
void AddDependency(IfaceInfo *pInfo);
|
||||||
|
void AddInterface(SMInterface *pInterface);
|
||||||
private:
|
private:
|
||||||
IdentityToken_t *m_pIdentToken;
|
IdentityToken_t *m_pIdentToken;
|
||||||
IExtensionInterface *m_pAPI;
|
IExtensionInterface *m_pAPI;
|
||||||
String m_File;
|
String m_File;
|
||||||
ILibrary *m_pLib;
|
ILibrary *m_pLib;
|
||||||
String m_Error;
|
String m_Error;
|
||||||
|
List<IfaceInfo> m_Deps;
|
||||||
|
List<SMInterface *> m_Interfaces;
|
||||||
|
PluginId m_PlId;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CExtensionManager :
|
class CExtensionManager :
|
||||||
@ -42,13 +53,13 @@ public: //IExtensionManager
|
|||||||
ExtensionLifetime lifetime,
|
ExtensionLifetime lifetime,
|
||||||
char *error,
|
char *error,
|
||||||
size_t err_max);
|
size_t err_max);
|
||||||
unsigned int NumberOfPluginDependents(IExtension *pExt, unsigned int *optional);
|
|
||||||
bool IsExtensionUnloadable(IExtension *pExtension);
|
|
||||||
bool UnloadExtension(IExtension *pExt);
|
bool UnloadExtension(IExtension *pExt);
|
||||||
IExtension *FindExtensionByFile(const char *file);
|
IExtension *FindExtensionByFile(const char *file);
|
||||||
IExtension *FindExtensionByName(const char *ext);
|
IExtension *FindExtensionByName(const char *ext);
|
||||||
public:
|
public:
|
||||||
IExtension *LoadAutoExtension(const char *path);
|
IExtension *LoadAutoExtension(const char *path);
|
||||||
|
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
|
||||||
|
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
|
||||||
private:
|
private:
|
||||||
List<CExtension *> m_Libs;
|
List<CExtension *> m_Libs;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "ShareSys.h"
|
#include "ShareSys.h"
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
|
#include "ExtensionSys.h"
|
||||||
|
|
||||||
ShareSystem g_ShareSys;
|
ShareSystem g_ShareSys;
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type)
|
|||||||
return pToken;
|
return pToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token)
|
bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
|
||||||
{
|
{
|
||||||
if (!iface)
|
if (!iface)
|
||||||
{
|
{
|
||||||
@ -99,17 +100,9 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token)
|
|||||||
|
|
||||||
IfaceInfo info;
|
IfaceInfo info;
|
||||||
|
|
||||||
|
info.owner = myself;
|
||||||
info.iface = iface;
|
info.iface = iface;
|
||||||
info.token = token;
|
|
||||||
|
|
||||||
if (token)
|
|
||||||
{
|
|
||||||
/* If we're an external object, we have to do this */
|
|
||||||
info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot(), NULL);
|
|
||||||
} else {
|
|
||||||
info.handle = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Interfaces.push_back(info);
|
m_Interfaces.push_back(info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -117,28 +110,13 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token)
|
|||||||
|
|
||||||
bool ShareSystem::RequestInterface(const char *iface_name,
|
bool ShareSystem::RequestInterface(const char *iface_name,
|
||||||
unsigned int iface_vers,
|
unsigned int iface_vers,
|
||||||
IdentityToken_t *token,
|
IExtension *mysql,
|
||||||
SMInterface **pIface)
|
SMInterface **pIface)
|
||||||
{
|
{
|
||||||
/* If Some yahoo.... SOME HOOLIGAN... some NO GOOD DIRTY
|
|
||||||
* HORRIBLE PERSON passed in a token that we don't recognize....
|
|
||||||
* <b>Punish them.</b>
|
|
||||||
*/
|
|
||||||
HandleSecurity sec;
|
|
||||||
|
|
||||||
sec.pIdentity = GetIdentRoot();
|
|
||||||
sec.pOwner = NULL;
|
|
||||||
|
|
||||||
if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, &sec, NULL))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See if the interface exists */
|
/* See if the interface exists */
|
||||||
List<IfaceInfo>::iterator iter;
|
List<IfaceInfo>::iterator iter;
|
||||||
SMInterface *iface;
|
SMInterface *iface;
|
||||||
IdentityToken_t *iface_owner;
|
IExtension *iface_owner;
|
||||||
Handle_t iface_handle;
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
|
for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
|
||||||
{
|
{
|
||||||
@ -149,8 +127,7 @@ bool ShareSystem::RequestInterface(const char *iface_name,
|
|||||||
if (iface->GetInterfaceVersion() == iface_vers
|
if (iface->GetInterfaceVersion() == iface_vers
|
||||||
|| iface->IsVersionCompatible(iface_vers))
|
|| iface->IsVersionCompatible(iface_vers))
|
||||||
{
|
{
|
||||||
iface_owner = info.token;
|
iface_owner = info.owner;
|
||||||
iface_handle = info.handle;
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -162,23 +139,21 @@ bool ShareSystem::RequestInterface(const char *iface_name,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If something external owns this, we need to track it. */
|
/* Add a dependency node */
|
||||||
if (iface_owner)
|
if (iface_owner)
|
||||||
{
|
{
|
||||||
Handle_t newhandle;
|
IfaceInfo info;
|
||||||
if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, &sec)
|
info.iface = iface;
|
||||||
!= HandleError_None)
|
info.owner = iface_owner;
|
||||||
{
|
g_Extensions.BindDependency(iface_owner, &info);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Now we can deny module loads based on dependencies.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :TODO: finish */
|
if (pIface)
|
||||||
|
{
|
||||||
|
*pIface = iface;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[])
|
void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[])
|
||||||
@ -202,3 +177,17 @@ void ShareSystem::DestroyIdentType(IdentityType_t type)
|
|||||||
g_HandleSys.RemoveType(type, GetIdentRoot());
|
g_HandleSys.RemoveType(type, GetIdentRoot());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShareSystem::RemoveInterfaces(IExtension *pExtension)
|
||||||
|
{
|
||||||
|
List<IfaceInfo>::iterator iter = m_Interfaces.begin();
|
||||||
|
|
||||||
|
while (iter != m_Interfaces.end())
|
||||||
|
{
|
||||||
|
if ((*iter).owner == pExtension)
|
||||||
|
{
|
||||||
|
iter = m_Interfaces.erase(iter);
|
||||||
|
} else {
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,8 +20,7 @@ namespace SourceMod
|
|||||||
struct IfaceInfo
|
struct IfaceInfo
|
||||||
{
|
{
|
||||||
SMInterface *iface;
|
SMInterface *iface;
|
||||||
IdentityToken_t *token;
|
IExtension *owner;
|
||||||
Handle_t handle;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShareSystem :
|
class ShareSystem :
|
||||||
@ -32,10 +31,10 @@ class ShareSystem :
|
|||||||
public:
|
public:
|
||||||
ShareSystem();
|
ShareSystem();
|
||||||
public: //IShareSys
|
public: //IShareSys
|
||||||
bool AddInterface(SMInterface *iface, IdentityToken_t *token);
|
bool AddInterface(IExtension *myself, SMInterface *pIface);
|
||||||
bool RequestInterface(const char *iface_name,
|
bool RequestInterface(const char *iface_name,
|
||||||
unsigned int iface_vers,
|
unsigned int iface_vers,
|
||||||
IdentityToken_t *token,
|
IExtension *mysql,
|
||||||
SMInterface **pIface);
|
SMInterface **pIface);
|
||||||
void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]);
|
void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]);
|
||||||
IdentityType_t CreateIdentType(const char *name);
|
IdentityType_t CreateIdentType(const char *name);
|
||||||
@ -51,6 +50,7 @@ public: //IHandleTypeDispatch
|
|||||||
void OnHandleDestroy(HandleType_t type, void *object);
|
void OnHandleDestroy(HandleType_t type, void *object);
|
||||||
public:
|
public:
|
||||||
IdentityToken_t *CreateCoreIdentity();
|
IdentityToken_t *CreateCoreIdentity();
|
||||||
|
void RemoveInterfaces(IExtension *pExtension);
|
||||||
public:
|
public:
|
||||||
inline IdentityToken_t *GetIdentRoot()
|
inline IdentityToken_t *GetIdentRoot()
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="3"
|
RuntimeLibrary="1"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="true"
|
Detect64BitPortabilityProblems="true"
|
||||||
@ -60,6 +60,7 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
|
OutputFile="$(OutDir)\sample.ext.dll"
|
||||||
LinkIncremental="2"
|
LinkIncremental="2"
|
||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
SubSystem="2"
|
SubSystem="2"
|
||||||
@ -116,7 +117,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||||
RuntimeLibrary="2"
|
RuntimeLibrary="0"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="true"
|
Detect64BitPortabilityProblems="true"
|
||||||
@ -133,6 +134,7 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
|
OutputFile="$(OutDir)\sample.ext.dll"
|
||||||
LinkIncremental="1"
|
LinkIncremental="1"
|
||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
SubSystem="2"
|
SubSystem="2"
|
||||||
@ -193,7 +195,7 @@
|
|||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SMEXT_CONF_METAMOD"
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SMEXT_CONF_METAMOD"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="3"
|
RuntimeLibrary="1"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="true"
|
Detect64BitPortabilityProblems="true"
|
||||||
@ -211,6 +213,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
AdditionalDependencies="tier0.lib"
|
AdditionalDependencies="tier0.lib"
|
||||||
|
OutputFile="$(OutDir)\sample.ext.dll"
|
||||||
LinkIncremental="2"
|
LinkIncremental="2"
|
||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
SubSystem="2"
|
SubSystem="2"
|
||||||
@ -267,7 +270,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SMEXT_CONF_METAMOD"
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SMEXT_CONF_METAMOD"
|
||||||
RuntimeLibrary="2"
|
RuntimeLibrary="0"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="true"
|
Detect64BitPortabilityProblems="true"
|
||||||
@ -284,6 +287,7 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
|
OutputFile="$(OutDir)\sample.ext.dll"
|
||||||
LinkIncremental="1"
|
LinkIncremental="1"
|
||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
SubSystem="2"
|
SubSystem="2"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include "smsdk_ext.h"
|
#include "smsdk_ext.h"
|
||||||
|
|
||||||
IShareSys *g_pShareSys = NULL;
|
IShareSys *g_pShareSys = NULL;
|
||||||
IdentityToken_t *myself = NULL;
|
IExtension *myself = NULL;
|
||||||
IHandleSys *g_pHandleSys = NULL;
|
IHandleSys *g_pHandleSys = NULL;
|
||||||
|
|
||||||
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
|
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
|
||||||
@ -22,7 +22,9 @@ SDKExtension::SDKExtension()
|
|||||||
bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late)
|
bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late)
|
||||||
{
|
{
|
||||||
g_pShareSys = sys;
|
g_pShareSys = sys;
|
||||||
myself = me->GetIdentity();
|
myself = me;
|
||||||
|
|
||||||
|
m_WeAreUnloaded = true;
|
||||||
|
|
||||||
#if defined SMEXT_CONF_METAMOD
|
#if defined SMEXT_CONF_METAMOD
|
||||||
if (!m_SourceMMLoaded)
|
if (!m_SourceMMLoaded)
|
||||||
@ -37,7 +39,13 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error,
|
|||||||
|
|
||||||
SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys);
|
SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys);
|
||||||
|
|
||||||
return SDK_OnLoad(error, err_max, late);
|
if (SDK_OnLoad(error, err_max, late))
|
||||||
|
{
|
||||||
|
m_WeAreUnloaded = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDKExtension::IsMetamodExtension()
|
bool SDKExtension::IsMetamodExtension()
|
||||||
@ -51,7 +59,9 @@ bool SDKExtension::IsMetamodExtension()
|
|||||||
|
|
||||||
void SDKExtension::OnExtensionPauseChange(bool state)
|
void SDKExtension::OnExtensionPauseChange(bool state)
|
||||||
{
|
{
|
||||||
|
#if defined SMEXT_CONF_METAMOD
|
||||||
m_WeGotPauseChange = true;
|
m_WeGotPauseChange = true;
|
||||||
|
#endif
|
||||||
SDK_OnPauseChange(state);
|
SDK_OnPauseChange(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +72,9 @@ void SDKExtension::OnExtensionsAllLoaded()
|
|||||||
|
|
||||||
void SDKExtension::OnExtensionUnload()
|
void SDKExtension::OnExtensionUnload()
|
||||||
{
|
{
|
||||||
|
#if defined SMEXT_CONF_METAMOD
|
||||||
m_WeAreUnloaded = true;
|
m_WeAreUnloaded = true;
|
||||||
|
#endif
|
||||||
SDK_OnUnload();
|
SDK_OnUnload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ private:
|
|||||||
extern SDKExtension *g_pExtensionIface;
|
extern SDKExtension *g_pExtensionIface;
|
||||||
|
|
||||||
extern IShareSys *g_pShareSys;
|
extern IShareSys *g_pShareSys;
|
||||||
extern IdentityToken_t *myself;
|
extern IExtension *myself;
|
||||||
extern IHandleSys *g_pHandleSys;
|
extern IHandleSys *g_pHandleSys;
|
||||||
|
|
||||||
#if defined SMEXT_CONF_METAMOD
|
#if defined SMEXT_CONF_METAMOD
|
||||||
|
Loading…
Reference in New Issue
Block a user