diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index bdd95a92..655e98af 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -73,7 +73,7 @@ namespace SourceMod * @param result Pointer to store result of function on return. * @return SourcePawn error code (if any). */ - virtual int CallFunction(cell_t *params, unsigned int num_params, cell_t *result) =0; + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; /** * @brief Returns which plugin this function belongs to. diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 69f81f2a..4c7fca59 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -4,6 +4,7 @@ #include "systems/LibrarySys.h" #include "vm/sp_vm_engine.h" #include +#include "PluginSys.h" SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; @@ -99,5 +100,23 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) return false; } + unsigned int api = g_pVM->GetAPIVersion(); + if (api != SOURCEPAWN_VM_API_VERSION) + { + ShutdownJIT(); + if (error && err_max) + { + snprintf(error, err_max, "JIT is not a compatible version"); + } + return false; + } + + g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str()); + IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max); + IPluginFunction *func = pPlugin->GetFunctionByName("OnPluginInit"); + cell_t result; + func->CallFunction(NULL, 0, &result); + g_PluginMngr.UnloadPlugin(pPlugin); + return true; } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 2b7d2cec..71cce53d 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -7,6 +7,34 @@ CPluginManager::CPluginManager() { } +void CFunction::Set(funcid_t funcid, CPlugin *plugin) +{ + m_funcid = funcid; + m_pPlugin = plugin; +} + +int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) +{ + IPluginContext *ctx = m_pPlugin->m_ctx_current.base; + + for (unsigned int i=0; iPushCell(params[i]); + } + + return ctx->Execute(m_funcid, result); +} + +IPlugin *CFunction::GetParentPlugin() +{ + return m_pPlugin; +} + +CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : + m_funcid(funcid), m_pPlugin(plugin) +{ +} + CPlugin *CPlugin::CreatePlugin(const char *file, bool debug_default, PluginType type, @@ -67,9 +95,89 @@ CPlugin *CPlugin::CreatePlugin(const char *file, ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin; + /* Build function information loosely */ + pPlugin->m_funcsnum = g_pVM->FunctionCount(ctx); + + if (pPlugin->m_funcsnum) + { + pPlugin->m_priv_funcs = new CFunction *[pPlugin->m_funcsnum]; + memset(pPlugin->m_priv_funcs, 0, sizeof(CFunction *) * pPlugin->m_funcsnum); + } else { + pPlugin->m_priv_funcs = NULL; + } + + if (pl->info.publics_num) + { + pPlugin->m_pub_funcs = new CFunction *[pl->info.publics_num]; + memset(pPlugin->m_pub_funcs, 0, sizeof(CFunction *) * pl->info.publics_num); + } else { + pPlugin->m_pub_funcs = NULL; + } + return pPlugin; } +IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) +{ + CFunction *pFunc = NULL; + funcid_t save = func_id; + + if (func_id & 1) + { + func_id >>= 1; + if (func_id >= m_plugin->info.publics_num) + { + return NULL; + } + pFunc = m_pub_funcs[func_id]; + if (!pFunc) + { + pFunc = g_PluginMngr.GetFunctionFromPool(save, this); + m_pub_funcs[func_id] = pFunc; + } + } else { + func_id >>= 1; + unsigned int index; + if (!g_pVM->FunctionLookup(m_ctx_current.ctx, func_id, &index)) + { + return NULL; + } + pFunc = m_priv_funcs[func_id]; + if (!pFunc) + { + pFunc = g_PluginMngr.GetFunctionFromPool(save, this); + m_priv_funcs[func_id] = pFunc; + } + } + + return pFunc; +} + +IPluginFunction *CPlugin::GetFunctionByName(const char *public_name) +{ + uint32_t index; + IPluginContext *base = m_ctx_current.base; + + if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE) + { + return NULL; + } + + CFunction *pFunc = m_pub_funcs[index]; + if (!pFunc) + { + sp_public_t *pub = NULL; + base->GetPublicByIndex(index, &pub); + if (pub) + { + pFunc = g_PluginMngr.GetFunctionFromPool(pub->funcid, this); + m_pub_funcs[index] = pFunc; + } + } + + return pFunc; +} + void CPlugin::UpdateInfo() { /* Now grab the info */ @@ -242,6 +350,26 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pListener = (*iter); pListener->OnPluginDestroyed(pPlugin); } + + if (pPlugin->m_pub_funcs) + { + for (uint32_t i=0; im_plugin->info.publics_num; i++) + { + delete pPlugin->m_pub_funcs[i]; + } + delete [] pPlugin->m_pub_funcs; + pPlugin->m_pub_funcs = NULL; + } + + if (pPlugin->m_priv_funcs) + { + for (unsigned int i=0; im_funcsnum; i++) + { + delete pPlugin->m_priv_funcs[i]; + } + delete [] pPlugin->m_priv_funcs; + pPlugin->m_priv_funcs = NULL; + } if (pPlugin->m_ctx_current.base) { @@ -304,3 +432,26 @@ void CPluginManager::ReleaseIterator(CPluginIterator *iter) { m_iters.push(iter); } + +void CPluginManager::ReleaseFunctionToPool(CFunction *func) +{ + m_funcpool.push(func); +} + +CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin) +{ + if (m_funcpool.empty()) + { + return new CFunction(f, plugin); + } else { + CFunction *func = m_funcpool.front(); + m_funcpool.pop(); + func->Set(f, plugin); + return func; + } +} + +CPluginManager::~CPluginManager() +{ + //:TODO: we need a good way to free what we're holding +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 5705dcc3..25825e0e 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -19,9 +19,26 @@ struct ContextPair sp_context_t *ctx; }; +class CPlugin; + +class CFunction : public IPluginFunction +{ +public: + CFunction(funcid_t funcid, CPlugin *plugin); +public: + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); + virtual IPlugin *GetParentPlugin(); +public: + void Set(funcid_t funcid, CPlugin *plugin); +private: + funcid_t m_funcid; + CPlugin *m_pPlugin; +}; + class CPlugin : public IPlugin { friend class CPluginManager; + friend class CFunction; public: virtual PluginType GetType() const; virtual SourcePawn::IPluginContext *GetBaseContext() const; @@ -53,12 +70,17 @@ private: unsigned int m_serial; sm_plugininfo_t m_info; sp_plugin_t *m_plugin; + unsigned int m_funcsnum; + CFunction **m_priv_funcs; + CFunction **m_pub_funcs; }; class CPluginManager : public IPluginManager { + friend class CPlugin; public: CPluginManager(); + ~CPluginManager(); public: class CPluginIterator : public IPluginIterator { @@ -90,10 +112,13 @@ public: virtual void RemovePluginsListener(IPluginsListener *listener); protected: void ReleaseIterator(CPluginIterator *iter); + CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); + void ReleaseFunctionToPool(CFunction *func); private: List m_listeners; List m_plugins; CStack m_iters; + CStack m_funcpool; }; extern CPluginManager g_PluginMngr;