finished most of the extension system
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40320
This commit is contained in:
parent
3bba8d6a2a
commit
c5d0848177
3
TODO.txt
3
TODO.txt
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#endif
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourcePawn;
|
||||
|
||||
class SDKExtension :
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
|
Loading…
Reference in New Issue
Block a user