Added global class initialization automation
Finalized basics of plugin loading Began redoing how dependencies will be tracked Renamed some bad names Finished some stuff in ForwardSys --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40216
This commit is contained in:
parent
a93faa3cbf
commit
90d1f4495e
@ -8,16 +8,12 @@ namespace SourceMod
|
|||||||
{
|
{
|
||||||
class IModuleInterface;
|
class IModuleInterface;
|
||||||
|
|
||||||
class IModule : public IUnloadableParent
|
class IModule
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual UnloadableParentType GetParentType()
|
|
||||||
{
|
|
||||||
return ParentType_Module;
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
virtual IModuleInterface *GetModuleInfo() =0;
|
virtual IModuleInterface *GetModuleInfo() =0;
|
||||||
virtual const char *GetFilename() =0;
|
virtual const char *GetFilename() =0;
|
||||||
|
virtual IdentityToken_t GetIdentityToken() =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IModuleInterface
|
class IModuleInterface
|
||||||
@ -27,13 +23,19 @@ namespace SourceMod
|
|||||||
* @brief Called when the module is loaded.
|
* @brief Called when the module is loaded.
|
||||||
*
|
*
|
||||||
* @param me Pointer back to module.
|
* @param me Pointer back to module.
|
||||||
|
* @param token Identity token handle.
|
||||||
* @param sys Pointer to interface sharing system of SourceMod.
|
* @param sys Pointer to interface sharing system of SourceMod.
|
||||||
* @param error Error buffer to print back to, if any.
|
* @param error Error buffer to print back to, if any.
|
||||||
* @param err_max Maximum size of error buffer.
|
* @param err_max Maximum size of error buffer.
|
||||||
* @param late If this module was loaded "late" (i.e. manually).
|
* @param late If this module was loaded "late" (i.e. manually).
|
||||||
* @return True if load should continue, false otherwise.
|
* @return True if load should continue, false otherwise.
|
||||||
*/
|
*/
|
||||||
virtual bool OnModuleLoad(IModule *me, IShareSys *sys, char *error, size_t err_max, bool late) =0;
|
virtual bool OnModuleLoad(IModule *me,
|
||||||
|
IdentityToken_t token,
|
||||||
|
IShareSys *sys,
|
||||||
|
char *error,
|
||||||
|
size_t err_max,
|
||||||
|
bool late) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when the module is unloaded.
|
* @brief Called when the module is unloaded.
|
||||||
@ -51,7 +53,6 @@ namespace SourceMod
|
|||||||
* @param pause True if pausing, false if unpausing.
|
* @param pause True if pausing, false if unpausing.
|
||||||
*/
|
*/
|
||||||
virtual void OnPauseChange(bool pause) =0;
|
virtual void OnPauseChange(bool pause) =0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual const char *GetModuleName() =0;
|
virtual const char *GetModuleName() =0;
|
||||||
virtual const char *GetModuleVersion() =0;
|
virtual const char *GetModuleVersion() =0;
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
namespace SourceMod
|
namespace SourceMod
|
||||||
{
|
{
|
||||||
#define SM_FUNCFLAG_COPYBACK (1<<0) /* Copy an array/reference back after call */
|
#define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */
|
||||||
|
|
||||||
#define SP_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */
|
#define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */
|
||||||
#define SP_STRING_COPY (1<<1) /* String should be copied into the plugin */
|
#define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Represents what a function needs to implement in order to be callable.
|
* @brief Represents what a function needs to implement in order to be callable.
|
||||||
|
@ -25,15 +25,19 @@ namespace SourceMod
|
|||||||
const char *url;
|
const char *url;
|
||||||
} sm_plugininfo_t;
|
} sm_plugininfo_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Describes the usability status of a plugin.
|
* @brief Describes the usability status of a plugin.
|
||||||
*/
|
*/
|
||||||
enum PluginStatus
|
enum PluginStatus
|
||||||
{
|
{
|
||||||
Plugin_Running=0, /* Plugin is running */
|
Plugin_Running=0, /* Plugin is running */
|
||||||
Plugin_Loaded, /* Plugin is loaded but not initialized */
|
/* All states below are unexecutable */
|
||||||
Plugin_Paused, /* Plugin is paused */
|
Plugin_Paused, /* Plugin is loaded but paused */
|
||||||
|
/* All states below do not have all natives */
|
||||||
|
Plugin_Loaded, /* Plugin has passed loading and can be finalized */
|
||||||
Plugin_Error, /* Plugin has a blocking error */
|
Plugin_Error, /* Plugin has a blocking error */
|
||||||
|
Plugin_Created, /* Plugin is created but not initialized */
|
||||||
Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */
|
Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */
|
||||||
Plugin_BadLoad, /* Plugin failed to load */
|
Plugin_BadLoad, /* Plugin failed to load */
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_
|
#ifndef _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_
|
||||||
#define _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_
|
#define _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_
|
||||||
|
|
||||||
|
#include <sp_vm_types.h>
|
||||||
|
|
||||||
namespace SourceMod
|
namespace SourceMod
|
||||||
{
|
{
|
||||||
|
typedef unsigned int IdentityToken_t;
|
||||||
/**
|
/**
|
||||||
* @brief Defines the base functionality required by a shared interface.
|
* @brief Defines the base functionality required by a shared interface.
|
||||||
*/
|
*/
|
||||||
@ -37,48 +40,6 @@ namespace SourceMod
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum UnloadableParentType
|
|
||||||
{
|
|
||||||
ParentType_Module,
|
|
||||||
ParentType_Plugin
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Denotes a top-level unloadable object.
|
|
||||||
*/
|
|
||||||
class IUnloadableParent
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual UnloadableParentType GetParentType() =0;
|
|
||||||
|
|
||||||
virtual void *GetParentToken() =0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Called when an interface this object has requested is removed.
|
|
||||||
*
|
|
||||||
* @param pIface Interface being removed.
|
|
||||||
*/
|
|
||||||
virtual void OnInterfaceUnlink(SMInterface *pIface) =0;
|
|
||||||
protected:
|
|
||||||
void *m_parent_token;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Listens for unlinked objects.
|
|
||||||
*/
|
|
||||||
class IUnlinkListener
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Called when a parent object is unloaded.
|
|
||||||
*
|
|
||||||
* @param parent The parent object which is dying.
|
|
||||||
*/
|
|
||||||
virtual void OnParentUnlink(IUnloadableParent *parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tracks dependencies and fires dependency listeners.
|
* @brief Tracks dependencies and fires dependency listeners.
|
||||||
*/
|
*/
|
||||||
@ -89,9 +50,9 @@ namespace SourceMod
|
|||||||
* @brief Adds an interface to the global interface system
|
* @brief Adds an interface to the global interface system
|
||||||
*
|
*
|
||||||
* @param iface Interface pointer (must be unique).
|
* @param iface Interface pointer (must be unique).
|
||||||
* @param parent Parent unloadable token given to the module/interface.
|
* @param token Parent token of the module/interface.
|
||||||
*/
|
*/
|
||||||
virtual bool AddInterface(SMInterface *iface, IUnloadableParent *parent) =0;
|
virtual bool AddInterface(SMInterface *iface, IdentityToken_t token) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Requests an interface from the global interface system.
|
* @brief Requests an interface from the global interface system.
|
||||||
@ -99,36 +60,21 @@ namespace SourceMod
|
|||||||
*
|
*
|
||||||
* @param iface_name Interface name.
|
* @param iface_name Interface name.
|
||||||
* @param iface_vers Interface version to attempt to match.
|
* @param iface_vers Interface version to attempt to match.
|
||||||
* @param me Object requesting this interface, in order to track dependencies.
|
* @param token Object requesting this interface, in order to track dependencies.
|
||||||
* @param pIface Pointer to store the return value in.
|
* @param pIface Pointer to store the return value in.
|
||||||
*/
|
*/
|
||||||
virtual bool RequestInterface(const char *iface_name,
|
virtual bool RequestInterface(const char *iface_name,
|
||||||
unsigned int iface_vers,
|
unsigned int iface_vers,
|
||||||
IUnloadableParent *me,
|
IdentityToken_t token,
|
||||||
void **pIface) =0;
|
void **pIface) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unloads an interface.
|
* @brief Adds a list of natives to the global native pool.
|
||||||
*
|
*
|
||||||
* @param iface Interface pointer.
|
* @param token Identity token of parent object.
|
||||||
* @param parent Security token, trivial measure to prevent accidental unloads.
|
* @param natives Array of natives to add, NULL terminated.
|
||||||
* This token must match the one used with AddInterface().
|
|
||||||
*/
|
*/
|
||||||
virtual void RemoveInterface(SMInterface *iface, IUnloadableParent *parent) =0;
|
virtual void AddNatives(IdentityToken_t token, const sp_nativeinfo_t *natives[]) =0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds an unlink listener.
|
|
||||||
*
|
|
||||||
* @param pListener Listener pointer.
|
|
||||||
*/
|
|
||||||
virtual void AddUnlinkListener(IUnlinkListener *pListener) =0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Removes an unlink listener.
|
|
||||||
*
|
|
||||||
* @param pListener Listener pointer.
|
|
||||||
*/
|
|
||||||
virtual void RemoveUnlinkListener(IUnlinkListener *pListener) =0;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -186,6 +186,10 @@
|
|||||||
RelativePath="..\sm_memtable.cpp"
|
RelativePath="..\sm_memtable.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\sm_trie.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\sourcemm_api.cpp"
|
RelativePath="..\sourcemm_api.cpp"
|
||||||
>
|
>
|
||||||
@ -216,6 +220,10 @@
|
|||||||
RelativePath="..\sm_platform.h"
|
RelativePath="..\sm_platform.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\sm_trie.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\sm_version.h"
|
RelativePath="..\sm_version.h"
|
||||||
>
|
>
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
#if !defined snprintf
|
#if !defined snprintf
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined stat
|
||||||
|
#define stat _stat
|
||||||
|
#endif
|
||||||
#define strcasecmp strcmpi
|
#define strcasecmp strcmpi
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
|
@ -266,6 +266,56 @@ void sm_trie_destroy(Trie *trie)
|
|||||||
delete trie;
|
delete trie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sm_trie_delete(Trie *trie, const char *key)
|
||||||
|
{
|
||||||
|
unsigned int lastidx = 1; /* the last node index */
|
||||||
|
unsigned int curidx; /* current node index */
|
||||||
|
const char *keyptr = key; /* input stream at current token */
|
||||||
|
TrieNode *node = NULL; /* current node being processed */
|
||||||
|
TrieNode *base = trie->base;
|
||||||
|
|
||||||
|
if (!*key)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start traversing at the root node */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Find where the next character is, then advance */
|
||||||
|
curidx = base[lastidx].idx;
|
||||||
|
node = &base[curidx];
|
||||||
|
curidx += charval(*keyptr);
|
||||||
|
node = &base[curidx];
|
||||||
|
keyptr++;
|
||||||
|
|
||||||
|
/* Check if this slot is supposed to be empty or is a collision */
|
||||||
|
if ((curidx > trie->baseSize) || node->mode == Node_Unused || node->parent != lastidx)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else if (node->mode == Node_Term) {
|
||||||
|
char *term = &trie->stringtab[node->idx];
|
||||||
|
if (strcmp(keyptr, term) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastidx = curidx;
|
||||||
|
} while (*keyptr != '\0');
|
||||||
|
|
||||||
|
assert(node != NULL);
|
||||||
|
|
||||||
|
if (!node->valset)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->valset = false;
|
||||||
|
node->value = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool sm_trie_retrieve(Trie *trie, const char *key, void **value)
|
bool sm_trie_retrieve(Trie *trie, const char *key, void **value)
|
||||||
{
|
{
|
||||||
unsigned int lastidx = 1; /* the last node index */
|
unsigned int lastidx = 1; /* the last node index */
|
||||||
|
@ -7,5 +7,6 @@ Trie *sm_trie_create();
|
|||||||
void sm_trie_destroy(Trie *trie);
|
void sm_trie_destroy(Trie *trie);
|
||||||
bool sm_trie_insert(Trie *trie, const char *key, void *value);
|
bool sm_trie_insert(Trie *trie, const char *key, void *value);
|
||||||
bool sm_trie_retrieve(Trie *trie, const char *key, void **value);
|
bool sm_trie_retrieve(Trie *trie, const char *key, void **value);
|
||||||
|
bool sm_trie_delete(Trie *trie, const char *key);
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_
|
#endif //_INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_
|
||||||
|
@ -130,12 +130,17 @@ void SourceModBase::StartSourceMod(bool late)
|
|||||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
|
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
|
||||||
|
|
||||||
/* If we're late, automatically load plugins now */
|
/* If we're late, automatically load plugins now */
|
||||||
DoGlobalPluginLoads();
|
if (late)
|
||||||
|
{
|
||||||
|
m_IsLateLoadInMap = late;
|
||||||
|
DoGlobalPluginLoads();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
DoGlobalPluginLoads();
|
DoGlobalPluginLoads();
|
||||||
|
|
||||||
@ -158,10 +163,23 @@ void SourceModBase::DoGlobalPluginLoads()
|
|||||||
"%s/plugins",
|
"%s/plugins",
|
||||||
GetSMBaseDir());
|
GetSMBaseDir());
|
||||||
|
|
||||||
g_PluginMngr.RefreshOrLoadPlugins(config_path, plugins_path);
|
g_PluginSys.LoadAll_FirstPass(config_path, plugins_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SourceModBase::IsLateLoadInMap()
|
||||||
|
{
|
||||||
|
return m_IsLateLoadInMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *SourceModBase::GetSMBaseDir()
|
const char *SourceModBase::GetSMBaseDir()
|
||||||
{
|
{
|
||||||
return m_SMBaseDir;
|
return m_SMBaseDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SMGlobalClass *SMGlobalClass::head = NULL;
|
||||||
|
|
||||||
|
SMGlobalClass::SMGlobalClass()
|
||||||
|
{
|
||||||
|
m_pGlobalClassNext = SMGlobalClass::head;
|
||||||
|
SMGlobalClass::head = this;
|
||||||
|
}
|
||||||
|
@ -37,6 +37,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
const char *GetSMBaseDir();
|
const char *GetSMBaseDir();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns whether our load in this map is late.
|
||||||
|
*/
|
||||||
|
bool IsLateLoadInMap();
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Loading plugins
|
* @brief Loading plugins
|
||||||
@ -45,6 +49,41 @@ 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Any class deriving from this will be automatically initiated/shutdown by SourceMod
|
||||||
|
*/
|
||||||
|
class SMGlobalClass
|
||||||
|
{
|
||||||
|
friend class SourceModBase;
|
||||||
|
public:
|
||||||
|
SMGlobalClass();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Called when SourceMod is initially loading
|
||||||
|
*/
|
||||||
|
virtual void OnSourceModStartup(bool late)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called after all global classes have initialized
|
||||||
|
*/
|
||||||
|
virtual void OnSourceModAllInitialized()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when SourceMod is shutting down
|
||||||
|
*/
|
||||||
|
virtual void OnSourceModShutdown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SMGlobalClass *m_pGlobalClassNext;
|
||||||
|
static SMGlobalClass *head;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SourceModBase g_SourceMod;
|
extern SourceModBase g_SourceMod;
|
||||||
|
@ -112,7 +112,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr
|
|||||||
|
|
||||||
int CFunction::PushString(const char *string)
|
int CFunction::PushString(const char *string)
|
||||||
{
|
{
|
||||||
return _PushString(string, SP_STRING_COPY, 0, strlen(string)+1);
|
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||||
@ -141,12 +141,12 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_
|
|||||||
m_params[m_curparam] = info->local_addr;
|
m_params[m_curparam] = info->local_addr;
|
||||||
m_curparam++; /* Prevent a leak */
|
m_curparam++; /* Prevent a leak */
|
||||||
|
|
||||||
if (!(sz_flags & SP_STRING_COPY))
|
if (!(sz_flags & SM_PARAM_STRING_COPY))
|
||||||
{
|
{
|
||||||
goto skip_localtostr;
|
goto skip_localtostr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sz_flags & SP_STRING_UTF8)
|
if (sz_flags & SM_PARAM_STRING_UTF8)
|
||||||
{
|
{
|
||||||
if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
|
if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,16 @@ CForwardManager g_Forwards;
|
|||||||
* X Push vararg strings (copyback tested = :TODO:)
|
* X Push vararg strings (copyback tested = :TODO:)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void CForwardManager::OnSourceModAllInitialized()
|
||||||
|
{
|
||||||
|
g_PluginSys.AddPluginsListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CForwardManager::OnSourceModShutdown()
|
||||||
|
{
|
||||||
|
g_PluginSys.RemovePluginsListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...)
|
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...)
|
||||||
{
|
{
|
||||||
CForward *fwd;
|
CForward *fwd;
|
||||||
@ -38,6 +48,11 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned
|
|||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
if (fwd)
|
||||||
|
{
|
||||||
|
m_managed.push_back(fwd);
|
||||||
|
}
|
||||||
|
|
||||||
return fwd;
|
return fwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,9 +66,43 @@ IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType
|
|||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
if (fwd)
|
||||||
|
{
|
||||||
|
m_unmanaged.push_back(fwd);
|
||||||
|
}
|
||||||
|
|
||||||
return fwd;
|
return fwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CForwardManager::OnPluginLoaded(IPlugin *plugin)
|
||||||
|
{
|
||||||
|
/* Attach any globally managed forwards */
|
||||||
|
List<CForward *>::iterator iter;
|
||||||
|
CForward *fwd;
|
||||||
|
|
||||||
|
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||||
|
{
|
||||||
|
fwd = (*iter);
|
||||||
|
IPluginFunction *pFunc = plugin->GetFunctionByName(fwd->GetForwardName());
|
||||||
|
if (pFunc)
|
||||||
|
{
|
||||||
|
fwd->AddFunction(pFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
|
||||||
|
{
|
||||||
|
List<CForward *>::iterator iter;
|
||||||
|
CForward *fwd;
|
||||||
|
|
||||||
|
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||||
|
{
|
||||||
|
fwd = (*iter);
|
||||||
|
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
|
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
|
||||||
{
|
{
|
||||||
List<CForward *>::iterator iter;
|
List<CForward *>::iterator iter;
|
||||||
@ -243,9 +292,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call the function and deal with the return value.
|
/* Call the function and deal with the return value. */
|
||||||
* :TODO: only pass reader if we know we have an array in the list
|
|
||||||
*/
|
|
||||||
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
@ -478,7 +525,7 @@ int CForward::PushString(const char *string)
|
|||||||
m_params[m_curparam].pushedas = Param_String;
|
m_params[m_curparam].pushedas = Param_String;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Int_PushString((cell_t *)string, strlen(string)+1, SP_STRING_COPY, 0);
|
_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
|
||||||
m_curparam++;
|
m_curparam++;
|
||||||
|
|
||||||
return SP_ERROR_NONE;
|
return SP_ERROR_NONE;
|
||||||
@ -521,7 +568,7 @@ void CForward::Cancel()
|
|||||||
|
|
||||||
bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
|
bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
|
||||||
{
|
{
|
||||||
IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx);
|
IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx);
|
||||||
if (!pPlugin)
|
if (!pPlugin)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -590,7 +637,7 @@ bool CForward::AddFunction(IPluginFunction *func)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//:TODO: eventually we will tell the plugin we're using it
|
//:TODO: eventually we will tell the plugin we're using it [?]
|
||||||
m_functions.push_back(func);
|
m_functions.push_back(func);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
|
#include "sourcemod.h"
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
@ -83,10 +84,13 @@ protected:
|
|||||||
int m_errstate;
|
int m_errstate;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CForwardManager : public IForwardManager
|
class CForwardManager :
|
||||||
|
public IForwardManager,
|
||||||
|
public IPluginsListener,
|
||||||
|
public SMGlobalClass
|
||||||
{
|
{
|
||||||
friend class CForward;
|
friend class CForward;
|
||||||
public:
|
public: //IForwardManager
|
||||||
virtual IForward *CreateForward(const char *name,
|
virtual IForward *CreateForward(const char *name,
|
||||||
ExecType et,
|
ExecType et,
|
||||||
unsigned int num_params,
|
unsigned int num_params,
|
||||||
@ -99,6 +103,12 @@ public:
|
|||||||
...);
|
...);
|
||||||
virtual IForward *FindForward(const char *name, IChangeableForward **ifchng);
|
virtual IForward *FindForward(const char *name, IChangeableForward **ifchng);
|
||||||
virtual void ReleaseForward(IForward *forward);
|
virtual void ReleaseForward(IForward *forward);
|
||||||
|
public: //IPluginsListener
|
||||||
|
virtual void OnPluginLoaded(IPlugin *plugin);
|
||||||
|
virtual void OnPluginUnloaded(IPlugin *plugin);
|
||||||
|
public: //SMGlobalClass
|
||||||
|
virtual void OnSourceModAllInitialized();
|
||||||
|
virtual void OnSourceModShutdown();
|
||||||
protected:
|
protected:
|
||||||
CForward *ForwardMake();
|
CForward *ForwardMake();
|
||||||
void ForwardFree(CForward *fwd);
|
void ForwardFree(CForward *fwd);
|
||||||
|
@ -85,7 +85,7 @@ PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, cons
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_PluginMngr.TestAliasMatch(name, filename))
|
if (!g_PluginSys.TestAliasMatch(name, filename))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,7 @@
|
|||||||
#include "sourcemod.h"
|
#include "sourcemod.h"
|
||||||
#include "CTextParsers.h"
|
#include "CTextParsers.h"
|
||||||
|
|
||||||
CPluginManager g_PluginMngr;
|
CPluginManager g_PluginSys;
|
||||||
|
|
||||||
CPluginManager::CPluginManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CPlugin::CPlugin(const char *file)
|
CPlugin::CPlugin(const char *file)
|
||||||
{
|
{
|
||||||
@ -54,7 +50,7 @@ CPlugin::~CPlugin()
|
|||||||
{
|
{
|
||||||
for (uint32_t i=0; i<m_plugin->info.publics_num; i++)
|
for (uint32_t i=0; i<m_plugin->info.publics_num; i++)
|
||||||
{
|
{
|
||||||
g_PluginMngr.ReleaseFunctionToPool(m_pub_funcs[i]);
|
g_PluginSys.ReleaseFunctionToPool(m_pub_funcs[i]);
|
||||||
}
|
}
|
||||||
delete [] m_pub_funcs;
|
delete [] m_pub_funcs;
|
||||||
m_pub_funcs = NULL;
|
m_pub_funcs = NULL;
|
||||||
@ -64,7 +60,7 @@ CPlugin::~CPlugin()
|
|||||||
{
|
{
|
||||||
for (unsigned int i=0; i<m_funcsnum; i++)
|
for (unsigned int i=0; i<m_funcsnum; i++)
|
||||||
{
|
{
|
||||||
g_PluginMngr.ReleaseFunctionToPool(m_priv_funcs[i]);
|
g_PluginSys.ReleaseFunctionToPool(m_priv_funcs[i]);
|
||||||
}
|
}
|
||||||
delete [] m_priv_funcs;
|
delete [] m_priv_funcs;
|
||||||
m_priv_funcs = NULL;
|
m_priv_funcs = NULL;
|
||||||
@ -196,6 +192,8 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength)
|
|||||||
m_pub_funcs = NULL;
|
m_pub_funcs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_status = Plugin_Created;
|
||||||
|
|
||||||
UpdateInfo();
|
UpdateInfo();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -226,7 +224,7 @@ IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
|
|||||||
pFunc = m_pub_funcs[func_id];
|
pFunc = m_pub_funcs[func_id];
|
||||||
if (!pFunc)
|
if (!pFunc)
|
||||||
{
|
{
|
||||||
pFunc = g_PluginMngr.GetFunctionFromPool(save, this);
|
pFunc = g_PluginSys.GetFunctionFromPool(save, this);
|
||||||
m_pub_funcs[func_id] = pFunc;
|
m_pub_funcs[func_id] = pFunc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -239,7 +237,7 @@ IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
|
|||||||
pFunc = m_priv_funcs[func_id];
|
pFunc = m_priv_funcs[func_id];
|
||||||
if (!pFunc)
|
if (!pFunc)
|
||||||
{
|
{
|
||||||
pFunc = g_PluginMngr.GetFunctionFromPool(save, this);
|
pFunc = g_PluginSys.GetFunctionFromPool(save, this);
|
||||||
m_priv_funcs[func_id] = pFunc;
|
m_priv_funcs[func_id] = pFunc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,7 +262,7 @@ IPluginFunction *CPlugin::GetFunctionByName(const char *public_name)
|
|||||||
base->GetPublicByIndex(index, &pub);
|
base->GetPublicByIndex(index, &pub);
|
||||||
if (pub)
|
if (pub)
|
||||||
{
|
{
|
||||||
pFunc = g_PluginMngr.GetFunctionFromPool(pub->funcid, this);
|
pFunc = g_PluginSys.GetFunctionFromPool(pub->funcid, this);
|
||||||
m_pub_funcs[index] = pFunc;
|
m_pub_funcs[index] = pFunc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,6 +305,77 @@ void CPlugin::UpdateInfo()
|
|||||||
m_info.version = m_info.version ? m_info.version : "";
|
m_info.version = m_info.version ? m_info.version : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPlugin::Call_OnPluginInit()
|
||||||
|
{
|
||||||
|
if (m_status != Plugin_Loaded)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_status = Plugin_Running;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
cell_t result;
|
||||||
|
IPluginFunction *pFunction = GetFunctionByName("OnPluginInit");
|
||||||
|
if (!pFunction)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* :TODO: push our own handle */
|
||||||
|
pFunction->PushCell(0);
|
||||||
|
if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
/* :TODO: log into debugger instead */
|
||||||
|
SetErrorState(Plugin_Error, "Runtime error %d", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
|
||||||
|
{
|
||||||
|
if (m_status != Plugin_Created)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
error = m_errormsg;
|
||||||
|
maxlength = sizeof(m_errormsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int err;
|
||||||
|
cell_t result;
|
||||||
|
IPluginFunction *pFunction = GetFunctionByName("AskPluginLoad");
|
||||||
|
|
||||||
|
if (!pFunction)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pFunction->PushCell(0); //:TODO: handle to ourself
|
||||||
|
pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
|
||||||
|
pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
|
||||||
|
pFunction->PushCell(maxlength);
|
||||||
|
if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
/* :TODO: debugging system */
|
||||||
|
snprintf(error, maxlength, "Plugin load returned run time error %d", err);
|
||||||
|
m_status = Plugin_Error;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
m_status = Plugin_Error;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_status = Plugin_Loaded;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const sp_plugin_t *CPlugin::GetPluginStructure() const
|
const sp_plugin_t *CPlugin::GetPluginStructure() const
|
||||||
{
|
{
|
||||||
return m_plugin;
|
return m_plugin;
|
||||||
@ -397,7 +466,7 @@ void CPluginManager::CPluginIterator::NextPlugin()
|
|||||||
|
|
||||||
void CPluginManager::CPluginIterator::Release()
|
void CPluginManager::CPluginIterator::Release()
|
||||||
{
|
{
|
||||||
g_PluginMngr.ReleaseIterator(this);
|
g_PluginSys.ReleaseIterator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
CPluginManager::CPluginIterator::~CPluginIterator()
|
CPluginManager::CPluginIterator::~CPluginIterator()
|
||||||
@ -413,7 +482,20 @@ void CPluginManager::CPluginIterator::Reset()
|
|||||||
* PLUGIN MANAGER *
|
* PLUGIN MANAGER *
|
||||||
******************/
|
******************/
|
||||||
|
|
||||||
void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedir)
|
CPluginManager::CPluginManager()
|
||||||
|
{
|
||||||
|
m_LoadLookup = sm_trie_create();
|
||||||
|
m_AllPluginsLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPluginManager::~CPluginManager()
|
||||||
|
{
|
||||||
|
//:TODO: we need a good way to free what we're holding
|
||||||
|
sm_trie_destroy(m_LoadLookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CPluginManager::LoadAll_FirstPass( const char *config, const char *basedir )
|
||||||
{
|
{
|
||||||
/* First read in the database of plugin settings */
|
/* First read in the database of plugin settings */
|
||||||
SMCParseError err;
|
SMCParseError err;
|
||||||
@ -467,29 +549,51 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa
|
|||||||
} else if (dir->IsEntryFile()) {
|
} else if (dir->IsEntryFile()) {
|
||||||
const char *name = dir->GetEntryName();
|
const char *name = dir->GetEntryName();
|
||||||
size_t len = strlen(name);
|
size_t len = strlen(name);
|
||||||
if (len < 4
|
if (len >= 4
|
||||||
|| strcmp(&name[len-4], ".smx") != 0)
|
&& strcmp(&name[len-4], ".smx") == 0)
|
||||||
{
|
{
|
||||||
continue;
|
/* If the filename matches, load the plugin */
|
||||||
|
char plugin[PLATFORM_MAX_PATH+1];
|
||||||
|
if (localpath == NULL)
|
||||||
|
{
|
||||||
|
snprintf(plugin, sizeof(plugin), "%s", name);
|
||||||
|
} else {
|
||||||
|
g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
|
||||||
|
}
|
||||||
|
LoadAutoPlugin(plugin);
|
||||||
}
|
}
|
||||||
/* If the filename matches, load the plugin */
|
|
||||||
char plugin[PLATFORM_MAX_PATH+1];
|
|
||||||
if (localpath == NULL)
|
|
||||||
{
|
|
||||||
snprintf(plugin, sizeof(plugin), "%s", name);
|
|
||||||
} else {
|
|
||||||
g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
|
|
||||||
}
|
|
||||||
LoadAutoPlugin(plugin);
|
|
||||||
}
|
}
|
||||||
dir->NextEntry();
|
dir->NextEntry();
|
||||||
}
|
}
|
||||||
g_LibSys.CloseDirectory(dir);
|
g_LibSys.CloseDirectory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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()
|
||||||
void CPluginManager::LoadAutoPlugin(const char *file)
|
void CPluginManager::LoadAutoPlugin(const char *file)
|
||||||
{
|
{
|
||||||
CPlugin *pPlugin = CPlugin::CreatePlugin(file, NULL, 0);
|
/**
|
||||||
|
* Does this plugin already exist?
|
||||||
|
*/
|
||||||
|
CPlugin *pPlugin;
|
||||||
|
if (sm_trie_retrieve(m_LoadLookup, file, (void **)&pPlugin))
|
||||||
|
{
|
||||||
|
/* First check the type */
|
||||||
|
PluginType type = pPlugin->GetType();
|
||||||
|
if (type == PluginType_Private
|
||||||
|
|| type == PluginType_Global)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Check to see if we should try reloading it */
|
||||||
|
if (pPlugin->GetStatus() == Plugin_BadLoad
|
||||||
|
|| pPlugin->GetStatus() == Plugin_Error)
|
||||||
|
{
|
||||||
|
UnloadPlugin(pPlugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pPlugin = CPlugin::CreatePlugin(file, NULL, 0);
|
||||||
|
|
||||||
assert(pPlugin != NULL);
|
assert(pPlugin != NULL);
|
||||||
|
|
||||||
@ -539,12 +643,36 @@ void CPluginManager::LoadAutoPlugin(const char *file)
|
|||||||
co = NULL;
|
co = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitAndAddPlugin(pPlugin);
|
/* We don't care about the return value */
|
||||||
|
if (pPlugin->GetStatus() == Plugin_Created)
|
||||||
|
{
|
||||||
|
AddCoreNativesToPlugin(pPlugin);
|
||||||
|
pPlugin->Call_AskPluginLoad(NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddPlugin(pPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
|
IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
|
||||||
{
|
{
|
||||||
CPlugin *pPlugin = CPlugin::CreatePlugin(path, error, err_max);
|
/* See if this plugin is already loaded... reformat to get sep chars right */
|
||||||
|
char checkpath[PLATFORM_MAX_PATH+1];
|
||||||
|
g_LibSys.PathFormat(checkpath, sizeof(checkpath), "%s", path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In manually loading a plugin, any sort of load error causes a deletion.
|
||||||
|
* This is because it's assumed manually loaded plugins will not be managed.
|
||||||
|
* For managed plugins, we need the UI to report them properly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CPlugin *pPlugin;
|
||||||
|
if (sm_trie_retrieve(m_LoadLookup, checkpath, (void **)&pPlugin))
|
||||||
|
{
|
||||||
|
snprintf(error, err_max, "Plugin file is alread loaded");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPlugin = CPlugin::CreatePlugin(path, error, err_max);
|
||||||
|
|
||||||
if (!pPlugin)
|
if (!pPlugin)
|
||||||
{
|
{
|
||||||
@ -568,14 +696,24 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ
|
|||||||
|
|
||||||
pPlugin->m_type = type;
|
pPlugin->m_type = type;
|
||||||
|
|
||||||
InitAndAddPlugin(pPlugin);
|
AddCoreNativesToPlugin(pPlugin);
|
||||||
|
|
||||||
|
/* Finally, ask the plugin if it wants to be loaded */
|
||||||
|
if (!pPlugin->Call_AskPluginLoad(error, err_max))
|
||||||
|
{
|
||||||
|
delete pPlugin;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddPlugin(pPlugin);
|
||||||
|
|
||||||
return pPlugin;
|
return pPlugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin)
|
void CPluginManager::AddPlugin(CPlugin *pPlugin)
|
||||||
{
|
{
|
||||||
m_plugins.push_back(pPlugin);
|
m_plugins.push_back(pPlugin);
|
||||||
|
sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
|
||||||
|
|
||||||
List<IPluginsListener *>::iterator iter;
|
List<IPluginsListener *>::iterator iter;
|
||||||
IPluginsListener *pListener;
|
IPluginsListener *pListener;
|
||||||
@ -585,7 +723,43 @@ void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin)
|
|||||||
pListener->OnPluginCreated(pPlugin);
|
pListener->OnPluginCreated(pPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :TODO: a lot more... */
|
/* If the second pass was already completed, we have to run the pass on this plugin */
|
||||||
|
if (m_AllPluginsLoaded && pPlugin->GetStatus() == Plugin_Loaded)
|
||||||
|
{
|
||||||
|
RunSecondPass(pPlugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPluginManager::RunSecondPass(CPlugin *pPlugin)
|
||||||
|
{
|
||||||
|
/* Tell this plugin to finish initializing itself */
|
||||||
|
pPlugin->Call_OnPluginInit();
|
||||||
|
|
||||||
|
/* Finish by telling all listeners */
|
||||||
|
List<IPluginsListener *>::iterator iter;
|
||||||
|
IPluginsListener *pListener;
|
||||||
|
for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
|
||||||
|
{
|
||||||
|
pListener = (*iter);
|
||||||
|
pListener->OnPluginLoaded(pPlugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
|
||||||
|
{
|
||||||
|
List<sp_nativeinfo_t *>::iterator iter;
|
||||||
|
|
||||||
|
for (iter=m_natives.begin(); iter!=m_natives.end(); iter++)
|
||||||
|
{
|
||||||
|
sp_nativeinfo_t *natives = (*iter);
|
||||||
|
IPluginContext *ctx = pPlugin->GetBaseContext();
|
||||||
|
unsigned int i=0;
|
||||||
|
/* Attempt to bind every native! */
|
||||||
|
while (natives[i].func != NULL)
|
||||||
|
{
|
||||||
|
ctx->BindNative(&natives[i++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
||||||
@ -601,6 +775,9 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
|||||||
pListener = (*iter);
|
pListener = (*iter);
|
||||||
pListener->OnPluginDestroyed(pPlugin);
|
pListener->OnPluginDestroyed(pPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_plugins.remove(plugin);
|
||||||
|
sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
|
||||||
|
|
||||||
delete pPlugin;
|
delete pPlugin;
|
||||||
|
|
||||||
@ -877,7 +1054,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPluginManager::~CPluginManager()
|
bool CPluginManager::IsLateLoadTime()
|
||||||
{
|
{
|
||||||
//:TODO: we need a good way to free what we're holding
|
return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap());
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||||
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include "CFunction.h"
|
#include "CFunction.h"
|
||||||
#include "PluginInfoDatabase.h"
|
#include "PluginInfoDatabase.h"
|
||||||
|
#include "sm_trie.h"
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
@ -29,6 +31,31 @@ using namespace SourceHook;
|
|||||||
* plugins that failed to load from the internal loading mechanism are always tracked. This
|
* plugins that failed to load from the internal loading mechanism are always tracked. This
|
||||||
* allows users to see which automatically loaded plugins failed, and makes the interface a bit
|
* allows users to see which automatically loaded plugins failed, and makes the interface a bit
|
||||||
* more flexible.
|
* more flexible.
|
||||||
|
*
|
||||||
|
* Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
|
||||||
|
* for execution. SourceMod is a two pass system, and even though the second pass is not implemented
|
||||||
|
* yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
|
||||||
|
* implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
|
||||||
|
*
|
||||||
|
* The two pass loading mechanism is described below. Modules/natives are not implemented yet.
|
||||||
|
* PASS ONE: All loadable plugins are found and have the following steps performed:
|
||||||
|
* 1. Loading and compilation is attempted.
|
||||||
|
* 2. If successful, all natives from Core are added.
|
||||||
|
* 3. OnPluginLoad() is called.
|
||||||
|
* 4. If failed, any user natives are scrapped and the process halts here.
|
||||||
|
* 5. If successful, the plugin is ready for Pass 2.
|
||||||
|
* INTERMEDIATE:
|
||||||
|
* 1. All forced modules are loaded.
|
||||||
|
* PASS TWO: All loaded plugins are found and have these steps performed:
|
||||||
|
* 1. Any modules referenced in the plugin that are not already loaded, are loaded.
|
||||||
|
* 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
|
||||||
|
* 3. If any natives are unresolved, check if they are found in the user-natives pool.
|
||||||
|
* 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
|
||||||
|
* 5. If the filter fails, the plugin is marked as failed.
|
||||||
|
* 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
|
||||||
|
* Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
|
||||||
|
* PASS THREE (not a real pass):
|
||||||
|
* 7. Once all plugins are deemed to be loaded, OnPluginInit() is called
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SM_CONTEXTVAR_MYSELF 0
|
#define SM_CONTEXTVAR_MYSELF 0
|
||||||
@ -88,6 +115,24 @@ public:
|
|||||||
* Sets an error state on the plugin
|
* Sets an error state on the plugin
|
||||||
*/
|
*/
|
||||||
void SetErrorState(PluginStatus status, const char *error_fmt, ...);
|
void SetErrorState(PluginStatus status, const char *error_fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the OnPluginLoad function, and sets any failed states if necessary.
|
||||||
|
* NOTE: Valid pre-states are: Plugin_Created
|
||||||
|
* If validated, plugin state is changed to Plugin_Loaded
|
||||||
|
*
|
||||||
|
* If the error buffer is NULL, the error message is cached locally.
|
||||||
|
*/
|
||||||
|
bool Call_AskPluginLoad(char *error, size_t maxlength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the OnPluginInit function.
|
||||||
|
* NOTE: Valid pre-states are: Plugin_Created
|
||||||
|
* NOTE: Pre-state will be changed to Plugin_Running
|
||||||
|
*/
|
||||||
|
void Call_OnPluginInit();
|
||||||
|
public:
|
||||||
|
time_t HasUpdatedFile();
|
||||||
protected:
|
protected:
|
||||||
void UpdateInfo();
|
void UpdateInfo();
|
||||||
private:
|
private:
|
||||||
@ -102,6 +147,7 @@ private:
|
|||||||
CFunction **m_priv_funcs;
|
CFunction **m_priv_funcs;
|
||||||
CFunction **m_pub_funcs;
|
CFunction **m_pub_funcs;
|
||||||
char m_errormsg[256];
|
char m_errormsg[256];
|
||||||
|
time_t m_LastAccess;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPluginManager : public IPluginManager
|
class CPluginManager : public IPluginManager
|
||||||
@ -142,9 +188,14 @@ public: //IPluginManager
|
|||||||
virtual void RemovePluginsListener(IPluginsListener *listener);
|
virtual void RemovePluginsListener(IPluginsListener *listener);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Refreshes and loads plugins, usually used on mapchange
|
* Loads all plugins not yet loaded
|
||||||
*/
|
*/
|
||||||
void RefreshOrLoadPlugins(const char *config, const char *basedir);
|
void LoadAll_FirstPass(const char *config, const char *basedir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the second loading pass for all plugins
|
||||||
|
*/
|
||||||
|
void LoadAll_SecondPass();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a plugin file mask against a local folder.
|
* Tests a plugin file mask against a local folder.
|
||||||
@ -156,6 +207,16 @@ public:
|
|||||||
* Wildcards are allowed in the filename.
|
* Wildcards are allowed in the filename.
|
||||||
*/
|
*/
|
||||||
bool TestAliasMatch(const char *alias, const char *localdir);
|
bool TestAliasMatch(const char *alias, const char *localdir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers natives in core itself ONLY.
|
||||||
|
*/
|
||||||
|
void RegisterGlobalNatives(sp_nativeinfo_t *info[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether anything loaded will be a late load.
|
||||||
|
*/
|
||||||
|
bool IsLateLoadTime();
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Recursively loads all plugins in the given directory.
|
* Recursively loads all plugins in the given directory.
|
||||||
@ -169,9 +230,19 @@ private:
|
|||||||
void LoadAutoPlugin(const char *file);
|
void LoadAutoPlugin(const char *file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds and initializes a plugin object. This is wrapped by LoadPlugin functions.
|
* Adds a plugin object. This is wrapped by LoadPlugin functions.
|
||||||
*/
|
*/
|
||||||
void InitAndAddPlugin(CPlugin *pPlugin);
|
void AddPlugin(CPlugin *pPlugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the second loading pass on a plugin.
|
||||||
|
*/
|
||||||
|
void RunSecondPass(CPlugin *pPlugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds any globally registered natives to a plugin
|
||||||
|
*/
|
||||||
|
void AddCoreNativesToPlugin(CPlugin *pPlugin);
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Caching internal objects
|
* Caching internal objects
|
||||||
@ -182,11 +253,14 @@ protected:
|
|||||||
private:
|
private:
|
||||||
List<IPluginsListener *> m_listeners;
|
List<IPluginsListener *> m_listeners;
|
||||||
List<IPlugin *> m_plugins;
|
List<IPlugin *> m_plugins;
|
||||||
|
List<sp_nativeinfo_t *> m_natives;
|
||||||
CStack<CPluginManager::CPluginIterator *> m_iters;
|
CStack<CPluginManager::CPluginIterator *> m_iters;
|
||||||
CStack<CFunction *> m_funcpool;
|
CStack<CFunction *> m_funcpool;
|
||||||
CPluginInfoDatabase m_PluginInfo;
|
CPluginInfoDatabase m_PluginInfo;
|
||||||
|
Trie *m_LoadLookup;
|
||||||
|
bool m_AllPluginsLoaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPluginManager g_PluginMngr;
|
extern CPluginManager g_PluginSys;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||||
|
Loading…
Reference in New Issue
Block a user