added a quick experimental system for overriding core natives
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401695
This commit is contained in:
parent
dfa007081b
commit
a79a169384
@ -285,7 +285,22 @@ void CExtension::RemovePlugin(IPlugin *pPlugin)
|
|||||||
if ((*iter).pl == pPlugin)
|
if ((*iter).pl == pPlugin)
|
||||||
{
|
{
|
||||||
iter = m_WeakNatives.erase(iter);
|
iter = m_WeakNatives.erase(iter);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = m_ReplacedNatives.begin();
|
||||||
|
while (iter != m_ReplacedNatives.end())
|
||||||
|
{
|
||||||
|
if ((*iter).pl == pPlugin)
|
||||||
|
{
|
||||||
|
iter = m_ReplacedNatives.erase(iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -703,6 +718,7 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
|||||||
uint32_t natives = pContext->GetNativesNum();
|
uint32_t natives = pContext->GetNativesNum();
|
||||||
sp_native_t *native;
|
sp_native_t *native;
|
||||||
sm_extnative_t *x_native;
|
sm_extnative_t *x_native;
|
||||||
|
sm_repnative_t *r_native;
|
||||||
for (uint32_t i=0; i<natives; i++)
|
for (uint32_t i=0; i<natives; i++)
|
||||||
{
|
{
|
||||||
/* Make sure the native is valid */
|
/* Make sure the native is valid */
|
||||||
@ -710,11 +726,26 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the native is not already bound */
|
/* Make sure the native is not already bound */
|
||||||
if (native->status == SP_NATIVE_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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if we've got this native in our cache */
|
/* See if we've got this native in our cache */
|
||||||
if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL)
|
if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL)
|
||||||
{
|
{
|
||||||
@ -789,7 +820,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
|
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unbound weak natives */
|
/* Unbind weak natives */
|
||||||
List<WeakNative>::iterator wkn_iter;
|
List<WeakNative>::iterator wkn_iter;
|
||||||
for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++)
|
for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++)
|
||||||
{
|
{
|
||||||
@ -798,6 +829,21 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
|
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 */
|
/* Notify and/or unload all dependencies */
|
||||||
List<CExtension *>::iterator c_iter;
|
List<CExtension *>::iterator c_iter;
|
||||||
CExtension *pDep;
|
CExtension *pDep;
|
||||||
@ -871,6 +917,22 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Tell it to unload */
|
/* Tell it to unload */
|
||||||
pAPI = pExt->GetAPI();
|
pAPI = pExt->GetAPI();
|
||||||
pAPI->OnExtensionUnload();
|
pAPI->OnExtensionUnload();
|
||||||
@ -919,6 +981,25 @@ void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *na
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
void CExtensionManager::MarkAllLoaded()
|
||||||
{
|
{
|
||||||
List<CExtension *>::iterator iter;
|
List<CExtension *>::iterator iter;
|
||||||
|
@ -55,6 +55,14 @@ struct sm_extnative_t
|
|||||||
const sp_nativeinfo_t *info;
|
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
|
||||||
{
|
{
|
||||||
friend class CExtensionManager;
|
friend class CExtensionManager;
|
||||||
@ -98,6 +106,7 @@ protected:
|
|||||||
List<IPlugin *> m_Plugins;
|
List<IPlugin *> m_Plugins;
|
||||||
List<const sp_nativeinfo_t *> m_Natives;
|
List<const sp_nativeinfo_t *> m_Natives;
|
||||||
List<WeakNative> m_WeakNatives;
|
List<WeakNative> m_WeakNatives;
|
||||||
|
List<WeakNative> m_ReplacedNatives;
|
||||||
List<String> m_Libraries;
|
List<String> m_Libraries;
|
||||||
unsigned int unload_code;
|
unsigned int unload_code;
|
||||||
bool m_bFullyLoaded;
|
bool m_bFullyLoaded;
|
||||||
@ -168,6 +177,7 @@ public:
|
|||||||
void TryAutoload();
|
void TryAutoload();
|
||||||
void AddLibrary(IExtension *pSource, const char *library);
|
void AddLibrary(IExtension *pSource, const char *library);
|
||||||
bool LibraryExists(const char *library);
|
bool LibraryExists(const char *library);
|
||||||
|
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||||
public:
|
public:
|
||||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
@ -175,6 +185,8 @@ private:
|
|||||||
CExtension *FindByOrder(unsigned int num);
|
CExtension *FindByOrder(unsigned int num);
|
||||||
private:
|
private:
|
||||||
List<CExtension *> m_Libs;
|
List<CExtension *> m_Libs;
|
||||||
|
List<sm_repnative_t> m_RepNativeList;
|
||||||
|
KTrie<sm_repnative_t> m_RepNatives;
|
||||||
KTrie<sm_extnative_t> m_ExtNatives;
|
KTrie<sm_extnative_t> m_ExtNatives;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1440,6 +1440,18 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
|
||||||
{
|
{
|
||||||
assert(pPlugin->GetBaseContext() != NULL);
|
assert(pPlugin->GetBaseContext() != NULL);
|
||||||
|
@ -489,6 +489,7 @@ public:
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
|
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||||
|
SPVM_NATIVE_FUNC FindCoreNative(const char *name);
|
||||||
private:
|
private:
|
||||||
void AddFakeNativesToPlugin(CPlugin *pPlugin);
|
void AddFakeNativesToPlugin(CPlugin *pPlugin);
|
||||||
void TryRefreshDependencies(CPlugin *pOther);
|
void TryRefreshDependencies(CPlugin *pOther);
|
||||||
|
@ -243,3 +243,8 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
|
|||||||
{
|
{
|
||||||
g_Extensions.AddLibrary(myself, name);
|
g_Extensions.AddLibrary(myself, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||||
|
{
|
||||||
|
g_Extensions.OverrideNatives(myself, natives);
|
||||||
|
}
|
||||||
|
@ -81,6 +81,7 @@ public: //IShareSys
|
|||||||
void DestroyIdentity(IdentityToken_t *identity);
|
void DestroyIdentity(IdentityToken_t *identity);
|
||||||
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||||
void RegisterLibrary(IExtension *myself, const char *name);
|
void RegisterLibrary(IExtension *myself, const char *name);
|
||||||
|
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||||
public: //SMGlobalClass
|
public: //SMGlobalClass
|
||||||
/* Pre-empt in case anything tries to register idents early */
|
/* Pre-empt in case anything tries to register idents early */
|
||||||
void OnSourceModStartup(bool late);
|
void OnSourceModStartup(bool late);
|
||||||
|
@ -127,8 +127,11 @@ namespace SourceMod
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Version code of the IExtensionInterface API itself.
|
* @brief Version code of the IExtensionInterface API itself.
|
||||||
|
*
|
||||||
|
* Note: This is bumped when IShareSys is changed, because IShareSys
|
||||||
|
* itself is not versioned.
|
||||||
*/
|
*/
|
||||||
#define SMINTERFACE_EXTENSIONAPI_VERSION 2
|
#define SMINTERFACE_EXTENSIONAPI_VERSION 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The interface an extension must expose.
|
* @brief The interface an extension must expose.
|
||||||
|
@ -200,6 +200,29 @@ namespace SourceMod
|
|||||||
* @param name Library name.
|
* @param name Library name.
|
||||||
*/
|
*/
|
||||||
virtual void RegisterLibrary(IExtension *myself, const char *name) =0;
|
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.
|
||||||
|
*
|
||||||
|
* A Core version of each native must exist. If one does not, then
|
||||||
|
* Core will simply ignore that entry.
|
||||||
|
*
|
||||||
|
* Override natives represent a weak coupling. If the extension is
|
||||||
|
* unloaded, the native will be re-bound to the Core version.
|
||||||
|
*
|
||||||
|
* @param myself Identity token of parent object.
|
||||||
|
* @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 OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user