diff --git a/core/sm_autonatives.cpp b/core/sm_autonatives.cpp
index 09fd2881..21522e22 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 c3b0d22b..7545442a 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 5327cb8d..fb903052 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 76f865f3..5e1fd71b 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 4aea3619..8cf5fbbd 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 03230ab7..14229452 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 ffa79e1d..2f6894a3 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 30b3bf6f..c6177c3c 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 a1aee68a..ff0bca9d 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 213a4e2f..391a9c7c 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 b26b9ea2..ffba6b56 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 8c73ab46..e097f6f2 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 8c780c43..ee9db35a 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 165fbcb4..4eb57fd6 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;
/**