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
This commit is contained in:
parent
c824afc61e
commit
c93d05f622
@ -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);
|
||||
}
|
||||
|
@ -50,4 +50,8 @@ public:
|
||||
sp_nativeinfo_t *m_NativeList;
|
||||
};
|
||||
|
||||
class CNativeOwner;
|
||||
|
||||
extern CNativeOwner *g_pCoreNatives;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_
|
||||
|
@ -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;
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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.
|
||||
* <s>Also refuse anything < 3 because we need fake natives.</s>
|
||||
* 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)
|
||||
{
|
||||
|
@ -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<WeakNative>::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<CExtension *> 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; i<natives; i++)
|
||||
{
|
||||
/* Make sure the native is valid */
|
||||
if (pContext->GetNativeByIndex(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<CExtension *>::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<IPlugin *>::iterator p_iter = pExt->m_Plugins.begin();
|
||||
while (p_iter != pExt->m_Plugins.end())
|
||||
List<CPlugin *>::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<String>::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<WeakNative>::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<CExtension *>::iterator c_iter;
|
||||
CExtension *pDep;
|
||||
@ -898,40 +772,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
}
|
||||
|
||||
/* Unbind our natives from Core */
|
||||
List<const sp_nativeinfo_t *>::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<sm_repnative_t>::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<CExtension *>::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<IPlugin *> plugins;
|
||||
List<CPlugin *> 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<IPlugin *>::iterator p_iter;
|
||||
for (p_iter=pOther->m_Plugins.begin();
|
||||
p_iter!=pOther->m_Plugins.end();
|
||||
List<CPlugin *>::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<IPlugin *>::iterator iter;
|
||||
IPlugin *pPlugin;
|
||||
for (iter = pExt->m_Plugins.begin(); iter != pExt->m_Plugins.end(); iter++)
|
||||
List<CPlugin *>::iterator iter;
|
||||
CPlugin *pPlugin;
|
||||
for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
|
||||
{
|
||||
pPlugin = (*iter);
|
||||
if (plugins.find(pPlugin) == plugins.end())
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <IPluginSys.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#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<IfaceInfo> m_Deps; /** Dependencies */
|
||||
List<IfaceInfo> m_ChildDeps; /** Children who might depend on us */
|
||||
List<SMInterface *> m_Interfaces;
|
||||
List<IPlugin *> m_Plugins;
|
||||
List<const sp_nativeinfo_t *> m_Natives;
|
||||
List<WeakNative> m_WeakNatives;
|
||||
List<WeakNative> m_ReplacedNatives;
|
||||
List<String> 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<CExtension *> m_Libs;
|
||||
List<sm_repnative_t> m_RepNativeList;
|
||||
KTrie<sm_repnative_t> m_RepNatives;
|
||||
KTrie<sm_extnative_t> m_ExtNatives;
|
||||
};
|
||||
|
||||
extern CExtensionManager g_Extensions;
|
||||
|
@ -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<FakeNative *>::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<FakeNative *>::iterator iter;
|
||||
FakeNative *pNative;
|
||||
List<NativeEntry *>::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<CPlugin *>::iterator iter;
|
||||
List<WeakNative>::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<CPluginManager::CPluginIterator *>::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<CPlugin *>::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<NativeEntry *>::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; i<natives; i++)
|
||||
{
|
||||
if (pContext->GetNativeByIndex(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<String>::iterator lib_iter;
|
||||
List<String>::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<FakeNative *>::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<CPlugin *>::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<WeakNative>::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<IPluginsListener *>::iterator iter;
|
||||
IPluginsListener *pListener;
|
||||
|
||||
@ -1720,29 +1640,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
||||
pPlugin->Call_OnPluginEnd();
|
||||
}
|
||||
|
||||
/* Unbound weak natives */
|
||||
List<WeakNative>::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<FakeNative *>::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<CPlugin *>::iterator iter;
|
||||
|
@ -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<CPlugin *> m_dependents;
|
||||
List<CPlugin *> m_dependsOn;
|
||||
List<FakeNative *> m_fakeNatives;
|
||||
List<WeakNative> m_WeakNatives;
|
||||
List<String> m_RequiredLibs;
|
||||
List<String> 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<IPluginsListener *> m_listeners;
|
||||
@ -500,11 +470,9 @@ private:
|
||||
Trie *m_LoadLookup;
|
||||
bool m_AllPluginsLoaded;
|
||||
IdentityToken_t *m_MyIdent;
|
||||
Trie *m_pCoreNatives;
|
||||
|
||||
/* Dynamic native stuff */
|
||||
List<FakeNative *> m_Natives;
|
||||
Trie *m_pNativeLookup;
|
||||
|
||||
bool m_LoadingLocked;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <IShareSys.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <sh_list.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#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<IfaceInfo> m_Interfaces;
|
||||
HandleType_t m_TypeRoot;
|
||||
IdentityToken_t m_IdentRoot;
|
||||
HandleType_t m_IfaceType;
|
||||
IdentityType_t m_CoreType;
|
||||
KTrie<NativeEntry *> m_NtvCache;
|
||||
};
|
||||
|
||||
extern ShareSystem g_ShareSys;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user