2006-11-10 19:08:13 +01:00
|
|
|
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
|
|
|
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
|
|
|
|
2006-12-15 14:38:04 +01:00
|
|
|
#include <time.h>
|
2006-11-10 19:08:13 +01:00
|
|
|
#include <IPluginSys.h>
|
2006-11-11 02:19:46 +01:00
|
|
|
#include <sh_list.h>
|
|
|
|
#include <sh_stack.h>
|
2006-11-10 19:08:13 +01:00
|
|
|
#include "sm_globals.h"
|
2006-11-11 12:10:24 +01:00
|
|
|
#include "CFunction.h"
|
2006-12-10 10:19:59 +01:00
|
|
|
#include "PluginInfoDatabase.h"
|
2006-12-15 14:38:04 +01:00
|
|
|
#include "sm_trie.h"
|
2006-11-10 19:08:13 +01:00
|
|
|
|
2006-11-11 02:19:46 +01:00
|
|
|
using namespace SourceHook;
|
|
|
|
|
2006-12-13 12:16:20 +01:00
|
|
|
/**
|
|
|
|
* 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.
|
2006-12-15 14:38:04 +01:00
|
|
|
*
|
|
|
|
* 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
|
2006-12-13 12:16:20 +01:00
|
|
|
*/
|
|
|
|
|
2006-11-11 02:19:46 +01:00
|
|
|
#define SM_CONTEXTVAR_MYSELF 0
|
|
|
|
|
2006-11-10 19:08:13 +01:00
|
|
|
struct ContextPair
|
|
|
|
{
|
2006-12-13 12:16:20 +01:00
|
|
|
ContextPair() : base(NULL), ctx(NULL), co(NULL)
|
2006-11-10 19:08:13 +01:00
|
|
|
{
|
|
|
|
};
|
|
|
|
IPluginContext *base;
|
|
|
|
sp_context_t *ctx;
|
2006-12-13 12:16:20 +01:00
|
|
|
ICompilation *co;
|
|
|
|
IVirtualMachine *vm;
|
2006-11-10 19:08:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class CPlugin : public IPlugin
|
|
|
|
{
|
2006-11-11 02:19:46 +01:00
|
|
|
friend class CPluginManager;
|
2006-11-11 06:49:52 +01:00
|
|
|
friend class CFunction;
|
2006-12-13 12:16:20 +01:00
|
|
|
public:
|
|
|
|
CPlugin(const char *file);
|
|
|
|
~CPlugin();
|
2006-11-10 19:08:13 +01:00
|
|
|
public:
|
2006-11-11 02:19:46 +01:00
|
|
|
virtual PluginType GetType() const;
|
2006-11-10 19:08:13 +01:00
|
|
|
virtual SourcePawn::IPluginContext *GetBaseContext() const;
|
|
|
|
virtual sp_context_t *GetContext() const;
|
|
|
|
virtual const sm_plugininfo_t *GetPublicInfo() const;
|
|
|
|
virtual const char *GetFilename() const;
|
|
|
|
virtual bool IsDebugging() const;
|
|
|
|
virtual PluginStatus GetStatus() const;
|
|
|
|
virtual bool SetPauseState(bool paused);
|
|
|
|
virtual unsigned int GetSerial() const;
|
|
|
|
virtual const sp_plugin_t *GetPluginStructure() const;
|
2006-11-11 02:19:46 +01:00
|
|
|
virtual IPluginFunction *GetFunctionByName(const char *public_name);
|
|
|
|
virtual IPluginFunction *GetFunctionById(funcid_t func_id);
|
2006-11-10 19:08:13 +01:00
|
|
|
public:
|
2006-12-13 12:16:20 +01:00
|
|
|
/**
|
|
|
|
* Creates a plugin object with default values.
|
|
|
|
* If an error buffer is specified, and an error occurs, the error will be copied to the buffer
|
|
|
|
* and NULL will be returned.
|
|
|
|
* 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, ...);
|
2006-12-15 14:38:04 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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();
|
2006-11-10 19:08:13 +01:00
|
|
|
protected:
|
|
|
|
void UpdateInfo();
|
|
|
|
private:
|
2006-12-13 12:16:20 +01:00
|
|
|
ContextPair m_ctx;
|
2006-11-11 02:19:46 +01:00
|
|
|
PluginType m_type;
|
2006-11-10 19:08:13 +01:00
|
|
|
char m_filename[PLATFORM_MAX_PATH+1];
|
|
|
|
PluginStatus m_status;
|
|
|
|
unsigned int m_serial;
|
|
|
|
sm_plugininfo_t m_info;
|
|
|
|
sp_plugin_t *m_plugin;
|
2006-11-11 06:49:52 +01:00
|
|
|
unsigned int m_funcsnum;
|
|
|
|
CFunction **m_priv_funcs;
|
|
|
|
CFunction **m_pub_funcs;
|
2006-12-13 12:16:20 +01:00
|
|
|
char m_errormsg[256];
|
2006-12-15 14:38:04 +01:00
|
|
|
time_t m_LastAccess;
|
2006-12-10 10:19:59 +01:00
|
|
|
};
|
|
|
|
|
2006-11-11 02:19:46 +01:00
|
|
|
class CPluginManager : public IPluginManager
|
|
|
|
{
|
2006-11-11 06:49:52 +01:00
|
|
|
friend class CPlugin;
|
2006-11-11 02:19:46 +01:00
|
|
|
public:
|
|
|
|
CPluginManager();
|
2006-11-11 06:49:52 +01:00
|
|
|
~CPluginManager();
|
2006-11-11 02:19:46 +01:00
|
|
|
public:
|
2006-12-10 10:19:59 +01:00
|
|
|
/* Implements iterator class */
|
2006-11-11 02:19:46 +01:00
|
|
|
class CPluginIterator : public IPluginIterator
|
|
|
|
{
|
|
|
|
public:
|
2006-12-15 14:53:58 +01:00
|
|
|
CPluginIterator(List<CPlugin *> *mylist);
|
2006-11-11 02:19:46 +01:00
|
|
|
virtual ~CPluginIterator();
|
|
|
|
virtual bool MorePlugins();
|
|
|
|
virtual IPlugin *GetPlugin();
|
|
|
|
virtual void NextPlugin();
|
|
|
|
virtual void Release();
|
|
|
|
public:
|
|
|
|
void Reset();
|
|
|
|
private:
|
2006-12-15 14:53:58 +01:00
|
|
|
List<CPlugin *> *mylist;
|
|
|
|
List<CPlugin *>::iterator current;
|
2006-11-11 02:19:46 +01:00
|
|
|
};
|
|
|
|
friend class CPluginManager::CPluginIterator;
|
2006-12-10 10:19:59 +01:00
|
|
|
public: //IPluginManager
|
2006-11-11 02:19:46 +01:00
|
|
|
virtual IPlugin *LoadPlugin(const char *path,
|
|
|
|
bool debug,
|
|
|
|
PluginType type,
|
|
|
|
char error[],
|
|
|
|
size_t err_max);
|
|
|
|
virtual bool UnloadPlugin(IPlugin *plugin);
|
|
|
|
virtual IPlugin *FindPluginByContext(const sp_context_t *ctx);
|
|
|
|
virtual unsigned int GetPluginCount();
|
|
|
|
virtual IPluginIterator *GetPluginIterator();
|
|
|
|
virtual void AddPluginsListener(IPluginsListener *listener);
|
|
|
|
virtual void RemovePluginsListener(IPluginsListener *listener);
|
2006-12-06 01:09:46 +01:00
|
|
|
public:
|
2006-12-10 10:19:59 +01:00
|
|
|
/**
|
2006-12-15 14:38:04 +01:00
|
|
|
* Loads all plugins not yet loaded
|
|
|
|
*/
|
|
|
|
void LoadAll_FirstPass(const char *config, const char *basedir);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Runs the second loading pass for all plugins
|
2006-12-10 10:19:59 +01:00
|
|
|
*/
|
2006-12-15 14:38:04 +01:00
|
|
|
void LoadAll_SecondPass();
|
2006-12-10 10:19:59 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tests a plugin file mask against a local folder.
|
|
|
|
* The alias is searched backwards from localdir - i.e., given this input:
|
|
|
|
* csdm/ban csdm/ban
|
|
|
|
* ban csdm/ban
|
|
|
|
* csdm/ban optional/csdm/ban
|
|
|
|
* All of these will return true for an alias match.
|
|
|
|
* Wildcards are allowed in the filename.
|
|
|
|
*/
|
2006-12-13 12:16:20 +01:00
|
|
|
bool TestAliasMatch(const char *alias, const char *localdir);
|
2006-12-15 14:38:04 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers natives in core itself ONLY.
|
|
|
|
*/
|
|
|
|
void RegisterGlobalNatives(sp_nativeinfo_t *info[]);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether anything loaded will be a late load.
|
|
|
|
*/
|
|
|
|
bool IsLateLoadTime();
|
2006-12-13 12:16:20 +01:00
|
|
|
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);
|
|
|
|
|
|
|
|
/**
|
2006-12-15 14:38:04 +01:00
|
|
|
* Adds a plugin object. This is wrapped by LoadPlugin functions.
|
|
|
|
*/
|
|
|
|
void AddPlugin(CPlugin *pPlugin);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Runs the second loading pass on a plugin.
|
|
|
|
*/
|
|
|
|
void RunSecondPass(CPlugin *pPlugin);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds any globally registered natives to a plugin
|
2006-12-13 12:16:20 +01:00
|
|
|
*/
|
2006-12-15 14:38:04 +01:00
|
|
|
void AddCoreNativesToPlugin(CPlugin *pPlugin);
|
2006-11-11 02:19:46 +01:00
|
|
|
protected:
|
2006-12-13 12:16:20 +01:00
|
|
|
/**
|
|
|
|
* Caching internal objects
|
|
|
|
*/
|
2006-11-11 02:19:46 +01:00
|
|
|
void ReleaseIterator(CPluginIterator *iter);
|
2006-11-11 06:49:52 +01:00
|
|
|
CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin);
|
|
|
|
void ReleaseFunctionToPool(CFunction *func);
|
2006-11-11 02:19:46 +01:00
|
|
|
private:
|
|
|
|
List<IPluginsListener *> m_listeners;
|
2006-12-15 14:53:58 +01:00
|
|
|
List<CPlugin *> m_plugins;
|
2006-12-15 14:38:04 +01:00
|
|
|
List<sp_nativeinfo_t *> m_natives;
|
2006-11-11 02:19:46 +01:00
|
|
|
CStack<CPluginManager::CPluginIterator *> m_iters;
|
2006-11-11 06:49:52 +01:00
|
|
|
CStack<CFunction *> m_funcpool;
|
2006-12-10 10:19:59 +01:00
|
|
|
CPluginInfoDatabase m_PluginInfo;
|
2006-12-15 14:38:04 +01:00
|
|
|
Trie *m_LoadLookup;
|
|
|
|
bool m_AllPluginsLoaded;
|
2006-11-11 02:19:46 +01:00
|
|
|
};
|
|
|
|
|
2006-12-15 14:38:04 +01:00
|
|
|
extern CPluginManager g_PluginSys;
|
2006-11-11 02:19:46 +01:00
|
|
|
|
2006-11-10 19:08:13 +01:00
|
|
|
#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|