finished most of the extension system

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40320
This commit is contained in:
David Anderson 2007-01-18 23:28:14 +00:00
parent 3bba8d6a2a
commit c5d0848177
12 changed files with 322 additions and 92 deletions

View File

@ -1,9 +1,10 @@
things to do for a release, in priority
X finish plugin unloading
X URGENT: fix compiler's sizeof(), add cellsof
- do module api
X do module api
X finish plugin pausing/unpausing, forwards must block execution
- do admin api
- make "mapupdated" plugins work as intended (reload on mapchange if newer)
X add debugging output to logger
- finish ML api, expose through interface
X add error messages to format routine

View File

@ -67,6 +67,15 @@ namespace SourceMod
* @param iter Pointer to iterator to free.
*/
virtual void FreeDependencyIterator(ITERATOR *iter) =0;
/**
* @brief Queries the extension to see its run state.
*
* @param error Error buffer (may be NULL).
* @param maxlength Maximum length of buffer.
* @return True if extension is okay, false if not okay.
*/
virtual bool IsRunning(char *error, size_t maxlength) =0;
};
#define SMINTERFACE_EXTENSIONAPI_VERSION 1

View File

@ -7,6 +7,7 @@
#include "PluginSys.h"
#include "ShareSys.h"
#include "CLogger.h"
#include "ExtensionSys.h"
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
@ -131,13 +132,11 @@ void SourceModBase::StartSourceMod(bool late)
/* First initialize the global hooks we need */
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
m_IsLateLoadInMap = late;
/* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head;
while (pBase)
{
pBase->OnSourceModStartup(m_IsLateLoadInMap);
pBase->OnSourceModStartup(false);
pBase = pBase->m_pGlobalClassNext;
}
@ -156,7 +155,6 @@ void SourceModBase::StartSourceMod(bool late)
bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
{
m_IsMapLoading = true;
m_IsLateLoadInMap = false;
g_Logger.MapChange(pMapName);
@ -167,6 +165,11 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch
RETURN_META_VALUE(MRES_IGNORED, true);
}
bool SourceModBase::IsMapLoading()
{
return m_IsMapLoading;
}
void SourceModBase::DoGlobalPluginLoads()
{
char config_path[PLATFORM_MAX_PATH];
@ -181,10 +184,17 @@ void SourceModBase::DoGlobalPluginLoads()
"%s/plugins",
GetSMBaseDir());
/* Run the first pass */
g_PluginSys.LoadAll_FirstPass(config_path, plugins_path);
/* Mark any extensions as loaded */
g_Extensions.MarkAllLoaded();
/* No modules yet, it's safe to call this from here */
g_PluginSys.LoadAll_SecondPass();
/* Re-mark any extensions as loaded */
g_Extensions.MarkAllLoaded();
}
void SourceModBase::CloseSourceMod()
@ -209,11 +219,6 @@ void SourceModBase::CloseSourceMod()
ShutdownJIT();
}
bool SourceModBase::IsLateLoadInMap()
{
return m_IsLateLoadInMap;
}
const char *SourceModBase::GetSMBaseDir()
{
return m_SMBaseDir;

View File

@ -46,11 +46,6 @@ public:
* @brief Returns the base folder for file natives.
*/
const char *GetBaseDir();
/**
* @brief Returns whether our load in this map is late.
*/
bool IsLateLoadInMap();
private:
/**
* @brief Loading plugins
@ -59,7 +54,6 @@ private:
private:
char m_SMBaseDir[PLATFORM_MAX_PATH+1];
bool m_IsMapLoading;
bool m_IsLateLoadInMap;
};
extern SourceModBase g_SourceMod;

View File

@ -17,6 +17,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
m_pIdentToken = NULL;
m_PlId = 0;
unload_code = 0;
m_FullyLoaded = false;
char path[PLATFORM_MAX_PATH+1];
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename);
@ -56,7 +57,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType);
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, err_max, g_SourceMod.IsLateLoadInMap()))
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, err_max, !g_SourceMod.IsMapLoading()))
{
if (m_pAPI->IsMetamodExtension())
{
@ -73,6 +74,12 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
g_ShareSys.DestroyIdentity(m_pIdentToken);
m_pIdentToken = NULL;
return;
} else {
/* Check if we're past load time */
if (!g_SourceMod.IsMapLoading())
{
m_pAPI->OnExtensionsAllLoaded();
}
}
}
@ -98,6 +105,16 @@ CExtension::~CExtension()
}
}
void CExtension::MarkAllLoaded()
{
assert(m_FullyLoaded == false);
if (!m_FullyLoaded)
{
m_FullyLoaded = true;
m_pAPI->OnExtensionsAllLoaded();
}
}
void CExtension::AddPlugin(IPlugin *pPlugin)
{
m_Plugins.push_back(pPlugin);
@ -204,6 +221,20 @@ void CExtension::AddInterface(SMInterface *pInterface)
m_Interfaces.push_back(pInterface);
}
bool CExtension::IsRunning(char *error, size_t maxlength)
{
if (!IsLoaded())
{
if (error)
{
snprintf(error, maxlength, "%s", m_Error.c_str());
}
return false;
}
return m_pAPI->QueryRunning(error, maxlength);
}
/*********************
* EXTENSION MANAGER *
*********************/
@ -224,6 +255,13 @@ void CExtensionManager::OnSourceModShutdown()
IExtension *CExtensionManager::LoadAutoExtension(const char *path)
{
if (!strstr(path, "." PLATFORM_LIB_EXT))
{
char newpath[PLATFORM_MAX_PATH+1];
snprintf(newpath, PLATFORM_MAX_PATH, "%s.%s", path, PLATFORM_LIB_EXT);
return LoadAutoExtension(newpath);
}
IExtension *pAlready;
if ((pAlready=FindExtensionByFile(path)) != NULL)
{
@ -249,6 +287,13 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
List<CExtension *>::iterator iter;
CExtension *pExt;
if (!strstr(file, "." PLATFORM_LIB_EXT))
{
char path[PLATFORM_MAX_PATH];
snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT);
return FindExtensionByFile(path);
}
/* Make sure the file direction is right */
char path[PLATFORM_MAX_PATH+1];
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
@ -315,6 +360,8 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime
return NULL;
}
/* :TODO: do QueryRunning check if the map is loaded */
m_Libs.push_back(pExt);
return pExt;
@ -372,6 +419,47 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num)
return NULL;
}
void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
{
List<CExtension *>::iterator iter;
CExtension *pExt;
IPluginContext *pContext = pPlugin->GetBaseContext();
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
{
pExt = (*iter);
if (!pExt->IsLoaded())
{
continue;
}
if (!pExt->m_Natives.size())
{
continue;
}
bool set = false;
List<const sp_nativeinfo_t *>::iterator n_iter;
const sp_nativeinfo_t *natives;
for (n_iter = pExt->m_Natives.begin();
n_iter != pExt->m_Natives.end();
n_iter++)
{
natives = (*n_iter);
unsigned int i=0;
while (natives[i].func != NULL && natives[i].name != NULL)
{
if (pContext->BindNative(&natives[i++]) == SP_ERROR_NONE)
{
set = true;
}
}
}
if (set && (pExt->m_Plugins.find(pPlugin) == pExt->m_Plugins.end()))
{
/* For now, mark this plugin as a requirement. Later we'll introduce native filtering. */
pExt->m_Plugins.push_back(pPlugin);
}
}
}
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
{
if (!_pExt)
@ -449,6 +537,33 @@ 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);
}
void CExtensionManager::MarkAllLoaded()
{
List<CExtension *>::iterator iter;
CExtension *pExt;
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
{
pExt = (*iter);
if (!pExt->IsLoaded())
{
continue;
}
if (pExt->m_FullyLoaded)
{
continue;
}
pExt->MarkAllLoaded();
}
}
void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argcount)
{
if (argcount >= 3)
@ -482,11 +597,17 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco
pExt = (*iter);
if (pExt->IsLoaded())
{
IExtensionInterface *pAPI = pExt->GetAPI();
const char *name = pAPI->GetExtensionName();
const char *version = pAPI->GetExtensionVerString();
const char *descr = pAPI->GetExtensionDescription();
g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
char error[255];
if (!pExt->IsRunning(error, sizeof(error)))
{
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
} else {
IExtensionInterface *pAPI = pExt->GetAPI();
const char *name = pAPI->GetExtensionName();
const char *version = pAPI->GetExtensionVerString();
const char *descr = pAPI->GetExtensionDescription();
g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
}
} else {
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
}
@ -542,13 +663,21 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
} else {
IExtensionInterface *pAPI = pExt->GetAPI();
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no");
char error[255];
if (!pExt->IsRunning(error, sizeof(error)))
{
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: Yes");
g_RootMenu.ConsolePrint(" Running: No (%s)", error);
} else {
IExtensionInterface *pAPI = pExt->GetAPI();
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no");
}
}
return;
} else if (strcmp(cmd, "unload") == 0) {

View File

@ -28,12 +28,14 @@ public: //IExtension
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
void FreeDependencyIterator(ITERATOR *iter);
bool IsRunning(char *error, size_t maxlength);
public:
void SetError(const char *error);
void AddDependency(IfaceInfo *pInfo);
void AddInterface(SMInterface *pInterface);
void AddPlugin(IPlugin *pPlugin);
void RemovePlugin(IPlugin *pPlugin);
void MarkAllLoaded();
private:
IdentityToken_t *m_pIdentToken;
IExtensionInterface *m_pAPI;
@ -43,8 +45,10 @@ private:
List<IfaceInfo> m_Deps;
List<SMInterface *> m_Interfaces;
List<IPlugin *> m_Plugins;
List<const sp_nativeinfo_t *> m_Natives;
PluginId m_PlId;
unsigned int unload_code;
bool m_FullyLoaded;
};
class CExtensionManager :
@ -73,6 +77,9 @@ public:
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 MarkAllLoaded();
private:
CExtension *FindByOrder(unsigned int num);
private:

