diff --git a/sourcemm/CPlugin.cpp b/sourcemm/CPlugin.cpp index e015eed..f9696cd 100644 --- a/sourcemm/CPlugin.cpp +++ b/sourcemm/CPlugin.cpp @@ -39,7 +39,7 @@ CPluginManager::~CPluginManager() CPluginManager::CPlugin::CPlugin() : m_Lib(NULL), m_API(NULL), m_Id(0), m_Source(0) { - memset(&fac_list, 0, sizeof(factories)); + } PluginId CPluginManager::Load(const char *file, PluginId source, bool &already, char *error, size_t maxlen) @@ -260,7 +260,7 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source snprintf(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION); pl->m_Status = Pl_Error; } else { - if (pl->m_API->Load(pl->m_Id, static_cast(&g_SmmAPI), &(pl->fac_list), error, maxlen, m_AllLoaded)) + if (pl->m_API->Load(pl->m_Id, static_cast(&g_SmmAPI), error, maxlen, m_AllLoaded)) { pl->m_Status = Pl_Running; if (m_AllLoaded) @@ -409,7 +409,7 @@ bool CPluginManager::UnloadAll() return status; } -bool CPluginManager::Query(PluginId id, const char *&file, factories *&list, Pl_Status &status, PluginId &source) +bool CPluginManager::Query(PluginId id, const char *&file, Pl_Status &status, PluginId &source) { CPlugin *pl = FindById(id); @@ -417,7 +417,6 @@ bool CPluginManager::Query(PluginId id, const char *&file, factories *&list, Pl_ return false; file = pl->m_File.c_str(); - list = &(pl->fac_list); status = pl->m_Status; source = pl->m_Source; diff --git a/sourcemm/CPlugin.h b/sourcemm/CPlugin.h index 2057661..00a4fbd 100644 --- a/sourcemm/CPlugin.h +++ b/sourcemm/CPlugin.h @@ -61,9 +61,9 @@ namespace SourceMM PluginId m_Source; ISmmPlugin *m_API; HINSTANCE m_Lib; - factories fac_list; SourceHook::List m_Cvars; SourceHook::List m_Cmds; + SourceHook::List m_Events; }; public: CPluginManager(); @@ -76,7 +76,7 @@ namespace SourceMM bool Unpause(PluginId id, char *error, size_t maxlen); bool UnloadAll(); public: - bool Query(PluginId id, const char *&file, factories *&list, Pl_Status &status, PluginId &source); + bool Query(PluginId id, const char *&file, Pl_Status &status, PluginId &source); bool QueryRunning(PluginId id, char *error, size_t maxlength); void AddPluginCvar(ISmmPlugin *api, ConCommandBase *pCvar); diff --git a/sourcemm/CSmmAPI.cpp b/sourcemm/CSmmAPI.cpp index 78bcb07..d67f412 100644 --- a/sourcemm/CSmmAPI.cpp +++ b/sourcemm/CSmmAPI.cpp @@ -28,16 +28,6 @@ CSmmAPI::CSmmAPI() m_Cache = false; } -ISmmPluginManager *CSmmAPI::PluginManager() -{ - return static_cast(&g_PluginMngr); -} - -SourceHook::ISourceHook *CSmmAPI::SourceHook() -{ - return static_cast(&g_SourceHook); -} - void CSmmAPI::LogMsg(ISmmPlugin *pl, const char *msg, ...) { va_list ap; @@ -139,6 +129,58 @@ void CSmmAPI::ConPrintf(const char *fmt, ...) va_end(ap); } +void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener) +{ + CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin); + + pl->m_Events.push_back(pListener); +} + +void *CSmmAPI::MetaFactory(const char *iface, int *_ret) +{ + if (!iface) + return NULL; + + //first check ours... we get first chance! + if (strcmp(iface, MMIFACE_SOURCEHOOK)==0) + { + if (_ret) + *_ret = IFACE_OK; + return static_cast(static_cast(&g_SourceHook)); + } else if (strcmp(iface, MMIFACE_PLMANAGER)==0) { + if (_ret) + *_ret = IFACE_OK; + return static_cast(static_cast(&g_SMConVarAccessor)); + } + + CPluginManager::CPlugin *pl; + SourceHook::List::iterator event; + IMetamodListener *api; + int ret = 0; + void *val = NULL; + + for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) + { + pl = (*iter); + for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) + { + api = (*event); + ret = IFACE_FAILED; + if ( (val=api->OnMetamodQuery(iface, &ret)) != NULL ) + { + if (_ret) + *_ret = ret; + return val; + } + } + } + + if (_ret) + *_ret = IFACE_FAILED; + + return NULL; +} + ////////////////////////////////////////////////////////////////////////// //THERE BE HAX HERE!!!! DON'T TELL ALFRED, BUT GABE WANTED IT THAT WAY. // // (note: you can find the offset by looking for the text // diff --git a/sourcemm/CSmmAPI.h b/sourcemm/CSmmAPI.h index 9ebe0a5..0f838c5 100644 --- a/sourcemm/CSmmAPI.h +++ b/sourcemm/CSmmAPI.h @@ -27,8 +27,6 @@ namespace SourceMM public: CSmmAPI::CSmmAPI(); public: - ISmmPluginManager *PluginManager(); - SourceHook::ISourceHook *SourceHook(); void LogMsg(ISmmPlugin *pl, const char *msg, ...); public: CreateInterfaceFn engineFactory(bool syn=true); @@ -50,6 +48,8 @@ namespace SourceMM } virtual void GetApiVersions(int &major, int &minor, int &plvers, int &plmin); virtual void GetShVersions(int &shvers, int &shimpl); + virtual void AddListener(ISmmPlugin *plugin, IMetamodListener *pListener); + virtual void *MetaFactory(const char *iface, int *ret); public: bool CacheCmds(); private: diff --git a/sourcemm/IPluginManager.h b/sourcemm/IPluginManager.h index bfe1d8c..a496594 100644 --- a/sourcemm/IPluginManager.h +++ b/sourcemm/IPluginManager.h @@ -110,7 +110,7 @@ public: * @param source By reference source of plugin * @return True on success, false if not found */ - virtual bool Query(PluginId id, const char *&file, factories *&list, Pl_Status &status, PluginId &source) =0; + virtual bool Query(PluginId id, const char *&file, Pl_Status &status, PluginId &source) =0; /** * @brief Checks another plugin's QueryRunning() status. diff --git a/sourcemm/ISmmAPI.h b/sourcemm/ISmmAPI.h index ad18218..4c5fb43 100644 --- a/sourcemm/ISmmAPI.h +++ b/sourcemm/ISmmAPI.h @@ -28,14 +28,16 @@ #endif //version check #endif //__GNUC__ +class IMetamodListener; class ISmmPluginManager; class ISmmPlugin; +#define MMIFACE_SOURCEHOOK "ISourceHook" +#define MMIFACE_PLMANAGER "IPluginManager" + class ISmmAPI { public: - virtual ISmmPluginManager *PluginManager() =0; - virtual SourceHook::ISourceHook *SourceHook() =0; virtual void LogMsg(ISmmPlugin *pl, const char *msg, ...) =0; public: virtual CreateInterfaceFn engineFactory(bool syn=true) =0; @@ -64,8 +66,13 @@ public: //Added in 1.10 (1:0) virtual void GetApiVersions(int &major, int &minor, int &plvers, int &plmin) =0; //Returns sourcehook API version and implementation version virtual void GetShVersions(int &shvers, int &shimpl) =0; + //Binds an event listener to your plugin + virtual void AddListener(ISmmPlugin *plugin, IMetamodListener *pListener) =0; + //Queries the metamod factory + virtual void *MetaFactory(const char *iface, int *ret) =0; }; + /** Version history * 1.10 bumped API to 1:0. The breaking changes occured in sourcehook and the plugin API. */ diff --git a/sourcemm/ISmmPlugin.h b/sourcemm/ISmmPlugin.h index 511a4c6..a8ba6ea 100644 --- a/sourcemm/ISmmPlugin.h +++ b/sourcemm/ISmmPlugin.h @@ -23,14 +23,6 @@ #define PLAPI_VERSION 7 #define PLAPI_NAME "ISmmPlugin" -struct factories -{ - CreateInterfaceFn engine; - CreateInterfaceFn server; - CreateInterfaceFn physics; - CreateInterfaceFn fileSystem; -}; - class ISmmAPI; typedef int PluginId; @@ -57,7 +49,7 @@ public: * @param maxlen Size of error message buffer * @return True if successful, return false to reject the load. */ - virtual bool Load(PluginId id, ISmmAPI *ismm, factories *list, char *error, size_t maxlength, bool late) =0; + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late) =0; /** * @brief Called when your plugin is "queried". This is useful for rejecting a loaded @@ -151,6 +143,60 @@ public: } }; +/** + * @brief Added in 1.2 so plugins could listen to specific events + */ +class IMetamodListener +{ +public: + virtual ~IMetamodListener() { } +public: + virtual void OnPluginLoad(PluginId id) { } + + virtual void OnPluginUnload(PluginId id) { } + + virtual void OnPluginPause(PluginId id) { } + + virtual void OnPluginUnpause(PluginId id) { } + + virtual void OnLevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) { } + + virtual void *OnEngineQuery(const char *iface, int *ret) + { + if (ret) + *ret = IFACE_FAILED; + return NULL; + } + + virtual void *OnPhysicsQuery(const char *iface, int *ret) + { + if (ret) + *ret = IFACE_FAILED; + return NULL; + } + + virtual void *OnFileSystemQuery(const char *iface, int *ret) + { + if (ret) + *ret = IFACE_FAILED; + return NULL; + } + + virtual void *OnGameDLLQuery(const char *iface, int *ret) + { + if (ret) + *ret = IFACE_FAILED; + return NULL; + } + + virtual void *OnMetamodQuery(const char *iface, int *ret) + { + if (ret) + *ret = IFACE_FAILED; + return NULL; + } +}; + #define PL_EXPOSURE CreateInterface #define PL_EXPOSURE_C "CreateInterface" @@ -174,7 +220,7 @@ public: #define PLUGIN_SAVEVARS() \ g_SMAPI = ismm; \ - g_SHPtr = ismm->SourceHook(); \ + g_SHPtr = ismm->MetaQuery(MMIFACE_SOURCEHOOK, NULL); \ g_PLAPI = static_cast(this); \ g_PLID = id; diff --git a/sourcemm/sourcemm.cpp b/sourcemm/sourcemm.cpp index e265862..1cc9476 100644 --- a/sourcemm/sourcemm.cpp +++ b/sourcemm/sourcemm.cpp @@ -15,8 +15,11 @@ #include "sourcemm.h" #include "concommands.h" #include "CSmmAPI.h" +#include "CPlugin.h" #include "util.h" +using namespace SourceMM; + /** * @brief Implementation of main SourceMM GameDLL functionality * @file sourcemm.cpp @@ -45,6 +48,26 @@ SourceHook::CallClass *dllExec; void ClearGamedllList(); +//helper macro +#define IFACE_MACRO(orig,nam) \ + CPluginManager::CPlugin *pl; \ + SourceHook::List::iterator event; \ + IMetamodListener *api; \ + int mret = 0; \ + void *val = NULL; \ + for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \ + pl = (*iter); \ + for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \ + api = (*event); \ + mret = IFACE_FAILED; \ + if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \ + if (ret) *ret = mret; \ + return val; \ + } \ + } \ + } \ + return (orig)(iface, ret); + /////////////////////////////////// // Main code for HL2 Interaction // /////////////////////////////////// @@ -115,7 +138,7 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, } //This is where the magic happens -SMM_API void *CreateInterface(const char *name, int *ret) +SMM_API void *CreateInterface(const char *iface, int *ret) { if (!gParsedGameInfo) { @@ -317,10 +340,10 @@ SMM_API void *CreateInterface(const char *name, int *ret) const char *str = "ServerGameDLL"; size_t len = strlen(str); - if (strncmp(name, str, len) == 0) + if (strncmp(iface, str, len) == 0) { //This is the interface we want! Right now we support versions 3 and 4. - int version = atoi(&(name[len])); + int version = atoi(&(iface[len])); if (version < MIN_GAMEDLL_VERSION || version > MAX_GAMEDLL_VERSION) { Error("GameDLL version %d is not supported by Metamod!", version); @@ -332,7 +355,7 @@ SMM_API void *CreateInterface(const char *name, int *ret) for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++) { pInfo = (*iter); - ptr = (pInfo->factory)(name, ret); + ptr = (pInfo->factory)(iface, ret); if (ptr) { //this is our gamedll. unload the others. @@ -361,8 +384,7 @@ SMM_API void *CreateInterface(const char *name, int *ret) } //if we got here, there's definitely a gamedll. - //META_INTERFACE_MACRO(server, g_GameDll.factory); - return (g_GameDll.factory)(name, ret); + IFACE_MACRO(g_GameDll.factory, GameDLL); } void ClearGamedllList() @@ -491,23 +513,23 @@ int LoadPluginsFromFile(const char *file) //Wrapper function. This is called when the GameDLL thinks it's using // the engine's real engineFactory. -void *EngineFactory(const char *name, int *ret) +void *EngineFactory(const char *iface, int *ret) { - META_INTERFACE_MACRO(engine, g_Engine.engineFactory); + IFACE_MACRO(g_Engine.engineFactory, Engine); } //Wrapper function. This is called when the GameDLL thinks it's using // the engine's real physicsFactory. -void *PhysicsFactory(const char *name, int *ret) +void *PhysicsFactory(const char *iface, int *ret) { - META_INTERFACE_MACRO(physics, g_Engine.physicsFactory); + IFACE_MACRO(g_Engine.physicsFactory, Physics); } //Wrapper function. This is called when the GameDLL thinks it's using // the engine's real fileSystemFactory. -void *FileSystemFactory(const char *name, int *ret) +void *FileSystemFactory(const char *iface, int *ret) { - META_INTERFACE_MACRO(fileSystem, g_Engine.fileSystemFactory); + IFACE_MACRO(g_Engine.fileSystemFactory, FileSystem); } void LogMessage(const char *msg, ...) diff --git a/sourcemm/util.h b/sourcemm/util.h index f078363..0718510 100644 --- a/sourcemm/util.h +++ b/sourcemm/util.h @@ -24,34 +24,4 @@ void UTIL_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t void UTIL_PathFmt(char *buffer, size_t len, const char *fmt, ...); bool UTIL_PathCmp(const char *path1, const char *path2); -#define META_INTERFACE_MACRO(type, final) \ - PluginIter i; \ - void *mret=NULL, *d; \ - META_RES mres, high=MRES_IGNORED; \ - g_SmmAPI.SetLastMetaReturn(MRES_IGNORED); \ - for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++) \ - { \ - if ( (*i) && (*i)->fac_list. type ) \ - { \ - d = ((*i)->fac_list. type)(name, ret); \ - mres = g_SmmAPI.GetLastMetaReturn(); \ - if (mres > high) \ - high = mres; \ - if (mres >= MRES_OVERRIDE) \ - mret = d; \ - } \ - } \ - if (high == MRES_OVERRIDE) \ - { \ - if (final) \ - (final)(name, ret); \ - return mret; \ - } else if (high == MRES_SUPERCEDE) { \ - return mret; \ - } else { \ - if (final) \ - return (final)(name, ret); \ - return NULL; \ - } - #endif //_INCLUDE_UTIL_H