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

View File

@ -67,6 +67,15 @@ namespace SourceMod
* @param iter Pointer to iterator to free. * @param iter Pointer to iterator to free.
*/ */
virtual void FreeDependencyIterator(ITERATOR *iter) =0; 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 #define SMINTERFACE_EXTENSIONAPI_VERSION 1

View File

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

View File

@ -46,11 +46,6 @@ public:
* @brief Returns the base folder for file natives. * @brief Returns the base folder for file natives.
*/ */
const char *GetBaseDir(); const char *GetBaseDir();
/**
* @brief Returns whether our load in this map is late.
*/
bool IsLateLoadInMap();
private: private:
/** /**
* @brief Loading plugins * @brief Loading plugins
@ -59,7 +54,6 @@ private:
private: private:
char m_SMBaseDir[PLATFORM_MAX_PATH+1]; char m_SMBaseDir[PLATFORM_MAX_PATH+1];
bool m_IsMapLoading; bool m_IsMapLoading;
bool m_IsLateLoadInMap;
}; };
extern SourceModBase g_SourceMod; 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_pIdentToken = NULL;
m_PlId = 0; m_PlId = 0;
unload_code = 0; unload_code = 0;
m_FullyLoaded = false;
char path[PLATFORM_MAX_PATH+1]; char path[PLATFORM_MAX_PATH+1];
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename); 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); 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()) if (m_pAPI->IsMetamodExtension())
{ {
@ -73,6 +74,12 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
g_ShareSys.DestroyIdentity(m_pIdentToken); g_ShareSys.DestroyIdentity(m_pIdentToken);
m_pIdentToken = NULL; m_pIdentToken = NULL;
return; 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) void CExtension::AddPlugin(IPlugin *pPlugin)
{ {
m_Plugins.push_back(pPlugin); m_Plugins.push_back(pPlugin);
@ -204,6 +221,20 @@ void CExtension::AddInterface(SMInterface *pInterface)
m_Interfaces.push_back(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 * * EXTENSION MANAGER *
*********************/ *********************/
@ -224,6 +255,13 @@ void CExtensionManager::OnSourceModShutdown()
IExtension *CExtensionManager::LoadAutoExtension(const char *path) 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; IExtension *pAlready;
if ((pAlready=FindExtensionByFile(path)) != NULL) if ((pAlready=FindExtensionByFile(path)) != NULL)
{ {
@ -249,6 +287,13 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
List<CExtension *>::iterator iter; List<CExtension *>::iterator iter;
CExtension *pExt; 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 */ /* Make sure the file direction is right */
char path[PLATFORM_MAX_PATH+1]; char path[PLATFORM_MAX_PATH+1];
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file); g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
@ -315,6 +360,8 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime
return NULL; return NULL;
} }
/* :TODO: do QueryRunning check if the map is loaded */
m_Libs.push_back(pExt); m_Libs.push_back(pExt);
return pExt; return pExt;
@ -372,6 +419,47 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num)
return NULL; 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) bool CExtensionManager::UnloadExtension(IExtension *_pExt)
{ {
if (!_pExt) if (!_pExt)
@ -449,6 +537,33 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
return true; 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) void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argcount)
{ {
if (argcount >= 3) if (argcount >= 3)
@ -482,11 +597,17 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco
pExt = (*iter); pExt = (*iter);
if (pExt->IsLoaded()) if (pExt->IsLoaded())
{ {
IExtensionInterface *pAPI = pExt->GetAPI(); char error[255];
const char *name = pAPI->GetExtensionName(); if (!pExt->IsRunning(error, sizeof(error)))
const char *version = pAPI->GetExtensionVerString(); {
const char *descr = pAPI->GetExtensionDescription(); g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr); } 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 { } else {
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str()); 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(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str()); g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
} else { } else {
IExtensionInterface *pAPI = pExt->GetAPI(); char error[255];
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename()); if (!pExt->IsRunning(error, sizeof(error)))
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString()); {
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription()); g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL()); g_RootMenu.ConsolePrint(" Loaded: Yes");
g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString()); g_RootMenu.ConsolePrint(" Running: No (%s)", error);
g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no"); } 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; return;
} else if (strcmp(cmd, "unload") == 0) { } else if (strcmp(cmd, "unload") == 0) {

View File

@ -28,12 +28,14 @@ public: //IExtension
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface); ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface); bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
void FreeDependencyIterator(ITERATOR *iter); void FreeDependencyIterator(ITERATOR *iter);
bool IsRunning(char *error, size_t maxlength);
public: public:
void SetError(const char *error); void SetError(const char *error);
void AddDependency(IfaceInfo *pInfo); void AddDependency(IfaceInfo *pInfo);
void AddInterface(SMInterface *pInterface); void AddInterface(SMInterface *pInterface);
void AddPlugin(IPlugin *pPlugin); void AddPlugin(IPlugin *pPlugin);
void RemovePlugin(IPlugin *pPlugin); void RemovePlugin(IPlugin *pPlugin);
void MarkAllLoaded();
private: private:
IdentityToken_t *m_pIdentToken; IdentityToken_t *m_pIdentToken;
IExtensionInterface *m_pAPI; IExtensionInterface *m_pAPI;
@ -43,8 +45,10 @@ private:
List<IfaceInfo> m_Deps; List<IfaceInfo> m_Deps;
List<SMInterface *> m_Interfaces; List<SMInterface *> m_Interfaces;
List<IPlugin *> m_Plugins; List<IPlugin *> m_Plugins;
List<const sp_nativeinfo_t *> m_Natives;
PluginId m_PlId; PluginId m_PlId;
unsigned int unload_code; unsigned int unload_code;
bool m_FullyLoaded;
}; };
class CExtensionManager : class CExtensionManager :
@ -73,6 +77,9 @@ public:
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
void AddInterface(IExtension *pOwner, SMInterface *pInterface); void AddInterface(IExtension *pOwner, SMInterface *pInterface);
void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin); void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin);
void AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives);
void BindAllNativesToPlugin(IPlugin *pPlugin);
void MarkAllLoaded();
private: private:
CExtension *FindByOrder(unsigned int num); CExtension *FindByOrder(unsigned int num);
private: 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 //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) 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); AddCoreNativesToPlugin(pPlugin);
pPlugin->InitIdentity(); 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) if (_plugin)
@ -800,6 +803,16 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ
AddPlugin(pl); 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; return pl;
} }
@ -837,20 +850,25 @@ void CPluginManager::LoadAll_SecondPass()
List<CPlugin *>::iterator iter; List<CPlugin *>::iterator iter;
CPlugin *pPlugin; CPlugin *pPlugin;
char error[256];
for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++) for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
{ {
pPlugin = (*iter); pPlugin = (*iter);
if (pPlugin->GetStatus() == Plugin_Loaded) if (pPlugin->GetStatus() == Plugin_Loaded)
{ {
/* :TODO: fix */ error[0] = '\0';
RunSecondPass(pPlugin, NULL, 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; 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 */ /* Find any extensions this plugin needs */
struct _ext struct _ext
@ -888,36 +906,75 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng
{ {
continue; continue;
} }
snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT); if (pass == 1)
pExt = NULL;
/* Attempt to auto-load if necessary */
if (ext->autoload)
{ {
pExt = g_Extensions.LoadAutoExtension(path); /* Attempt to auto-load if necessary */
} if (ext->autoload)
/* See if we can find a similar extension */
if (ext->required && !pExt)
{
if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
{ {
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); snprintf(error, maxlength, "Native \"%s\" was not found.", native->name);
}
/* 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;
} }
return false;
} }
} }
@ -1268,7 +1325,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
bool CPluginManager::IsLateLoadTime() const bool CPluginManager::IsLateLoadTime() const
{ {
return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap()); return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading());
} }
void CPluginManager::OnSourceModAllInitialized() void CPluginManager::OnSourceModAllInitialized()
@ -1486,40 +1543,49 @@ void CPluginManager::OnRootConsoleCommand(const char *command, unsigned int argc
return; return;
} }
IPluginIterator *iter = GetPluginIterator(); CPlugin *pl = GetPluginByOrder(num);
for (; iter->MorePlugins() && id<num; iter->NextPlugin(), id++) {}
IPlugin *pl = iter->GetPlugin();
const sm_plugininfo_t *info = pl->GetPublicInfo(); const sm_plugininfo_t *info = pl->GetPublicInfo();
g_RootMenu.ConsolePrint(" Filename: %s", pl->GetFilename()); g_RootMenu.ConsolePrint(" Filename: %s", pl->GetFilename());
if (IS_STR_FILLED(info->name)) if (pl->GetStatus() <= Plugin_Error)
{
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 (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(" 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; return;
} else if (strcmp(cmd, "debug") == 0) { } else if (strcmp(cmd, "debug") == 0) {
if (argcount < 5) if (argcount < 5)

View File

@ -149,13 +149,13 @@ public:
void Call_OnPluginUnload(); void Call_OnPluginUnload();
/** /**
* Toggles debug mode in the plugin * Toggles debug mode in the plugin
*/ */
bool ToggleDebugMode(bool debug, char *error, size_t maxlength); 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; bool IsRunnable() const;
public: public:
time_t HasUpdatedFile(); time_t HasUpdatedFile();
@ -277,6 +277,7 @@ public:
* Gets status text for a status code * Gets status text for a status code
*/ */
const char *GetStatusText(PluginStatus status); const char *GetStatusText(PluginStatus status);
private: private:
bool _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max); 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 * Adds any globally registered natives to a plugin
*/ */
void AddCoreNativesToPlugin(CPlugin *pPlugin); void AddCoreNativesToPlugin(CPlugin *pPlugin);
/**
* Runs an extension pass on a plugin.
*/
bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
protected: protected:
/** /**
* Caching internal objects * 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) void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
{ {
g_Extensions.AddNatives(myself, natives);
} }
void ShareSystem::DestroyIdentity(IdentityToken_t *identity) void ShareSystem::DestroyIdentity(IdentityToken_t *identity)

View File

@ -27,6 +27,7 @@ public:
/** /**
* @brief This is called once all known extensions have been loaded. * @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(); //virtual void SDK_OnAllLoaded();
@ -34,6 +35,15 @@ public:
* @brief Called when the pause state is changed. * @brief Called when the pause state is changed.
*/ */
//virtual void SDK_OnPauseChange(bool paused); //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: public:
#if defined SMEXT_CONF_METAMOD #if defined SMEXT_CONF_METAMOD
/** /**

View File

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

View File

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