#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ #include #include #include #include "sm_globals.h" #include "CFunction.h" #include "PluginInfoDatabase.h" 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 struct ContextPair { ContextPair() : base(NULL), ctx(NULL), co(NULL) { }; IPluginContext *base; sp_context_t *ctx; ICompilation *co; IVirtualMachine *vm; }; class CPlugin : public IPlugin { friend class CPluginManager; friend class CFunction; public: CPlugin(const char *file); ~CPlugin(); public: virtual PluginType GetType() const; 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; virtual IPluginFunction *GetFunctionByName(const char *public_name); virtual IPluginFunction *GetFunctionById(funcid_t func_id); public: /** * 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, ...); protected: void UpdateInfo(); private: ContextPair m_ctx; PluginType m_type; char m_filename[PLATFORM_MAX_PATH+1]; PluginStatus m_status; unsigned int m_serial; sm_plugininfo_t m_info; sp_plugin_t *m_plugin; unsigned int m_funcsnum; CFunction **m_priv_funcs; CFunction **m_pub_funcs; char m_errormsg[256]; }; class CPluginManager : public IPluginManager { friend class CPlugin; public: CPluginManager(); ~CPluginManager(); public: /* Implements iterator class */ class CPluginIterator : public IPluginIterator { public: CPluginIterator(List *mylist); virtual ~CPluginIterator(); virtual bool MorePlugins(); virtual IPlugin *GetPlugin(); virtual void NextPlugin(); virtual void Release(); public: void Reset(); private: List *mylist; List::iterator current; }; friend class CPluginManager::CPluginIterator; public: //IPluginManager 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); public: /** * Refreshes and loads plugins, usually used on mapchange */ void RefreshOrLoadPlugins(const char *config, const char *basedir); /** * 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. */ 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: /** * Caching internal objects */ void ReleaseIterator(CPluginIterator *iter); CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); void ReleaseFunctionToPool(CFunction *func); private: List m_listeners; List m_plugins; CStack m_iters; CStack m_funcpool; CPluginInfoDatabase m_PluginInfo; }; extern CPluginManager g_PluginMngr; #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_