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:
David Anderson 2007-11-17 04:31:01 +00:00
parent dfa007081b
commit a79a169384
8 changed files with 141 additions and 3 deletions

View File

@ -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;

View File

@ -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;
}; };

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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.

View File

@ -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;
}; };
} }