diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 57376cf1..87c1240d 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -566,51 +566,54 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num) void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin) { - List::iterator iter; - CExtension *pExt; IPluginContext *pContext = pPlugin->GetBaseContext(); - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) + + List exts; + + uint32_t natives = pContext->GetNativesNum(); + sp_native_t *native; + sm_extnative_t *x_native; + for (uint32_t i=0; iIsLoaded()) + /* Make sure the native is valid */ + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE) { continue; } - if (!pExt->m_Natives.size()) + /* Make sure the native is not already bound */ + if (native->status == SP_NATIVE_BOUND) { continue; } - bool set = false; - List::iterator n_iter; - const sp_nativeinfo_t *natives; - for (n_iter = pExt->m_Natives.begin(); - n_iter != pExt->m_Natives.end(); - n_iter++) + /* See if we've got this native in our cache */ + if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL) { - natives = (*n_iter); - uint32_t idx; - unsigned int i=0; - while (natives[i].func != NULL && natives[i].name != NULL) - { - if (pContext->BindNative(&natives[i]) == SP_ERROR_NONE) - { - pContext->FindNativeByName(natives[i].name, &idx); - if (!(pContext->GetContext()->natives[idx].flags & SP_NTVFLAG_OPTIONAL)) - { - set = true; - } else { - WeakNative wkn = WeakNative((CPlugin *)pPlugin, idx); - pExt->m_WeakNatives.push_back(wkn); - } - } - i++; - } + continue; } - if (set && (pExt->m_Plugins.find(pPlugin) == pExt->m_Plugins.end())) + /* Try and bind it */ + if (pContext->BindNativeToIndex(i, x_native->info->func) != SP_ERROR_NONE) { - /* For now, mark this plugin as a requirement. Later we'll introduce native filtering. */ - pExt->m_Plugins.push_back(pPlugin); + 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); } } @@ -704,6 +707,26 @@ 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); + } + } + } + /* Tell it to unload */ pAPI = pExt->GetAPI(); pAPI->OnExtensionUnload(); @@ -743,6 +766,18 @@ void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *na 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::MarkAllLoaded() @@ -1028,3 +1063,11 @@ CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr) return NULL; } + +CExtensionManager::CExtensionManager() +{ +} + +CExtensionManager::~CExtensionManager() +{ +} diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index 395f68ef..4b3aed92 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "sm_globals.h" #include "ShareSys.h" #include @@ -46,6 +47,14 @@ using namespace SourceMod; using namespace SourceHook; +class CExtension; + +struct sm_extnative_t +{ + CExtension *owner; + const sp_nativeinfo_t *info; +}; + class CExtension : public IExtension { friend class CExtensionManager; @@ -95,6 +104,9 @@ class CExtensionManager : public IPluginsListener, public IRootConsoleCommand { +public: + CExtensionManager(); + ~CExtensionManager(); public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); @@ -127,6 +139,7 @@ private: CExtension *FindByOrder(unsigned int num); private: List m_Libs; + KTrie m_ExtNatives; }; extern CExtensionManager g_Extensions; diff --git a/public/IShareSys.h b/public/IShareSys.h index ec7baa61..4654e82e 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -118,12 +118,18 @@ namespace SourceMod SMInterface **pIface) =0; /** - * @brief Adds a list of natives to the global native pool, to be bound on plugin load. - * NOTE: Adding natives currently does not bind them to any loaded plugins. - * You must manually bind late natives. + * @brief Adds a list of natives to the global native pool, to be + * bound on plugin load. + * + * Adding natives does not bind them to any loaded plugins; the + * plugins must be reloaded for new natives to take effect. * * @param myself Identity token of parent object. - * @param natives Array of natives to add. The last entry must have NULL members. + * @param natives Array of natives to add. The last entry in + * the array must be filled with NULLs to + * terminate the array. The array must be static + * as Core will cache the pointer for the + * lifetime of the extension. */ virtual void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0;