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)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
}
|
||||
@ -703,6 +718,7 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
||||
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 */
|
||||
@ -710,11 +726,26 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -789,7 +820,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
|
||||
}
|
||||
|
||||
/* Unbound weak natives */
|
||||
/* Unbind weak natives */
|
||||
List<WeakNative>::iterator 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@ -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 */
|
||||
pAPI = pExt->GetAPI();
|
||||
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()
|
||||
{
|
||||
List<CExtension *>::iterator iter;
|
||||
|
@ -55,6 +55,14 @@ 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
|
||||
{
|
||||
friend class CExtensionManager;
|
||||
@ -98,6 +106,7 @@ protected:
|
||||
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;
|
||||
@ -168,6 +177,7 @@ public:
|
||||
void TryAutoload();
|
||||
void AddLibrary(IExtension *pSource, const char *library);
|
||||
bool LibraryExists(const char *library);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
public:
|
||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||
void Shutdown();
|
||||
@ -175,6 +185,8 @@ 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;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
assert(pPlugin->GetBaseContext() != NULL);
|
||||
|
@ -489,6 +489,7 @@ public:
|
||||
}
|
||||
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);
|
||||
|
@ -243,3 +243,8 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *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 AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||
void RegisterLibrary(IExtension *myself, const char *name);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
public: //SMGlobalClass
|
||||
/* Pre-empt in case anything tries to register idents early */
|
||||
void OnSourceModStartup(bool late);
|
||||
|
@ -127,8 +127,11 @@ namespace SourceMod
|
||||
|
||||
/**
|
||||
* @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.
|
||||
|
@ -200,6 +200,29 @@ namespace SourceMod
|
||||
* @param name Library name.
|
||||
*/
|
||||
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