View File

@ -693,7 +693,6 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa
}
//well i have discovered that gabe newell is very fat, so i wrote this comment now
//:TODO: remove this function, create a better wrapper for LoadPlugin()/LoadAutoPlugin()
bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t err_max)
{
/**
@ -777,7 +776,11 @@ bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug
{
AddCoreNativesToPlugin(pPlugin);
pPlugin->InitIdentity();
pPlugin->Call_AskPluginLoad(error, err_max);
if (pPlugin->Call_AskPluginLoad(error, err_max))
{
/* Autoload any modules */
LoadOrRequireExtensions(pPlugin, 1, error, err_max);
}
}
if (_plugin)
@ -800,6 +803,16 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ
AddPlugin(pl);
/* Run second pass if we need to */
if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded)
{
if (!RunSecondPass(pl, error, err_max))
{
UnloadPlugin(pl);
return NULL;
}
}
return pl;
}
@ -837,20 +850,25 @@ void CPluginManager::LoadAll_SecondPass()
List<CPlugin *>::iterator iter;
CPlugin *pPlugin;
char error[256];
for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
{
pPlugin = (*iter);
if (pPlugin->GetStatus() == Plugin_Loaded)
{
/* :TODO: fix */
RunSecondPass(pPlugin, NULL, 0);
error[0] = '\0';
if (!RunSecondPass(pPlugin, error, sizeof(error)))
{
g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
pPlugin->SetErrorState(Plugin_Failed, "%s", error);
}
}
}
m_AllPluginsLoaded = true;
}
bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength)
{
/* Find any extensions this plugin needs */
struct _ext
@ -888,36 +906,75 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng
{
continue;
}
snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT);
pExt = NULL;
/* Attempt to auto-load if necessary */
if (ext->autoload)
if (pass == 1)
{
pExt = g_Extensions.LoadAutoExtension(path);
}
/* See if we can find a similar extension */
if (ext->required && !pExt)
{
if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
/* Attempt to auto-load if necessary */
if (ext->autoload)
{
pExt = g_Extensions.FindExtensionByName(name);
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
g_Extensions.LoadAutoExtension(path);
}
} else if (pass == 2) {
/* Is this required? */
if (ext->required)
{
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
{
pExt = g_Extensions.FindExtensionByName(name);
}
/* :TODO: should we bind to unloaded extensions?
* Currently the extension manager will ignore this.
*/
if (!pExt || !pExt->IsRunning(NULL, 0))
{
if (error)
{
snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file);
}
pPlugin->m_status = Plugin_Failed;
return false;
} else {
g_Extensions.BindChildPlugin(pExt, pPlugin);
}
}
}
/* If we're requiring and got an extension and it's loaded, bind it */
if (ext->required && pExt && pExt->IsLoaded())
}
}
return true;
}
bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
{
/* Second pass for extension requirements */
if (!LoadOrRequireExtensions(pPlugin, 2, error, maxlength))
{
return false;
}
/* Bind all extra natives */
g_Extensions.BindAllNativesToPlugin(pPlugin);
/* Find any unbound natives
* Right now, these are not allowed
*/
IPluginContext *pContext = pPlugin->GetBaseContext();
uint32_t num = pContext->GetNativesNum();
sp_native_t *native;
for (unsigned int i=0; i<num; i++)
{
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
{
break;
}
if (native->status == SP_NATIVE_UNBOUND)
{
if (error)
{
g_Extensions.BindChildPlugin(pExt, pPlugin);
}
/* If we're requiring and we didn't get an extension or it's not loaded, error */
if (ext->required && (!pExt || !pExt->IsLoaded()))
{
if (error)
{
snprintf(error, maxlength, "Required extension \"%s\" (file \"%s\") not found", name, file);
}
pPlugin->m_status = Plugin_Failed;
return false;
snprintf(error, maxlength, "Native \"%s\" was not found.", native->name);
}
return false;
}
}
@ -1268,7 +1325,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
bool CPluginManager::IsLateLoadTime() const
{
return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap());
return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading());
}
void CPluginManager::OnSourceModAllInitialized()
@ -1486,40 +1543,49 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc
return;
}
IPluginIterator *iter = GetPluginIterator();
for (; iter->MorePlugins() && id<num; iter->NextPlugin(), id++) {}
IPlugin *pl = iter->GetPlugin();
CPlugin *pl = GetPluginByOrder(num);
const sm_plugininfo_t *info = pl->GetPublicInfo();
g_RootMenu.ConsolePrint(" Filename: %s", pl->GetFilename());
if (IS_STR_FILLED(info->name))
{
g_RootMenu.ConsolePrint(" Title: %s", info->name);
}
if (IS_STR_FILLED(info->author))
{
g_RootMenu.ConsolePrint(" Author: %s", info->author);
}
if (IS_STR_FILLED(info->version))
{
g_RootMenu.ConsolePrint(" Version: %s", info->version);
}
if (IS_STR_FILLED(info->description))
{
g_RootMenu.ConsolePrint(" Description: %s", info->description);
}
if (IS_STR_FILLED(info->url))
{
g_RootMenu.ConsolePrint(" URL: %s", info->url);
}
if (pl->GetStatus() >= Plugin_Error)
if (pl->GetStatus() <= Plugin_Error)
{
if (IS_STR_FILLED(info->name))
{
g_RootMenu.ConsolePrint(" Title: %s", info->name);
}
if (IS_STR_FILLED(info->version))
{
g_RootMenu.ConsolePrint(" Version: %s", info->version);
}
if (IS_STR_FILLED(info->url))
{
g_RootMenu.ConsolePrint(" URL: %s", info->url);
}
if (IS_STR_FILLED(info->author))
{
g_RootMenu.ConsolePrint(" Author: %s", info->author);
}
if (IS_STR_FILLED(info->version))
{
g_RootMenu.ConsolePrint(" Version: %s", info->version);
}
if (IS_STR_FILLED(info->description))
{
g_RootMenu.ConsolePrint(" Description: %s", info->description);
}
g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no");
g_RootMenu.ConsolePrint(" Paused: %s", pl->GetStatus() == Plugin_Running ? "yes" : "no");
} else {
g_RootMenu.ConsolePrint(" Load error: %s", pl->m_errormsg);
g_RootMenu.ConsolePrint(" File info: (title \"%s\") (version \"%s\")",
info->name ? info->name : "<none>",
info->version ? info->version : "<none>");
if (IS_STR_FILLED(info->url))
{
g_RootMenu.ConsolePrint(" File URL: %s", info->url);
}
}
iter->Release();
return;
} else if (strcmp(cmd, "debug") == 0) {
if (argcount < 5)

View File

@ -149,13 +149,13 @@ public:
void Call_OnPluginUnload();
/**
* Toggles debug mode in the plugin
*/
* Toggles debug mode in the plugin
*/
bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
/**
* Returns true if a plugin is usable.
*/
* Returns true if a plugin is usable.
*/
bool IsRunnable() const;
public:
time_t HasUpdatedFile();
@ -277,6 +277,7 @@ public:
* Gets status text for a status code
*/
const char *GetStatusText(PluginStatus status);
private:
bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max);
@ -301,6 +302,11 @@ private:
* Adds any globally registered natives to a plugin
*/
void AddCoreNativesToPlugin(CPlugin *pPlugin);
/**
* Runs an extension pass on a plugin.
*/
bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
protected:
/**
* Caching internal objects

View File

@ -161,7 +161,7 @@ bool ShareSystem::RequestInterface(const char *iface_name,
void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
{
g_Extensions.AddNatives(myself, natives);
}
void ShareSystem::DestroyIdentity(IdentityToken_t *identity)

View File

@ -27,6 +27,7 @@ public:
/**
* @brief This is called once all known extensions have been loaded.
* Note: It is is a good idea to add natives here, if any are provided.
*/
//virtual void SDK_OnAllLoaded();
@ -34,6 +35,15 @@ public:
* @brief Called when the pause state is changed.
*/
//virtual void SDK_OnPauseChange(bool paused);
/**
* @brief this is called when Core wants to know if your extension is working.
*
* @param error Error message buffer.
* @param err_max Size of error message buffer.
* @return True if working, false otherwise.
*/
//virtual void QueryRunning(char *error, size_t maxlength);
public:
#if defined SMEXT_CONF_METAMOD
/**

View File

@ -24,9 +24,9 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error,
g_pShareSys = sys;
myself = me;
#if defined SMEXT_CONF_METAMOD
m_WeAreUnloaded = true;
#if defined SMEXT_CONF_METAMOD
if (!m_SourceMMLoaded)
{
if (error)
@ -41,7 +41,9 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error,
if (SDK_OnLoad(error, err_max, late))
{
#if defined SMEXT_CONF_METAMOD
m_WeAreUnloaded = true;
#endif
return true;
}

View File

@ -13,6 +13,7 @@
#endif
using namespace SourceMod;
using namespace SourcePawn;
class SDKExtension :
#if defined SMEXT_CONF_METAMOD