!Added MOSTLY UNTESTED plugin loading
Fixed a match bug in TestAliasMatch() Removed pointless implementation of context switching in CPlugin Redesigned how CPlugins are allocated, deallocated, and instantiated. Added a basedir function so all code can reference relative paths. This may be redesigned. Various other changes --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40214
This commit is contained in:
parent
dc60ae49de
commit
23a91de75c
@ -33,8 +33,8 @@ namespace SourceMod
|
|||||||
Plugin_Running=0, /* Plugin is running */
|
Plugin_Running=0, /* Plugin is running */
|
||||||
Plugin_Loaded, /* Plugin is loaded but not initialized */
|
Plugin_Loaded, /* Plugin is loaded but not initialized */
|
||||||
Plugin_Paused, /* Plugin is paused */
|
Plugin_Paused, /* Plugin is paused */
|
||||||
Plugin_Stopped, /* Plugin is paused for map changes, too */
|
|
||||||
Plugin_Error, /* Plugin has a blocking error */
|
Plugin_Error, /* Plugin has a blocking error */
|
||||||
|
Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */
|
||||||
Plugin_BadLoad, /* Plugin failed to load */
|
Plugin_BadLoad, /* Plugin failed to load */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include "sourcemod.h"
|
#include "sourcemod.h"
|
||||||
|
|
||||||
SourceMod_Core g_SourceMod_Core;
|
SourceMod_Core g_SourceMod_Core;
|
||||||
|
IVEngineServer *engine = NULL;
|
||||||
|
IServerGameDLL *gamedll = NULL;
|
||||||
|
|
||||||
PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core);
|
PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core);
|
||||||
|
|
||||||
@ -11,6 +13,8 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen
|
|||||||
{
|
{
|
||||||
PLUGIN_SAVEVARS();
|
PLUGIN_SAVEVARS();
|
||||||
|
|
||||||
|
GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||||
|
|
||||||
return g_SourceMod.InitializeSourceMod(error, maxlen, late);
|
return g_SourceMod.InitializeSourceMod(error, maxlen, late);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define _INCLUDE_SOURCEMOD_MM_API_H_
|
#define _INCLUDE_SOURCEMOD_MM_API_H_
|
||||||
|
|
||||||
#include <ISmmPlugin.h>
|
#include <ISmmPlugin.h>
|
||||||
|
#include <eiface.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file Contains wrappers around required Metamod:Source API exports
|
* @file Contains wrappers around required Metamod:Source API exports
|
||||||
@ -27,6 +28,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern SourceMod_Core g_SourceMod_Core;
|
extern SourceMod_Core g_SourceMod_Core;
|
||||||
|
extern IVEngineServer *engine;
|
||||||
|
extern IServerGameDLL *gamedll;
|
||||||
|
|
||||||
PLUGIN_GLOBALVARS();
|
PLUGIN_GLOBALVARS();
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
#include "ForwardSys.h"
|
#include "ForwardSys.h"
|
||||||
|
|
||||||
|
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
|
||||||
|
|
||||||
SourcePawnEngine g_SourcePawn;
|
SourcePawnEngine g_SourcePawn;
|
||||||
SourceModBase g_SourceMod;
|
SourceModBase g_SourceMod;
|
||||||
|
|
||||||
@ -31,16 +33,21 @@ void ShutdownJIT()
|
|||||||
g_pJIT->CloseLibrary();
|
g_pJIT->CloseLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceModBase::SourceModBase()
|
||||||
|
{
|
||||||
|
m_IsMapLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
|
bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
|
||||||
{
|
{
|
||||||
//:TODO: we need a localinfo system!
|
|
||||||
g_BaseDir.assign(g_SMAPI->GetBaseDir());
|
g_BaseDir.assign(g_SMAPI->GetBaseDir());
|
||||||
|
g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str());
|
||||||
|
|
||||||
/* Attempt to load the JIT! */
|
/* Attempt to load the JIT! */
|
||||||
char file[PLATFORM_MAX_PATH];
|
char file[PLATFORM_MAX_PATH];
|
||||||
char myerror[255];
|
char myerror[255];
|
||||||
g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/bin/sourcepawn.jit.x86.%s",
|
g_SMAPI->PathFormat(file, sizeof(file), "%s/bin/sourcepawn.jit.x86.%s",
|
||||||
g_BaseDir.c_str(),
|
GetSMBaseDir(),
|
||||||
PLATFORM_LIB_EXT
|
PLATFORM_LIB_EXT
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -112,21 +119,49 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_SMAPI->PathFormat(file, sizeof(file), "%s/addons/sourcemod/plugins/test.smx", g_BaseDir.c_str());
|
StartSourceMod(late);
|
||||||
IPlugin *pPlugin = g_PluginMngr.LoadPlugin(file, false, PluginType_Global, error, err_max);
|
|
||||||
IPluginFunction *func = pPlugin->GetFunctionByName("Test");
|
|
||||||
IPluginFunction *func2 = pPlugin->GetFunctionByName("Test2");
|
|
||||||
cell_t result = 2;
|
|
||||||
cell_t val = 6;
|
|
||||||
ParamType types[] = {Param_Cell, Param_CellByRef};
|
|
||||||
va_list ap = va_start(ap, late);
|
|
||||||
CForward *fwd = CForward::CreateForward(NULL, ET_Custom, 2, types, ap);
|
|
||||||
fwd->AddFunction(func);
|
|
||||||
fwd->AddFunction(func2);
|
|
||||||
fwd->PushCell(1);
|
|
||||||
fwd->PushCellByRef(&val, 0);
|
|
||||||
fwd->Execute(&result, NULL);
|
|
||||||
g_PluginMngr.UnloadPlugin(pPlugin);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SourceModBase::StartSourceMod(bool late)
|
||||||
|
{
|
||||||
|
/* First initialize the global hooks we need */
|
||||||
|
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
|
||||||
|
|
||||||
|
/* If we're late, automatically load plugins now */
|
||||||
|
DoGlobalPluginLoads();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
|
||||||
|
{
|
||||||
|
m_IsMapLoading = true;
|
||||||
|
|
||||||
|
DoGlobalPluginLoads();
|
||||||
|
|
||||||
|
m_IsMapLoading = false;
|
||||||
|
|
||||||
|
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceModBase::DoGlobalPluginLoads()
|
||||||
|
{
|
||||||
|
char config_path[PLATFORM_MAX_PATH];
|
||||||
|
char plugins_path[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
|
g_SMAPI->PathFormat(config_path,
|
||||||
|
sizeof(config_path),
|
||||||
|
"%s/configs/plugin_settings.cfg",
|
||||||
|
GetSMBaseDir());
|
||||||
|
g_SMAPI->PathFormat(plugins_path,
|
||||||
|
sizeof(plugins_path),
|
||||||
|
"%s/plugins",
|
||||||
|
GetSMBaseDir());
|
||||||
|
|
||||||
|
g_PluginMngr.RefreshOrLoadPlugins(config_path, plugins_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *SourceModBase::GetSMBaseDir()
|
||||||
|
{
|
||||||
|
return m_SMBaseDir;
|
||||||
|
}
|
||||||
|
@ -9,11 +9,42 @@
|
|||||||
|
|
||||||
class SourceModBase
|
class SourceModBase
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
SourceModBase();
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Initializes SourceMod, or returns an error on failure.
|
* @brief Initializes SourceMod, or returns an error on failure.
|
||||||
*/
|
*/
|
||||||
bool InitializeSourceMod(char *error, size_t err_max, bool late);
|
bool InitializeSourceMod(char *error, size_t err_max, bool late);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts everything SourceMod needs to run
|
||||||
|
*/
|
||||||
|
void StartSourceMod(bool late);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Map change hook
|
||||||
|
*/
|
||||||
|
bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns whether or not a mapload is in progress
|
||||||
|
*/
|
||||||
|
bool IsMapLoading();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the base SourceMod folder.
|
||||||
|
*/
|
||||||
|
const char *GetSMBaseDir();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Loading plugins
|
||||||
|
*/
|
||||||
|
void DoGlobalPluginLoads();
|
||||||
|
private:
|
||||||
|
char m_SMBaseDir[PLATFORM_MAX_PATH+1];
|
||||||
|
bool m_IsMapLoading;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SourceModBase g_SourceMod;
|
extern SourceModBase g_SourceMod;
|
||||||
|
@ -15,7 +15,7 @@ void CFunction::Set(funcid_t funcid, CPlugin *plugin)
|
|||||||
|
|
||||||
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
|
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
|
||||||
{
|
{
|
||||||
IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
|
IPluginContext *ctx = m_pPlugin->m_ctx.base;
|
||||||
|
|
||||||
while (num_params--)
|
while (num_params--)
|
||||||
{
|
{
|
||||||
@ -79,7 +79,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr
|
|||||||
return SetError(SP_ERROR_PARAMS_MAX);
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
|
IPluginContext *ctx = m_pPlugin->m_ctx.base;
|
||||||
ParamInfo *info = &m_info[m_curparam];
|
ParamInfo *info = &m_info[m_curparam];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_
|
|||||||
return SetError(SP_ERROR_PARAMS_MAX);
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPluginContext *base = m_pPlugin->m_ctx_current.base;
|
IPluginContext *base = m_pPlugin->m_ctx.base;
|
||||||
ParamInfo *info = &m_info[m_curparam];
|
ParamInfo *info = &m_info[m_curparam];
|
||||||
size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
|
size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
|
||||||
int err;
|
int err;
|
||||||
@ -174,7 +174,7 @@ void CFunction::Cancel()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPluginContext *base = m_pPlugin->m_ctx_current.base;
|
IPluginContext *base = m_pPlugin->m_ctx.base;
|
||||||
|
|
||||||
while (m_curparam--)
|
while (m_curparam--)
|
||||||
{
|
{
|
||||||
@ -217,7 +217,7 @@ int CFunction::Execute(cell_t *result)
|
|||||||
docopies = false;
|
docopies = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPluginContext *base = m_pPlugin->m_ctx_current.base;
|
IPluginContext *base = m_pPlugin->m_ctx.base;
|
||||||
|
|
||||||
while (numparams--)
|
while (numparams--)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
#include "LibrarySys.h"
|
#include "LibrarySys.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
|
#include "sourcemod.h"
|
||||||
#include "CTextParsers.h"
|
#include "CTextParsers.h"
|
||||||
|
|
||||||
CPluginManager g_PluginMngr;
|
CPluginManager g_PluginMngr;
|
||||||
@ -10,86 +11,204 @@ CPluginManager::CPluginManager()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CPlugin *CPlugin::CreatePlugin(const char *file,
|
CPlugin::CPlugin(const char *file)
|
||||||
bool debug_default,
|
|
||||||
PluginType type,
|
|
||||||
char *error,
|
|
||||||
size_t maxlen)
|
|
||||||
{
|
{
|
||||||
static unsigned int MySerial = 0;
|
static int MySerial = 0;
|
||||||
FILE *fp = fopen(file, "rb");
|
|
||||||
|
m_type = PluginType_Private;
|
||||||
|
m_status = Plugin_Uncompiled;
|
||||||
|
m_serial = ++MySerial;
|
||||||
|
m_plugin = NULL;
|
||||||
|
m_funcsnum = 0;
|
||||||
|
m_priv_funcs = NULL;
|
||||||
|
m_pub_funcs = NULL;
|
||||||
|
m_errormsg[256] = '\0';
|
||||||
|
snprintf(m_filename, sizeof(m_filename), "%s", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPlugin::~CPlugin()
|
||||||
|
{
|
||||||
|
if (m_ctx.base)
|
||||||
|
{
|
||||||
|
g_pSourcePawn->FreeBaseContext(m_ctx.base);
|
||||||
|
m_ctx.base = NULL;
|
||||||
|
}
|
||||||
|
if (m_ctx.ctx)
|
||||||
|
{
|
||||||
|
m_ctx.vm->FreeContext(m_ctx.ctx);
|
||||||
|
m_ctx.ctx = NULL;
|
||||||
|
}
|
||||||
|
if (m_ctx.co)
|
||||||
|
{
|
||||||
|
m_ctx.vm->AbortCompilation(m_ctx.co);
|
||||||
|
m_ctx.co = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_plugin)
|
||||||
|
{
|
||||||
|
g_pSourcePawn->FreeFromMemory(m_plugin);
|
||||||
|
m_plugin = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pub_funcs)
|
||||||
|
{
|
||||||
|
for (uint32_t i=0; i<m_plugin->info.publics_num; i++)
|
||||||
|
{
|
||||||
|
g_PluginMngr.ReleaseFunctionToPool(m_pub_funcs[i]);
|
||||||
|
}
|
||||||
|
delete [] m_pub_funcs;
|
||||||
|
m_pub_funcs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_priv_funcs)
|
||||||
|
{
|
||||||
|
for (unsigned int i=0; i<m_funcsnum; i++)
|
||||||
|
{
|
||||||
|
g_PluginMngr.ReleaseFunctionToPool(m_priv_funcs[i]);
|
||||||
|
}
|
||||||
|
delete [] m_priv_funcs;
|
||||||
|
m_priv_funcs = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
|
||||||
|
{
|
||||||
|
char fullpath[PLATFORM_MAX_PATH+1];
|
||||||
|
g_LibSys.PathFormat(fullpath, sizeof(fullpath), "%s/plugins/%s", g_SourceMod.GetSMBaseDir(), file);
|
||||||
|
FILE *fp = fopen(fullpath, "rb");
|
||||||
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
snprintf(error, maxlen, "Could not open file");
|
if (error)
|
||||||
return NULL;
|
{
|
||||||
|
snprintf(error, maxlength, "Unable to open file");
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
CPlugin *pPlugin = new CPlugin(file);
|
||||||
|
snprintf(pPlugin->m_errormsg, sizeof(pPlugin->m_errormsg), "Unable to open file");
|
||||||
|
pPlugin->m_status = Plugin_BadLoad;
|
||||||
|
return pPlugin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err);
|
sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err);
|
||||||
if (pl == NULL)
|
if (pl == NULL)
|
||||||
{
|
{
|
||||||
snprintf(error, maxlen, "Could not load plugin, error %d", err);
|
fclose(fp);
|
||||||
return NULL;
|
if (error)
|
||||||
|
{
|
||||||
|
snprintf(error, maxlength, "Error %d while parsing plugin", err);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
CPlugin *pPlugin = new CPlugin(file);
|
||||||
|
snprintf(pPlugin->m_errormsg, sizeof(pPlugin->m_errormsg), "Error %d while parsing plugin", err);
|
||||||
|
pPlugin->m_status = Plugin_BadLoad;
|
||||||
|
return pPlugin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
ICompilation *co = g_pVM->StartCompilation(pl);
|
CPlugin *pPlugin = new CPlugin(file);
|
||||||
|
pPlugin->m_plugin = pl;
|
||||||
|
return pPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
if (debug_default)
|
ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm)
|
||||||
|
{
|
||||||
|
if (!m_plugin)
|
||||||
{
|
{
|
||||||
if (!g_pVM->SetCompilationOption(co, "debug", "1"))
|
|
||||||
{
|
|
||||||
g_pVM->AbortCompilation(co);
|
|
||||||
snprintf(error, maxlen, "Could not set plugin to debug mode");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sp_context_t *ctx = g_pVM->CompileToContext(co, &err);
|
|
||||||
if (ctx == NULL)
|
|
||||||
{
|
|
||||||
snprintf(error, maxlen, "Plugin failed to load, JIT error: %d", err);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPluginContext *base = g_pSourcePawn->CreateBaseContext(ctx);
|
/* :NOTICE: We will eventually need to change these natives
|
||||||
CPlugin *pPlugin = new CPlugin;
|
* for swapping in new contexts
|
||||||
|
*/
|
||||||
snprintf(pPlugin->m_filename, PLATFORM_MAX_PATH, "%s", file);
|
if (m_ctx.co || m_ctx.ctx)
|
||||||
pPlugin->m_debugging = debug_default;
|
|
||||||
pPlugin->m_ctx_current.base = base;
|
|
||||||
pPlugin->m_ctx_current.ctx = ctx;
|
|
||||||
pPlugin->m_type = type;
|
|
||||||
pPlugin->m_serial = ++MySerial;
|
|
||||||
pPlugin->m_status = Plugin_Loaded;
|
|
||||||
pPlugin->m_plugin = pl;
|
|
||||||
|
|
||||||
pPlugin->UpdateInfo();
|
|
||||||
|
|
||||||
ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin;
|
|
||||||
|
|
||||||
/* Build function information loosely */
|
|
||||||
pPlugin->m_funcsnum = g_pVM->FunctionCount(ctx);
|
|
||||||
|
|
||||||
if (pPlugin->m_funcsnum)
|
|
||||||
{
|
{
|
||||||
pPlugin->m_priv_funcs = new CFunction *[pPlugin->m_funcsnum];
|
return NULL;
|
||||||
memset(pPlugin->m_priv_funcs, 0, sizeof(CFunction *) * pPlugin->m_funcsnum);
|
|
||||||
} else {
|
|
||||||
pPlugin->m_priv_funcs = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pl->info.publics_num)
|
m_status = Plugin_Uncompiled;
|
||||||
|
|
||||||
|
m_ctx.vm = vm;
|
||||||
|
m_ctx.co = vm->StartCompilation(m_plugin);
|
||||||
|
|
||||||
|
return m_ctx.co;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlugin::CancelMyCompile()
|
||||||
|
{
|
||||||
|
if (!m_ctx.co)
|
||||||
{
|
{
|
||||||
pPlugin->m_pub_funcs = new CFunction *[pl->info.publics_num];
|
return;
|
||||||
memset(pPlugin->m_pub_funcs, 0, sizeof(CFunction *) * pl->info.publics_num);
|
|
||||||
} else {
|
|
||||||
pPlugin->m_pub_funcs = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pPlugin;
|
m_ctx.vm->AbortCompilation(m_ctx.co);
|
||||||
|
m_ctx.co = NULL;
|
||||||
|
m_ctx.vm = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPlugin::FinishMyCompile(char *error, size_t maxlength)
|
||||||
|
{
|
||||||
|
if (!m_ctx.co)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int err;
|
||||||
|
m_ctx.ctx = m_ctx.vm->CompileToContext(m_ctx.co, &err);
|
||||||
|
if (!m_ctx.ctx)
|
||||||
|
{
|
||||||
|
memset(&m_ctx, 0, sizeof(m_ctx));
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
SetErrorState(Plugin_Error, "Failed to compile (error %d)", err);
|
||||||
|
} else {
|
||||||
|
snprintf(error, maxlength, "Failed to compile (error %d)", err);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ctx.base = g_pSourcePawn->CreateBaseContext(m_ctx.ctx);
|
||||||
|
m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this;
|
||||||
|
|
||||||
|
m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: Since the m_plugin member will never change,
|
||||||
|
* it is safe to assume the function count will never change
|
||||||
|
*/
|
||||||
|
if (m_funcsnum && m_priv_funcs == NULL)
|
||||||
|
{
|
||||||
|
m_priv_funcs = new CFunction *[m_funcsnum];
|
||||||
|
memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
|
||||||
|
} else {
|
||||||
|
m_priv_funcs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_plugin->info.publics_num && m_pub_funcs == NULL)
|
||||||
|
{
|
||||||
|
m_pub_funcs = new CFunction *[m_plugin->info.publics_num];
|
||||||
|
memset(m_pub_funcs, 0, sizeof(CFunction *) * m_plugin->info.publics_num);
|
||||||
|
} else {
|
||||||
|
m_pub_funcs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateInfo();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
|
||||||
|
{
|
||||||
|
m_status = status;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, error_fmt);
|
||||||
|
vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
|
IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
|
||||||
@ -113,7 +232,7 @@ IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
|
|||||||
} else {
|
} else {
|
||||||
func_id >>= 1;
|
func_id >>= 1;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
if (!g_pVM->FunctionLookup(m_ctx_current.ctx, func_id, &index))
|
if (!g_pVM->FunctionLookup(m_ctx.ctx, func_id, &index))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -131,7 +250,7 @@ IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
|
|||||||
IPluginFunction *CPlugin::GetFunctionByName(const char *public_name)
|
IPluginFunction *CPlugin::GetFunctionByName(const char *public_name)
|
||||||
{
|
{
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
IPluginContext *base = m_ctx_current.base;
|
IPluginContext *base = m_ctx.base;
|
||||||
|
|
||||||
if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE)
|
if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
@ -195,12 +314,12 @@ const sp_plugin_t *CPlugin::GetPluginStructure() const
|
|||||||
|
|
||||||
IPluginContext *CPlugin::GetBaseContext() const
|
IPluginContext *CPlugin::GetBaseContext() const
|
||||||
{
|
{
|
||||||
return m_ctx_current.base;
|
return m_ctx.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_context_t *CPlugin::GetContext() const
|
sp_context_t *CPlugin::GetContext() const
|
||||||
{
|
{
|
||||||
return m_ctx_current.ctx;
|
return m_ctx.ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CPlugin::GetFilename() const
|
const char *CPlugin::GetFilename() const
|
||||||
@ -230,7 +349,12 @@ PluginStatus CPlugin::GetStatus() const
|
|||||||
|
|
||||||
bool CPlugin::IsDebugging() const
|
bool CPlugin::IsDebugging() const
|
||||||
{
|
{
|
||||||
return m_debugging;
|
if (!m_ctx.ctx)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPlugin::SetPauseState(bool paused)
|
bool CPlugin::SetPauseState(bool paused)
|
||||||
@ -299,30 +423,158 @@ void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedi
|
|||||||
/* :TODO: log the error, don't bail out though */
|
/* :TODO: log the error, don't bail out though */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadPluginsFromDir(basedir, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
|
||||||
|
{
|
||||||
|
char base_path[PLATFORM_MAX_PATH+1];
|
||||||
|
|
||||||
|
/* Form the current path to start reading from */
|
||||||
|
if (localpath == NULL)
|
||||||
|
{
|
||||||
|
g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
|
||||||
|
} else {
|
||||||
|
g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirectory *dir = g_LibSys.OpenDirectory(base_path);
|
||||||
|
|
||||||
|
if (!dir)
|
||||||
|
{
|
||||||
|
//:TODO: write a logger and LOG THIS UP, BABY
|
||||||
|
//g_LibSys.GetPlatformError(error, err_max);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//:TODO: move this to a separate recursive function and do stuff
|
|
||||||
/*IDirectory *dir = g_LibSys.OpenDirectory(basedir);
|
|
||||||
while (dir->MoreFiles())
|
while (dir->MoreFiles())
|
||||||
{
|
{
|
||||||
if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0))
|
if (dir->IsEntryDirectory()
|
||||||
|
&& (strcmp(dir->GetEntryName(), ".") != 0)
|
||||||
|
&& (strcmp(dir->GetEntryName(), "..") != 0)
|
||||||
|
&& (strcmp(dir->GetEntryName(), "disabled") != 0)
|
||||||
|
&& (strcmp(dir->GetEntryName(), "optional") != 0))
|
||||||
{
|
{
|
||||||
char path[PLATFORM_MAX_PATH+1];
|
char new_local[PLATFORM_MAX_PATH+1];
|
||||||
g_SMAPI->PathFormat(path, sizeof(path)-1, "%s/%s", basedir, dir->GetEntryName());
|
if (localpath == NULL)
|
||||||
RefreshOrLoadPlugins(basedir);
|
{
|
||||||
|
/* If no path yet, don't add a former slash */
|
||||||
|
snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
|
||||||
|
} else {
|
||||||
|
g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
|
||||||
|
}
|
||||||
|
LoadPluginsFromDir(basedir, new_local);
|
||||||
|
} else if (dir->IsEntryFile()) {
|
||||||
|
const char *name = dir->GetEntryName();
|
||||||
|
size_t len = strlen(name);
|
||||||
|
if (len < 4
|
||||||
|
|| 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);
|
||||||
|
}
|
||||||
|
dir->NextEntry();
|
||||||
|
}
|
||||||
|
g_LibSys.CloseDirectory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPluginManager::LoadAutoPlugin(const char *file)
|
||||||
|
{
|
||||||
|
CPlugin *pPlugin = CPlugin::CreatePlugin(file, NULL, 0);
|
||||||
|
|
||||||
|
assert(pPlugin != NULL);
|
||||||
|
|
||||||
|
pPlugin->m_type = PluginType_MapUpdated;
|
||||||
|
|
||||||
|
ICompilation *co = NULL;
|
||||||
|
|
||||||
|
if (pPlugin->m_status == Plugin_Uncompiled)
|
||||||
|
{
|
||||||
|
co = pPlugin->StartMyCompile(g_pVM);
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginSettings *pset;
|
||||||
|
unsigned int setcount = m_PluginInfo.GetSettingsNum();
|
||||||
|
for (unsigned int i=0; i<setcount; i++)
|
||||||
|
{
|
||||||
|
pset = m_PluginInfo.GetSettingsIfMatch(i, file);
|
||||||
|
if (!pset)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pPlugin->m_type = pset->type_val;
|
||||||
|
if (co)
|
||||||
|
{
|
||||||
|
for (unsigned int j=0; j<pset->opts_num; j++)
|
||||||
|
{
|
||||||
|
const char *key, *val;
|
||||||
|
m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
|
||||||
|
if (!key || !val)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!g_pVM->SetCompilationOption(co, key, val))
|
||||||
|
{
|
||||||
|
pPlugin->SetErrorState(Plugin_Error, "Unable to set option (key \"%s\") (value \"%s\")", key, val);
|
||||||
|
pPlugin->CancelMyCompile();
|
||||||
|
co = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_LibSys.CloseDirectory(dir);*/
|
|
||||||
|
if (co)
|
||||||
|
{
|
||||||
|
pPlugin->FinishMyCompile(NULL, 0);
|
||||||
|
co = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitAndAddPlugin(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, debug, type, error, err_max);
|
CPlugin *pPlugin = CPlugin::CreatePlugin(path, error, err_max);
|
||||||
|
|
||||||
if (!pPlugin)
|
if (!pPlugin)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ICompilation *co = pPlugin->StartMyCompile(g_pVM);
|
||||||
|
if (!co || (debug && !g_pVM->SetCompilationOption(co, "debug", "1")))
|
||||||
|
{
|
||||||
|
snprintf(error, err_max, "Unable to start%s compilation", debug ? " debug" : "");
|
||||||
|
pPlugin->CancelMyCompile();
|
||||||
|
delete pPlugin;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pPlugin->FinishMyCompile(error, err_max))
|
||||||
|
{
|
||||||
|
delete pPlugin;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPlugin->m_type = type;
|
||||||
|
|
||||||
|
InitAndAddPlugin(pPlugin);
|
||||||
|
|
||||||
|
return pPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin)
|
||||||
|
{
|
||||||
m_plugins.push_back(pPlugin);
|
m_plugins.push_back(pPlugin);
|
||||||
|
|
||||||
List<IPluginsListener *>::iterator iter;
|
List<IPluginsListener *>::iterator iter;
|
||||||
@ -334,8 +586,6 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* :TODO: a lot more... */
|
/* :TODO: a lot more... */
|
||||||
|
|
||||||
return pPlugin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
||||||
@ -352,45 +602,6 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin)
|
|||||||
pListener->OnPluginDestroyed(pPlugin);
|
pListener->OnPluginDestroyed(pPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pPlugin->m_pub_funcs)
|
|
||||||
{
|
|
||||||
for (uint32_t i=0; i<pPlugin->m_plugin->info.publics_num; i++)
|
|
||||||
{
|
|
||||||
g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_pub_funcs[i]);
|
|
||||||
}
|
|
||||||
delete [] pPlugin->m_pub_funcs;
|
|
||||||
pPlugin->m_pub_funcs = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pPlugin->m_priv_funcs)
|
|
||||||
{
|
|
||||||
for (unsigned int i=0; i<pPlugin->m_funcsnum; i++)
|
|
||||||
{
|
|
||||||
g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_priv_funcs[i]);
|
|
||||||
}
|
|
||||||
delete [] pPlugin->m_priv_funcs;
|
|
||||||
pPlugin->m_priv_funcs = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pPlugin->m_ctx_current.base)
|
|
||||||
{
|
|
||||||
g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_current.base);
|
|
||||||
}
|
|
||||||
if (pPlugin->m_ctx_backup.base)
|
|
||||||
{
|
|
||||||
g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_backup.base);
|
|
||||||
}
|
|
||||||
if (pPlugin->m_ctx_current.ctx)
|
|
||||||
{
|
|
||||||
pPlugin->m_ctx_current.ctx->vmbase->FreeContext(pPlugin->m_ctx_current.ctx);
|
|
||||||
}
|
|
||||||
if (pPlugin->m_ctx_backup.ctx)
|
|
||||||
{
|
|
||||||
pPlugin->m_ctx_backup.ctx->vmbase->FreeContext(pPlugin->m_ctx_backup.ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pSourcePawn->FreeFromMemory(pPlugin->m_plugin);
|
|
||||||
|
|
||||||
delete pPlugin;
|
delete pPlugin;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -477,7 +688,7 @@ bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
|
|||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alias_path_end == alias_len - 1)
|
if (alias_explicit_paths && alias_path_end == alias_len - 1)
|
||||||
{
|
{
|
||||||
/* Trailing slash is totally invalid here */
|
/* Trailing slash is totally invalid here */
|
||||||
return false;
|
return false;
|
||||||
|
@ -10,21 +10,47 @@
|
|||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOTES:
|
||||||
|
*
|
||||||
|
* Currently this system needs a lot of work but it's good skeletally. Plugin creation
|
||||||
|
* is done without actually compiling anything. This is done by Load functions in the
|
||||||
|
* manager. This will need a rewrite when we add context switching.
|
||||||
|
*
|
||||||
|
* The plugin object itself has a few things to note. The most important is that it stores
|
||||||
|
* a table of function objects. The manager marshals allocation and freeing of these objects.
|
||||||
|
* The plugin object can be in erroneous states, they are:
|
||||||
|
* Plugin_Error --> Some error occurred any time during or after compilation.
|
||||||
|
* This error can be cleared since the plugin itself is valid.
|
||||||
|
* However, the state itself being set prevents any runtime action.
|
||||||
|
* Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
|
||||||
|
*
|
||||||
|
* If a plugin fails to load externally, it is never added to the internal tracker. However,
|
||||||
|
* 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
|
||||||
|
* more flexible.
|
||||||
|
*/
|
||||||
|
|
||||||
#define SM_CONTEXTVAR_MYSELF 0
|
#define SM_CONTEXTVAR_MYSELF 0
|
||||||
|
|
||||||
struct ContextPair
|
struct ContextPair
|
||||||
{
|
{
|
||||||
ContextPair() : base(NULL), ctx(NULL)
|
ContextPair() : base(NULL), ctx(NULL), co(NULL)
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
IPluginContext *base;
|
IPluginContext *base;
|
||||||
sp_context_t *ctx;
|
sp_context_t *ctx;
|
||||||
|
ICompilation *co;
|
||||||
|
IVirtualMachine *vm;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPlugin : public IPlugin
|
class CPlugin : public IPlugin
|
||||||
{
|
{
|
||||||
friend class CPluginManager;
|
friend class CPluginManager;
|
||||||
friend class CFunction;
|
friend class CFunction;
|
||||||
|
public:
|
||||||
|
CPlugin(const char *file);
|
||||||
|
~CPlugin();
|
||||||
public:
|
public:
|
||||||
virtual PluginType GetType() const;
|
virtual PluginType GetType() const;
|
||||||
virtual SourcePawn::IPluginContext *GetBaseContext() const;
|
virtual SourcePawn::IPluginContext *GetBaseContext() const;
|
||||||
@ -39,18 +65,34 @@ public:
|
|||||||
virtual IPluginFunction *GetFunctionByName(const char *public_name);
|
virtual IPluginFunction *GetFunctionByName(const char *public_name);
|
||||||
virtual IPluginFunction *GetFunctionById(funcid_t func_id);
|
virtual IPluginFunction *GetFunctionById(funcid_t func_id);
|
||||||
public:
|
public:
|
||||||
static CPlugin *CreatePlugin(const char *file,
|
/**
|
||||||
bool debug_default,
|
* Creates a plugin object with default values.
|
||||||
PluginType life,
|
* If an error buffer is specified, and an error occurs, the error will be copied to the buffer
|
||||||
char *error,
|
* and NULL will be returned.
|
||||||
size_t maxlen);
|
* If an error buffer is not specified, the error will be copied to an internal buffer and
|
||||||
|
* a valid (but error-stated) CPlugin will be returned.
|
||||||
|
*/
|
||||||
|
static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Starts the initial compilation of a plugin.
|
||||||
|
* Returns false if another compilation exists or there is a current context set.
|
||||||
|
*/
|
||||||
|
ICompilation *StartMyCompile(IVirtualMachine *vm);
|
||||||
|
/**
|
||||||
|
* Finalizes a compilation. If error buffer is NULL, the error is saved locally.
|
||||||
|
*/
|
||||||
|
bool FinishMyCompile(char *error, size_t maxlength);
|
||||||
|
void CancelMyCompile();
|
||||||
|
/**
|
||||||
|
* Sets an error state on the plugin
|
||||||
|
*/
|
||||||
|
void SetErrorState(PluginStatus status, const char *error_fmt, ...);
|
||||||
protected:
|
protected:
|
||||||
void UpdateInfo();
|
void UpdateInfo();
|
||||||
private:
|
private:
|
||||||
ContextPair m_ctx_current;
|
ContextPair m_ctx;
|
||||||
ContextPair m_ctx_backup;
|
|
||||||
PluginType m_type;
|
PluginType m_type;
|
||||||
bool m_debugging;
|
|
||||||
char m_filename[PLATFORM_MAX_PATH+1];
|
char m_filename[PLATFORM_MAX_PATH+1];
|
||||||
PluginStatus m_status;
|
PluginStatus m_status;
|
||||||
unsigned int m_serial;
|
unsigned int m_serial;
|
||||||
@ -59,13 +101,7 @@ private:
|
|||||||
unsigned int m_funcsnum;
|
unsigned int m_funcsnum;
|
||||||
CFunction **m_priv_funcs;
|
CFunction **m_priv_funcs;
|
||||||
CFunction **m_pub_funcs;
|
CFunction **m_pub_funcs;
|
||||||
};
|
char m_errormsg[256];
|
||||||
|
|
||||||
struct PluginDBInfo
|
|
||||||
{
|
|
||||||
bool pause;
|
|
||||||
PluginType lifetime;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPluginManager : public IPluginManager
|
class CPluginManager : public IPluginManager
|
||||||
@ -108,7 +144,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Refreshes and loads plugins, usually used on mapchange
|
* Refreshes and loads plugins, usually used on mapchange
|
||||||
*/
|
*/
|
||||||
virtual void RefreshOrLoadPlugins(const char *config, const char *basedir);
|
void RefreshOrLoadPlugins(const char *config, const char *basedir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a plugin file mask against a local folder.
|
* Tests a plugin file mask against a local folder.
|
||||||
@ -119,8 +155,27 @@ public:
|
|||||||
* All of these will return true for an alias match.
|
* All of these will return true for an alias match.
|
||||||
* Wildcards are allowed in the filename.
|
* Wildcards are allowed in the filename.
|
||||||
*/
|
*/
|
||||||
virtual bool TestAliasMatch(const char *alias, const char *localdir);
|
bool TestAliasMatch(const char *alias, const char *localdir);
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Recursively loads all plugins in the given directory.
|
||||||
|
*/
|
||||||
|
void LoadPluginsFromDir(const char *basedir, const char *localdir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a plugin using automatic information.
|
||||||
|
* The file must be relative to the plugins folder.
|
||||||
|
*/
|
||||||
|
void LoadAutoPlugin(const char *file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds and initializes a plugin object. This is wrapped by LoadPlugin functions.
|
||||||
|
*/
|
||||||
|
void InitAndAddPlugin(CPlugin *pPlugin);
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
|
* Caching internal objects
|
||||||
|
*/
|
||||||
void ReleaseIterator(CPluginIterator *iter);
|
void ReleaseIterator(CPluginIterator *iter);
|
||||||
CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin);
|
CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin);
|
||||||
void ReleaseFunctionToPool(CFunction *func);
|
void ReleaseFunctionToPool(CFunction *func);
|
||||||
|
Loading…
Reference in New Issue
Block a user