From c93d05f6228803d7b0ec94fd6b5da3f5feacc971 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 May 2008 07:51:11 +0000 Subject: [PATCH] rewrite of the native and dependency binding/interaction code. this will ease the transition for native overrides, and greatly simplifies most of the logic. all native binding code now takes place almost entirely in ShareSys, and PluginSys supplements this logic where appropriate. extensionsys has been cleaned up --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402198 --- core/sm_autonatives.cpp | 7 +- core/sm_autonatives.h | 4 + core/smn_database.cpp | 6 +- core/smn_fakenatives.cpp | 6 +- core/sourcemod.cpp | 9 +- core/systems/ExtensionSys.cpp | 233 ++----------------------- core/systems/ExtensionSys.h | 33 ++-- core/systems/PluginSys.cpp | 289 +++++++++----------------------- core/systems/PluginSys.h | 46 +---- core/systems/ShareSys.cpp | 271 +++++++++++++++++++++++++++++- core/systems/ShareSys.h | 41 +++++ public/IShareSys.h | 14 +- public/sourcepawn/sp_vm_api.h | 24 ++- public/sourcepawn/sp_vm_types.h | 1 + 14 files changed, 461 insertions(+), 523 deletions(-) diff --git a/core/sm_autonatives.cpp b/core/sm_autonatives.cpp index 09fd28810..21522e221 100644 --- a/core/sm_autonatives.cpp +++ b/core/sm_autonatives.cpp @@ -31,8 +31,13 @@ #include "sm_autonatives.h" #include "PluginSys.h" +#include "NativeOwner.h" + +CNativeOwner g_CoreNatives; + +CNativeOwner *g_pCoreNatives = &g_CoreNatives; void CoreNativesToAdd::OnSourceModAllInitialized() { - g_PluginSys.RegisterNativesFromCore(m_NativeList); + g_CoreNatives.AddNatives(m_NativeList); } diff --git a/core/sm_autonatives.h b/core/sm_autonatives.h index c3b0d22bc..7545442a3 100644 --- a/core/sm_autonatives.h +++ b/core/sm_autonatives.h @@ -50,4 +50,8 @@ public: sp_nativeinfo_t *m_NativeList; }; +class CNativeOwner; + +extern CNativeOwner *g_pCoreNatives; + #endif //_INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_ diff --git a/core/smn_database.cpp b/core/smn_database.cpp index 5327cb8d0..fb903052d 100644 --- a/core/smn_database.cpp +++ b/core/smn_database.cpp @@ -333,7 +333,7 @@ static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params) CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); if (pExt) { - g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext())); + g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext())); } return hndl; @@ -391,7 +391,7 @@ static cell_t SQL_TConnect(IPluginContext *pContext, const cell_t *params) CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); if (pExt) { - g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext())); + g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext())); } /* Finally, add to the thread if we can */ @@ -462,7 +462,7 @@ static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params) CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); if (pExt) { - g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext())); + g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext())); } return hndl; diff --git a/core/smn_fakenatives.cpp b/core/smn_fakenatives.cpp index 76f865f35..5e1fd71b5 100644 --- a/core/smn_fakenatives.cpp +++ b/core/smn_fakenatives.cpp @@ -113,6 +113,8 @@ cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pD static cell_t CreateNative(IPluginContext *pContext, const cell_t *params) { char *name; + CPlugin *pPlugin; + pContext->LocalToString(params[1], &name); IPluginFunction *pFunction = pContext->GetFunctionById(params[2]); @@ -121,7 +123,9 @@ static cell_t CreateNative(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Function %x is not a valid function", params[2]); } - if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter)) + pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + + if (!pPlugin->AddFakeNative(pFunction, name, FakeNativeRouter)) { return pContext->ThrowNativeError("Fatal error creating dynamic native!"); } diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 4aea36190..8cf5fbbdd 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -190,7 +190,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late } return false; } - } else { + } + else + { /* On version bumps, we should check for older versions as well, if the new version fails. * We can then check the exports to see if any VM versions will be sufficient. */ @@ -240,10 +242,11 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late continue; } /* Refuse any API that we might not be able to deal with. - * Also refuse anything < 3 because we need fake natives. + * Also refuse anything < 3 because we need fake natives. + * Also refuse anything < 7 because we need the new sp_native definition. */ api_version = g_pVM->GetAPIVersion(); - if (api_version < 3 || api_version > SOURCEPAWN_VM_API_VERSION) + if (api_version < 7 || api_version > SOURCEPAWN_VM_API_VERSION) { if (error && maxlength) { diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 03230ab77..142294528 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -266,43 +266,12 @@ void CExtension::MarkAllLoaded() } } -void CExtension::AddPlugin(IPlugin *pPlugin) +void CExtension::AddPlugin(CPlugin *pPlugin) { /* Unfortunately we have to do this :( */ - if (m_Plugins.find(pPlugin) != m_Plugins.end()) + if (m_Dependents.find(pPlugin) != m_Dependents.end()) { - m_Plugins.push_back(pPlugin); - } -} - -void CExtension::RemovePlugin(IPlugin *pPlugin) -{ - m_Plugins.remove(pPlugin); - - List::iterator iter = m_WeakNatives.begin(); - while (iter != m_WeakNatives.end()) - { - if ((*iter).pl == pPlugin) - { - iter = m_WeakNatives.erase(iter); - } - else - { - iter++; - } - } - - iter = m_ReplacedNatives.begin(); - while (iter != m_ReplacedNatives.end()) - { - if ((*iter).pl == pPlugin) - { - iter = m_ReplacedNatives.erase(iter); - } - else - { - iter++; - } + m_Dependents.push_back(pPlugin); } } @@ -671,7 +640,7 @@ void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface pExt->AddInterface(pInterface); } -void CExtensionManager::BindChildPlugin(IExtension *pParent, IPlugin *pPlugin) +void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin ) { CExtension *pExt = (CExtension *)pParent; @@ -684,7 +653,7 @@ void CExtensionManager::OnPluginDestroyed(IPlugin *plugin) for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) { - (*iter)->RemovePlugin(plugin); + (*iter)->DropRefsTo((CPlugin *)plugin); } } @@ -709,77 +678,6 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num) return NULL; } -void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin) -{ - IPluginContext *pContext = pPlugin->GetBaseContext(); - - List exts; - - uint32_t natives = pContext->GetNativesNum(); - sp_native_t *native; - sm_extnative_t *x_native; - sm_repnative_t *r_native; - for (uint32_t i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE) - { - continue; - } - - /* Make sure the native is not already bound */ - if (native->status == SP_NATIVE_BOUND) - { - /* If it is bound, see if there is a replacement. */ - if ((r_native = m_RepNatives.retrieve(native->name)) == NULL) - { - continue; - } - - /* Rewrite the address. Whee! */ - native->pfn = r_native->info.func; - - /* Make sure this will unload safely */ - WeakNative wn((CPlugin *)pPlugin, i); - r_native->owner->m_ReplacedNatives.push_back(wn); - - continue; - } - - /* See if we've got this native in our cache */ - if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL) - { - continue; - } - /* Try and bind it */ - if (pContext->BindNativeToIndex(i, x_native->info->func) != SP_ERROR_NONE) - { - continue; - } - /* See if it's optional */ - if (native->flags & SP_NTVFLAG_OPTIONAL) - { - WeakNative wkn = WeakNative((CPlugin *)pPlugin, i); - x_native->owner->m_WeakNatives.push_back(wkn); - } - else if (exts.find(x_native->owner) == exts.end()) - { - exts.push_back(x_native->owner); - } - } - - List::iterator iter; - for (iter = exts.begin(); iter != exts.end(); iter++) - { - CExtension *pExt = (*iter); - if (pExt->m_Plugins.find(pPlugin) != pExt->m_Plugins.end()) - { - continue; - } - pExt->m_Plugins.push_back(pPlugin); - } -} - bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) @@ -804,12 +702,12 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) if (pExt->IsLoaded()) { /* Unload any dependent plugins */ - List::iterator p_iter = pExt->m_Plugins.begin(); - while (p_iter != pExt->m_Plugins.end()) + List::iterator p_iter = pExt->m_Dependents.begin(); + while (p_iter != pExt->m_Dependents.end()) { /* We have to manually unlink ourselves here, since we're no longer being managed */ g_PluginSys.UnloadPlugin((*p_iter)); - p_iter = pExt->m_Plugins.erase(p_iter); + p_iter = pExt->m_Dependents.erase(p_iter); } List::iterator s_iter; @@ -820,30 +718,6 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true); } - /* Unbind weak natives */ - List::iterator wkn_iter; - for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++) - { - WeakNative & wkn = (*wkn_iter); - sp_context_t *ctx = wkn.pl->GetContext(); - ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND; - } - - /* Unbind replacement natives, link them back to their originals */ - for (wkn_iter = pExt->m_ReplacedNatives.begin(); - wkn_iter != pExt->m_ReplacedNatives.end(); - wkn_iter++) - { - WeakNative & wkn = (*wkn_iter); - sp_context_t *ctx = wkn.pl->GetContext(); - sm_repnative_t *r_native = m_RepNatives.retrieve(ctx->natives[wkn.idx].name); - if (r_native == NULL || ctx->natives[wkn.idx].pfn != r_native->info.func) - { - continue; - } - ctx->natives[wkn.idx].pfn = r_native->original; - } - /* Notify and/or unload all dependencies */ List::iterator c_iter; CExtension *pDep; @@ -898,40 +772,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) } /* Unbind our natives from Core */ - List::iterator native_iter; - for (native_iter = pExt->m_Natives.begin(); - native_iter != pExt->m_Natives.end(); - native_iter++) - { - const sp_nativeinfo_t *natives = (*native_iter); - sm_extnative_t *x_native; - for (unsigned int n = 0; - natives[n].name != NULL && natives[n].func != NULL; - n++) - { - x_native = m_ExtNatives.retrieve(natives[n].name); - if (x_native && x_native->owner == pExt) - { - m_ExtNatives.remove(natives[n].name); - } - } - } - - /* Unbind our replacement natives */ - List::iterator rep_iter = m_RepNativeList.begin(); - while (rep_iter != m_RepNativeList.end()) - { - sm_repnative_t & r_native = (*rep_iter); - if (r_native.owner == pExt) - { - m_RepNatives.remove(r_native.info.name); - rep_iter = m_RepNativeList.erase(rep_iter); - } - else - { - rep_iter++; - } - } + pExt->DropEverything(); /* Tell it to unload */ pAPI = pExt->GetAPI(); @@ -962,44 +803,6 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) return true; } -void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives) -{ - CExtension *pExt = (CExtension *)pOwner; - - pExt->m_Natives.push_back(natives); - - for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++) - { - if (m_ExtNatives.retrieve(natives[i].name) != NULL) - { - continue; - } - sm_extnative_t x_native; - x_native.info = &natives[i]; - x_native.owner = pExt; - m_ExtNatives.insert(natives[i].name, x_native); - } -} - -void CExtensionManager::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) -{ - SPVM_NATIVE_FUNC orig; - - for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++) - { - if ((orig = g_PluginSys.FindCoreNative(natives[i].name)) == NULL) - { - continue; - } - sm_repnative_t rep; - rep.info = natives[i]; - rep.owner = (CExtension *)myself; - rep.original = orig; - m_RepNativeList.push_back(rep); - m_RepNatives.insert(natives[i].name, rep); - } -} - void CExtensionManager::MarkAllLoaded() { List::iterator iter; @@ -1206,7 +1009,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand } if (!pExt->IsLoaded() - || (!pExt->m_ChildDeps.size() && !pExt->m_Plugins.size())) + || (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size())) { char filename[PLATFORM_MAX_PATH]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); @@ -1216,7 +1019,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand } else { - List plugins; + List plugins; if (pExt->m_ChildDeps.size()) { g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename()); @@ -1246,9 +1049,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand { g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename()); /* Add to plugin unload list */ - List::iterator p_iter; - for (p_iter=pOther->m_Plugins.begin(); - p_iter!=pOther->m_Plugins.end(); + List::iterator p_iter; + for (p_iter=pOther->m_Dependents.begin(); + p_iter!=pOther->m_Dependents.end(); p_iter++) { if (plugins.find((*p_iter)) == plugins.end()) @@ -1260,12 +1063,12 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand } } } - if (pExt->m_Plugins.size()) + if (pExt->m_Dependents.size()) { g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename()); - List::iterator iter; - IPlugin *pPlugin; - for (iter = pExt->m_Plugins.begin(); iter != pExt->m_Plugins.end(); iter++) + List::iterator iter; + CPlugin *pPlugin; + for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++) { pPlugin = (*iter); if (plugins.find(pPlugin) == plugins.end()) diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index ffa79e1dc..2f6894a30 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -43,6 +43,7 @@ #include #include #include "PluginSys.h" +#include "NativeOwner.h" using namespace SourceMod; using namespace SourceHook; @@ -55,15 +56,9 @@ struct sm_extnative_t const sp_nativeinfo_t *info; }; -/* Replacement native */ -struct sm_repnative_t -{ - CExtension *owner; - sp_nativeinfo_t info; - SPVM_NATIVE_FUNC original; -}; - -class CExtension : public IExtension +class CExtension : + public IExtension, + public CNativeOwner { friend class CExtensionManager; public: @@ -81,8 +76,7 @@ public: void AddDependency(IfaceInfo *pInfo); void AddChildDependent(CExtension *pOther, SMInterface *iface); void AddInterface(SMInterface *pInterface); - void AddPlugin(IPlugin *pPlugin); - void RemovePlugin(IPlugin *pPlugin); + void AddPlugin(CPlugin *pPlugin); void MarkAllLoaded(); void AddLibrary(const char *library); public: @@ -103,10 +97,6 @@ protected: List m_Deps; /** Dependencies */ List m_ChildDeps; /** Children who might depend on us */ List m_Interfaces; - List m_Plugins; - List m_Natives; - List m_WeakNatives; - List m_ReplacedNatives; List m_Libraries; unsigned int unload_code; bool m_bFullyLoaded; @@ -169,26 +159,25 @@ public: IExtension *LoadAutoExtension(const char *path); void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); void AddInterface(IExtension *pOwner, SMInterface *pInterface); - void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin); - void AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives); - void BindAllNativesToPlugin(IPlugin *pPlugin); + void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin); void MarkAllLoaded(); void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload); void TryAutoload(); void AddLibrary(IExtension *pSource, const char *library); bool LibraryExists(const char *library); - void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives); void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax); public: CExtension *GetExtensionFromIdent(IdentityToken_t *ptr); void Shutdown(); + CNativeOwner *GetNativeOwner(IExtension *pExt) + { + CExtension *p = (CExtension *)pExt; + return p; + } private: CExtension *FindByOrder(unsigned int num); private: List m_Libs; - List m_RepNativeList; - KTrie m_RepNatives; - KTrie m_ExtNatives; }; extern CExtensionManager g_Extensions; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 30b3bf6f9..c6177c3c1 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -134,10 +134,6 @@ unsigned int CPlugin::CalcMemUsage() unsigned int base_size = sizeof(CPlugin) + sizeof(IdentityToken_t) - + (m_dependents.size() * sizeof(CPlugin *)) - + (m_dependsOn.size() * sizeof(CPlugin *)) - + (m_fakeNatives.size() * (sizeof(FakeNative *) + sizeof(FakeNative))) - + (m_WeakNatives.size() * sizeof(WeakNative)) + (m_configs.size() * (sizeof(AutoConfig *) + sizeof(AutoConfig))) + sm_trie_mem_usage(m_pProps); @@ -161,13 +157,6 @@ unsigned int CPlugin::CalcMemUsage() base_size += (*i).size(); } - for (List::iterator i = m_fakeNatives.begin(); - i != m_fakeNatives.end(); - i++) - { - base_size += (*i)->name.size(); - } - if (m_plugin != NULL) { base_size += sizeof(sp_plugin_t); @@ -740,19 +729,19 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) } } - List::iterator iter; - FakeNative *pNative; + List::iterator iter; + NativeEntry *pNative; sp_native_t *native; uint32_t idx; unsigned int unbound = 0; - for (iter = pOwner->m_fakeNatives.begin(); - iter != pOwner->m_fakeNatives.end(); + for (iter = pOwner->m_Natives.begin(); + iter != pOwner->m_Natives.end(); iter++) { pNative = (*iter); /* Find this native! */ - if (m_ctx.base->FindNativeByName(pNative->name.c_str(), &idx) != SP_ERROR_NONE) + if (m_ctx.base->FindNativeByName(pNative->name, &idx) != SP_ERROR_NONE) { continue; } @@ -773,8 +762,6 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) { SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename()); } - - m_dependsOn.remove(pOwner); } unsigned int CPlugin::GetConfigCount() @@ -814,6 +801,56 @@ void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder) m_configs.push_back(c); } +void CPlugin::DropEverything() +{ + CPlugin *pOther; + List::iterator iter; + List::iterator wk_iter; + + /* Tell everyone that depends on us that we're about to drop */ + for (iter = m_Dependents.begin(); + iter != m_Dependents.end(); + iter++) + { + pOther = (*iter); + pOther->DependencyDropped(this); + } + + /* Note: we don't care about things we depend on. + * The reason is that extensions have their own cleanup + * code for plugins. Although the "right" design would be + * to centralize that here, i'm omitting it for now. Thus, + * the code below to walk the plugins list will suffice. + */ + + /* Other plugins could be holding weak references that were + * added by us. We need to clean all of those up now. + */ + for (iter = g_PluginSys.m_plugins.begin(); + iter != g_PluginSys.m_plugins.end(); + iter++) + { + (*iter)->DropRefsTo(this); + } + + /* Proceed with the rest of the necessities. */ + CNativeOwner::DropEverything(); +} + +bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func) +{ + NativeEntry *pEntry; + + if ((pEntry = g_ShareSys.AddFakeNative(pFunc, name, func)) == NULL) + { + return false; + } + + m_Natives.push_back(pEntry); + + return true; +} + /******************* * PLUGIN ITERATOR * *******************/ @@ -862,8 +899,6 @@ CPluginManager::CPluginManager() m_LoadLookup = sm_trie_create(); m_AllPluginsLoaded = false; m_MyIdent = NULL; - m_pNativeLookup = sm_trie_create(); - m_pCoreNatives = sm_trie_create(); m_LoadingLocked = false; } @@ -875,8 +910,6 @@ CPluginManager::~CPluginManager() * will crash anyway. YAY */ sm_trie_destroy(m_LoadLookup); - sm_trie_destroy(m_pNativeLookup); - sm_trie_destroy(m_pCoreNatives); CStack::iterator iter; for (iter=m_iters.begin(); iter!=m_iters.end(); iter++) @@ -1083,7 +1116,8 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de /* Get the status */ if (pPlugin->GetStatus() == Plugin_Created) { - AddCoreNativesToPlugin(pPlugin); + /* First native pass - add anything from Core */ + g_ShareSys.BindNativesToPlugin(pPlugin, true); pPlugin->InitIdentity(); if (pPlugin->Call_AskPluginLoad(error, maxlength)) { @@ -1409,19 +1443,15 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng return false; } - /* Bind all extra natives */ - g_Extensions.BindAllNativesToPlugin(pPlugin); - if (!FindOrRequirePluginDeps(pPlugin, error, maxlength)) { return false; } - AddFakeNativesToPlugin(pPlugin); + /* Run another binding pass */ + g_ShareSys.BindNativesToPlugin(pPlugin, false); - /* Find any unbound natives - * Right now, these are not allowed - */ + /* Find any unbound natives. Right now, these are not allowed. */ IPluginContext *pContext = pPlugin->GetBaseContext(); uint32_t num = pContext->GetNativesNum(); sp_native_t *native; @@ -1456,7 +1486,7 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng pPlugin->Call_OnPluginStart(); /* Now, if we have fake natives, go through all plugins that might need rebinding */ - if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_fakeNatives.size()) + if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_Natives.size()) { List::iterator pl_iter; CPlugin *pOther; @@ -1471,6 +1501,18 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng { TryRefreshDependencies(pOther); } + else if ((pOther->GetStatus() == Plugin_Running + || pOther->GetStatus() == Plugin_Paused) + && pOther != pPlugin) + { + List::iterator nv_iter; + for (nv_iter = pPlugin->m_Natives.begin(); + nv_iter != pPlugin->m_Natives.end(); + nv_iter++) + { + g_ShareSys.BindNativeToPlugin(pOther, (*nv_iter)); + } + } } } @@ -1489,49 +1531,11 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng return true; } -void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) -{ - IPluginContext *pContext = pPlugin->GetBaseContext(); - - - uint32_t natives = pContext->GetNativesNum(); - sp_native_t *native; - SPVM_NATIVE_FUNC pfn; - for (uint32_t i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE) - { - continue; - } - if (native->status == SP_NATIVE_BOUND) - { - continue; - } - if (!sm_trie_retrieve(m_pCoreNatives, native->name, (void **)&pfn)) - { - continue; - } - pContext->BindNativeToIndex(i, pfn); - } -} - -SPVM_NATIVE_FUNC CPluginManager::FindCoreNative(const char *name) -{ - SPVM_NATIVE_FUNC pfn; - - if (!sm_trie_retrieve(m_pCoreNatives, name, (void **)&pfn)) - { - return NULL; - } - - return pfn; -} - void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin) { assert(pPlugin->GetBaseContext() != NULL); - AddFakeNativesToPlugin(pPlugin); + g_ShareSys.BindNativesToPlugin(pPlugin, false); List::iterator lib_iter; List::iterator req_iter; @@ -1589,52 +1593,6 @@ void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin) } } -void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin) -{ - IPluginContext *pContext = pPlugin->GetBaseContext(); - sp_nativeinfo_t native; - - List::iterator iter; - FakeNative *pNative; - sp_context_t *ctx; - for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++) - { - pNative = (*iter); - ctx = pNative->ctx->GetContext(); - if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) - { - /* Ignore natives in paused plugins */ - continue; - } - native.name = pNative->name.c_str(); - native.func = pNative->func; - if (pContext->BindNative(&native) == SP_ERROR_NONE) - { - uint32_t idx; - pContext->FindNativeByName(native.name, &idx); - if (pPlugin->GetContext()->natives[idx].flags & SP_NTVFLAG_OPTIONAL) - { - WeakNative wkn(pPlugin, idx); - GetPluginByCtx(ctx)->m_WeakNatives.push_back(wkn); - continue; - } - /* Add us as a dependency, but we're careful not to do this circularly! */ - if (pNative->ctx != pContext) - { - CPlugin *pOther = GetPluginByCtx(ctx); - if (pOther->m_dependents.find(pPlugin) == pOther->m_dependents.end()) - { - pOther->m_dependents.push_back(pPlugin); - } - if (pPlugin->m_dependsOn.find(pOther) == pPlugin->m_dependsOn.end()) - { - pPlugin->m_dependsOn.push_back(pOther); - } - } - } - } -} - bool CPluginManager::UnloadPlugin(IPlugin *plugin) { CPlugin *pPlugin = (CPlugin *)plugin; @@ -1667,44 +1625,6 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) OnLibraryAction((*s_iter).c_str(), true, true); } - /* Go through all dependent plugins and tell them this plugin is now gone */ - List::iterator pl_iter; - CPlugin *pOther; - for (pl_iter = pPlugin->m_dependents.begin(); - pl_iter != pPlugin->m_dependents.end(); - pl_iter++) - { - pOther = (*pl_iter); - pOther->DependencyDropped(pPlugin); - } - - /* Tell everyone we depend on that we no longer exist */ - for (pl_iter = pPlugin->m_dependsOn.begin(); - pl_iter != pPlugin->m_dependsOn.end(); - pl_iter++) - { - pOther = (*pl_iter); - pOther->m_dependents.remove(pPlugin); - } - - /* Remove weak references to us */ - for (pl_iter = m_plugins.begin(); - pl_iter != m_plugins.end(); - pl_iter++) - { - pOther = (*pl_iter); - List::iterator wk_iter = pOther->m_WeakNatives.begin(); - while (wk_iter != pOther->m_WeakNatives.end()) - { - if ((*wk_iter).pl == pPlugin) - { - wk_iter = pOther->m_WeakNatives.erase(wk_iter); - } else { - wk_iter++; - } - } - } - List::iterator iter; IPluginsListener *pListener; @@ -1720,29 +1640,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pPlugin->Call_OnPluginEnd(); } - /* Unbound weak natives */ - List::iterator wk_iter; - for (wk_iter=pPlugin->m_WeakNatives.begin(); wk_iter!=pPlugin->m_WeakNatives.end(); wk_iter++) - { - WeakNative & wkn = (*wk_iter); - sp_context_t *ctx = wkn.pl->GetContext(); - ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND; - wkn.pl->m_FakeNativesMissing = true; - } - - /* Remove all of our native functions */ - List::iterator fn_iter; - FakeNative *pNative; - for (fn_iter = pPlugin->m_fakeNatives.begin(); - fn_iter != pPlugin->m_fakeNatives.end(); - fn_iter++) - { - pNative = (*fn_iter); - m_Natives.remove(pNative); - sm_trie_delete(m_pNativeLookup, pNative->name.c_str()); - g_pVM->DestroyFakeNative(pNative->func); - delete pNative; - } + pPlugin->DropEverything(); for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) { @@ -2050,14 +1948,6 @@ bool CPluginManager::GetHandleApproxSize(HandleType_t type, void *object, unsign return true; } -void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives) -{ - for (unsigned int i = 0; natives[i].func != NULL; i++) - { - sm_trie_insert(m_pCoreNatives, natives[i].name, (void *)natives[i].func); - } -} - IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err) { IPlugin *pPlugin; @@ -2657,35 +2547,6 @@ void CPluginManager::_SetPauseState(CPlugin *pl, bool paused) } } -bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func) -{ - if (sm_trie_retrieve(m_pNativeLookup, name, NULL)) - { - return false; - } - - FakeNative *pNative = new FakeNative; - - pNative->func = g_pVM->CreateFakeNative(func, pNative); - if (!pNative->func) - { - delete pNative; - return false; - } - - pNative->call = pFunction; - pNative->name.assign(name); - pNative->ctx = pFunction->GetParentContext(); - - m_Natives.push_back(pNative); - sm_trie_insert(m_pNativeLookup, name,pNative); - - CPlugin *pPlugin = GetPluginByCtx(pNative->ctx->GetContext()); - pPlugin->m_fakeNatives.push_back(pNative); - - return true; -} - void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward) { List::iterator iter; diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index a1aee68a1..ff0bca9d1 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -54,6 +54,8 @@ #include "convar_sm.h" #endif #include "ITranslator.h" +#include "NativeOwner.h" +#include "ShareSys.h" using namespace SourceHook; @@ -120,14 +122,6 @@ struct ContextPair IVirtualMachine *vm; }; -struct FakeNative -{ - IPluginContext *ctx; - IPluginFunction *call; - String name; - SPVM_NATIVE_FUNC func; -}; - enum LoadRes { LoadRes_Successful, @@ -144,18 +138,10 @@ struct AutoConfig }; class CPlugin; -struct WeakNative -{ - WeakNative(CPlugin *plugin, uint32_t index) - { - pl = plugin; - idx = index; - } - CPlugin *pl; - uint32_t idx; -}; -class CPlugin : public IPlugin +class CPlugin : + public IPlugin, + public CNativeOwner { friend class CPluginManager; friend class CFunction; @@ -177,6 +163,7 @@ public: unsigned int CalcMemUsage(); bool SetProperty(const char *prop, void *ptr); bool GetProperty(const char *prop, void **ptr, bool remove=false); + void DropEverything(); public: /** * Creates a plugin object with default values. @@ -266,6 +253,7 @@ public: Handle_t GetMyHandle(); + bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func); void AddConfig(bool autoCreate, const char *cfg, const char *folder); unsigned int GetConfigCount(); AutoConfig *GetConfig(unsigned int i); @@ -292,10 +280,6 @@ private: Handle_t m_handle; bool m_WasRunning; IPhraseCollection *m_pPhrases; - List m_dependents; - List m_dependsOn; - List m_fakeNatives; - List m_WeakNatives; List m_RequiredLibs; List m_Libraries; Trie *m_pProps; @@ -381,11 +365,6 @@ public: */ bool IsLateLoadTime() const; - /** - * Adds natives from core into the native pool. - */ - void RegisterNativesFromCore(sp_nativeinfo_t *natives); - /** * Converts a Handle to an IPlugin if possible. */ @@ -460,11 +439,6 @@ private: */ bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength); - /** - * Adds any globally registered natives to a plugin - */ - void AddCoreNativesToPlugin(CPlugin *pPlugin); - /** * Runs an extension pass on a plugin. */ @@ -486,11 +460,7 @@ public: { return m_MyIdent; } -public: - bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func); - SPVM_NATIVE_FUNC FindCoreNative(const char *name); private: - void AddFakeNativesToPlugin(CPlugin *pPlugin); void TryRefreshDependencies(CPlugin *pOther); private: List m_listeners; @@ -500,11 +470,9 @@ private: Trie *m_LoadLookup; bool m_AllPluginsLoaded; IdentityToken_t *m_MyIdent; - Trie *m_pCoreNatives; /* Dynamic native stuff */ List m_Natives; - Trie *m_pNativeLookup; bool m_LoadingLocked; }; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 213a4e2f5..391a9c7ce 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -33,8 +33,11 @@ #include "HandleSys.h" #include "ExtensionSys.h" #include "LibrarySys.h" +#include "PluginSys.h" +#include "sm_stringutil.h" ShareSystem g_ShareSys; +static unsigned int g_mark_serial = 0; ShareSystem::ShareSystem() { @@ -200,7 +203,11 @@ bool ShareSystem::RequestInterface(const char *iface_name, void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) { - g_Extensions.AddNatives(myself, natives); + CNativeOwner *pOwner; + + pOwner = g_Extensions.GetNativeOwner(myself); + + pOwner->AddNatives(natives); } void ShareSystem::DestroyIdentity(IdentityToken_t *identity) @@ -228,7 +235,9 @@ void ShareSystem::RemoveInterfaces(IExtension *pExtension) if ((*iter).owner == pExtension) { iter = m_Interfaces.erase(iter); - } else { + } + else + { iter++; } } @@ -246,5 +255,261 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *name) void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) { - g_Extensions.OverrideNatives(myself, natives); + unsigned int i; + NativeEntry *pEntry; + CNativeOwner *pOwner; + + pOwner = g_Extensions.GetNativeOwner(myself); + + for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++) + { + if ((pEntry = FindNative(natives[i].name)) == NULL) + { + continue; + } + + if (pEntry->owner != g_pCoreNatives) + { + continue; + } + + if (pEntry->replacement.owner != NULL) + { + continue; + } + + /* Now it's safe to add the override */ + pEntry->replacement.func = natives[i].func; + pEntry->replacement.owner = pOwner; + pOwner->AddReplacedNative(pEntry); + } +} + +NativeEntry *ShareSystem::FindNative(const char *name) +{ + NativeEntry **ppEntry; + + if ((ppEntry = m_NtvCache.retrieve(name)) == NULL) + { + return NULL; + } + + return *ppEntry; +} + +void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly) +{ + NativeEntry *pEntry; + sp_native_t *native; + uint32_t i, native_count; + IPluginContext *pContext; + + pContext = pPlugin->GetBaseContext(); + + /* Generate a new serial ID, mark our dependencies with it. */ + g_mark_serial++; + pPlugin->PropogateMarkSerial(g_mark_serial); + + native_count = pContext->GetNativesNum(); + for (i = 0; i < native_count; i++) + { + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE) + { + continue; + } + + /* If we're bound, check if there is a replacement available. + * If not, this native is totally finalized. + */ + if (native->status == SP_NATIVE_BOUND) + { + pEntry = (NativeEntry *)native->user; + assert(pEntry != NULL); + if (pEntry->replacement.owner == NULL + || (pEntry->replacement.owner != NULL + && pEntry->replacement.func == native->pfn)) + { + continue; + } + } + /* Otherwise, the native must be in our cache. */ + else if ((pEntry = FindNative(native->name)) == NULL) + { + continue; + } + + if (bCoreOnly && pEntry->owner != g_pCoreNatives) + { + continue; + } + + BindNativeToPlugin(pPlugin, native, i, pEntry); + } +} + +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry) +{ + uint32_t i; + sp_native_t *native; + IPluginContext *pContext; + + pContext = pPlugin->GetBaseContext(); + + if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE) + { + return; + } + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE) + { + return; + } + + if (native->status == SP_NATIVE_BOUND) + { + return; + } + + BindNativeToPlugin(pPlugin, native, i, pEntry); +} + +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, + sp_native_t *native, + uint32_t index, + NativeEntry *pEntry) +{ + /* Mark as bound... we do the rest next. */ + native->status = SP_NATIVE_BOUND; + native->user = pEntry; + + /* See if a replacement is available. */ + if (pEntry->replacement.owner != NULL) + { + /* Perform a replacement bind. */ + native->pfn = pEntry->replacement.func; + pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry)); + } + else + { + /* Perform a normal bind. */ + native->pfn = pEntry->func; + + /* We don't bother with dependency crap if the owner is Core. */ + if (pEntry->owner != g_pCoreNatives) + { + /* The native is optional, this is a special case */ + if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL) + { + pEntry->owner->AddWeakRef(WeakNative(pPlugin, index)); + } + /* Otherwise, we're a strong dependent and not a weak one */ + else + { + /* See if this has already been marked as a dependent. + * If it has, it means this relationship has already occurred, + * and there is no reason to do it again. + */ + if (pEntry->owner != pPlugin + && pEntry->owner->GetMarkSerial() != g_mark_serial) + { + /* This has not been marked as a dependency yet */ + //pPlugin->AddDependency(pEntry->owner); + pEntry->owner->AddDependent(pPlugin); + pEntry->owner->SetMarkSerial(g_mark_serial); + } + } + } + } +} + +NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv) +{ + NativeEntry *pEntry; + + if ((pEntry = FindNative(ntv->name)) == NULL) + { + pEntry = new NativeEntry; + + pEntry->owner = pOwner; + pEntry->name = ntv->name; + pEntry->func = ntv->func; + pEntry->replacement.func = NULL; + pEntry->replacement.owner = NULL; + pEntry->fake = NULL; + + m_NtvCache.insert(ntv->name, pEntry); + + return pEntry; + } + + if (pEntry->owner != NULL) + { + return NULL; + } + + pEntry->owner = pOwner; + pEntry->func = ntv->func; + pEntry->name = ntv->name; + pEntry->func = NULL; + + return pEntry; +} + +void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name) +{ + NativeEntry *pEntry; + + if ((pEntry = FindNative(name)) == NULL) + { + return; + } + + if (pEntry->owner != pOwner) + { + return; + } + + pEntry->func = NULL; + pEntry->name = NULL; + pEntry->owner = NULL; + pEntry->replacement.func = NULL; + pEntry->replacement.owner = NULL; +} + +NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func) +{ + FakeNative *pFake; + NativeEntry *pEntry; + SPVM_NATIVE_FUNC gate; + + if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL) + { + return NULL; + } + + pFake = new FakeNative; + + if ((gate = g_pVM->CreateFakeNative(func, pFake)) == NULL) + { + delete pFake; + return NULL; + } + + if (pEntry == NULL) + { + pEntry = new NativeEntry; + m_NtvCache.insert(name, pEntry); + } + + pFake->call = pFunc; + pFake->ctx = pFunc->GetParentContext(); + strncopy(pFake->name, name, sizeof(pFake->name)); + + pEntry->fake = pFake; + pEntry->func = gate; + pEntry->name = pFake->name; + pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext()); + pEntry->replacement.func = NULL; + pEntry->replacement.owner = NULL; + + return pEntry; } diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index b26b9ea28..ffba6b568 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "sm_globals.h" #include "sourcemod.h" @@ -60,11 +61,38 @@ struct IfaceInfo IExtension *owner; }; +class CNativeOwner; +class CPlugin; +struct NativeEntry; + +struct ReplaceNative +{ + CNativeOwner *owner; + SPVM_NATIVE_FUNC func; +}; + +struct FakeNative +{ + char name[64]; + IPluginContext *ctx; + IPluginFunction *call; +}; + +struct NativeEntry +{ + CNativeOwner *owner; + SPVM_NATIVE_FUNC func; + const char *name; + ReplaceNative replacement; + FakeNative *fake; +}; + class ShareSystem : public IShareSys, public SMGlobalClass, public IHandleTypeDispatch { + friend class CNativeOwner; public: ShareSystem(); public: //IShareSys @@ -96,12 +124,25 @@ public: { return &m_IdentRoot; } +public: + void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly); + void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry); + NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func); +private: + NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv); + void ClearNativeFromCache(CNativeOwner *pOwner, const char *name); + NativeEntry *FindNative(const char *name); + void BindNativeToPlugin(CPlugin *pPlugin, + sp_native_t *ntv, + uint32_t index, + NativeEntry *pEntry); private: List m_Interfaces; HandleType_t m_TypeRoot; IdentityToken_t m_IdentRoot; HandleType_t m_IfaceType; IdentityType_t m_CoreType; + KTrie m_NtvCache; }; extern ShareSystem g_ShareSys; diff --git a/public/IShareSys.h b/public/IShareSys.h index 8c73ab46f..e097f6f25 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -202,18 +202,16 @@ namespace SourceMod virtual void RegisterLibrary(IExtension *myself, const char *name) =0; /** - * @brief Adds a list of natives to the global native pool, to be - * bound on plugin load. - * - * Unlike AddNatives(), this function implements natives that are - * ALWAYS bound, regardless of whether a previous function is bound. - * That means extensions can override Core natives. + * @brief Adds natives that will override Core natives when called. * * A Core version of each native must exist. If one does not, then - * Core will simply ignore that entry. + * Core will simply ignore that entry. No more than one override + * can exist on a given native. * * Override natives represent a weak coupling. If the extension is - * unloaded, the native will be re-bound to the Core version. + * unloaded, the native will be re-bound to the Core version. If + * the extension is loaded after plugins are loaded, the override + * will not take effect until those plugins are reloaded. * * @param myself Identity token of parent object. * @param natives Array of natives to add. The last entry in diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 8c780c433..ee9db35a3 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -44,7 +44,7 @@ #define SOURCEPAWN_ENGINE_API_VERSION 3 /** SourcePawn VM API Version */ -#define SOURCEPAWN_VM_API_VERSION 6 +#define SOURCEPAWN_VM_API_VERSION 7 #if !defined SOURCEMOD_BUILD #define SOURCEMOD_BUILD @@ -500,22 +500,18 @@ namespace SourcePawn virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; /** - * @brief Binds a list of native names and their function pointers to a context. - * If num is 0, the list is read until an entry with a NULL name is reached. - * If overwrite is non-zero, already registered natives will be overwritten. + * @brief Deprecated; do not use. * - * @param natives Array of natives. - * @param num Number of natives in array. - * @param overwrite Toggles overwrite. + * @param natives Deprecated; do not use. + * @param num Deprecated; do not use. + * @param overwrite Deprecated; do not use. */ virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; /** - * @brief Binds a single native. Overwrites any existing bind. - * If the context does not contain the native that will be binded the function will return - * with a SP_ERROR_NOT_FOUND error. + * @brief Deprecated; do not use. * - * @param native Pointer to native. + * @param native Deprecated; do not use. */ virtual int BindNative(const sp_nativeinfo_t *native) =0; @@ -599,10 +595,10 @@ namespace SourcePawn #endif /** - * @brief Binds a single native to a given native index. + * @brief Deprecated; do not use. * - * @param index Index to bind at. - * @param native Native function to bind. + * @param index Deprecated; do not use. + * @param native Deprecated; do not use. */ virtual int BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC native) =0; diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 165fbcb43..4eb57fd69 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -203,6 +203,7 @@ typedef struct sp_native_s const char * name; /**< Name of function */ uint32_t status; /**< Status flags */ uint32_t flags; /**< Native flags */ + void * user; /**< Host-specific data */ } sp_native_t; /**