2 * ===============================================================
3 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
4 * ===============================================================
6 * This file is not open source and may not be copied without explicit
7 * written permission of AlliedModders LLC. This file may not be redistributed
8 * in whole or significant part.
9 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
14 #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
15 #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
20 #include <IPluginSys.h>
21 #include <IHandleSys.h>
24 #include <sh_vector.h>
25 #include "sm_globals.h"
26 #include "vm/sp_vm_basecontext.h"
27 #include "PluginInfoDatabase.h"
29 #include "sourcemod.h"
30 #include <IRootConsoleMenu.h>
31 #include "convar_sm.h"
33 using namespace SourceHook;
38 * Currently this system needs a lot of work but it's good skeletally. Plugin creation
39 * is done without actually compiling anything. This is done by Load functions in the
40 * manager. This will need a rewrite when we add context switching.
42 * The plugin object itself has a few things to note. The most important is that it stores
43 * a table of function objects. The manager marshals allocation and freeing of these objects.
44 * The plugin object can be in erroneous states, they are:
45 * Plugin_Error --> Some error occurred any time during or after compilation.
46 * This error can be cleared since the plugin itself is valid.
47 * However, the state itself being set prevents any runtime action.
48 * Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
50 * If a plugin fails to load externally, it is never added to the internal tracker. However,
51 * plugins that failed to load from the internal loading mechanism are always tracked. This
52 * allows users to see which automatically loaded plugins failed, and makes the interface a bit
55 * Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
56 * for execution. SourceMod is a two pass system, and even though the second pass is not implemented
57 * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
58 * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
60 * The two pass loading mechanism is described below. Modules/natives are not implemented yet.
61 * PASS ONE: All loadable plugins are found and have the following steps performed:
62 * 1. Loading and compilation is attempted.
63 * 2. If successful, all natives from Core are added.
64 * 3. OnPluginLoad() is called.
65 * 4. If failed, any user natives are scrapped and the process halts here.
66 * 5. If successful, the plugin is ready for Pass 2.
68 * 1. All forced modules are loaded.
69 * PASS TWO: All loaded plugins are found and have these steps performed:
70 * 1. Any modules referenced in the plugin that are not already loaded, are loaded.
71 * 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
72 * 3. If any natives are unresolved, check if they are found in the user-natives pool.
73 * 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
74 * 5. If the filter fails, the plugin is marked as failed.
75 * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
76 * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
77 * PASS THREE (not a real pass):
78 * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
81 #define SM_CONTEXTVAR_MYSELF 0
85 ContextPair() : base(NULL), ctx(NULL), co(NULL)
97 LoadRes_AlreadyLoaded,
101 class CPlugin : public IPlugin
103 friend class CPluginManager;
104 friend class CFunction;
106 CPlugin(const char *file);
109 virtual PluginType GetType() const;
110 virtual SourcePawn::IPluginContext *GetBaseContext() const;
111 virtual sp_context_t *GetContext() const;
112 virtual const sm_plugininfo_t *GetPublicInfo() const;
113 virtual const char *GetFilename() const;
114 virtual bool IsDebugging() const;
115 virtual PluginStatus GetStatus() const;
116 virtual bool SetPauseState(bool paused);
117 virtual unsigned int GetSerial() const;
118 virtual const sp_plugin_t *GetPluginStructure() const;
119 virtual IdentityToken_t *GetIdentity() const;
120 virtual bool SetProperty(const char *prop, void *ptr);
121 virtual bool GetProperty(const char *prop, void **ptr, bool remove=false);
124 * Creates a plugin object with default values.
125 * If an error buffer is specified, and an error occurs, the error will be copied to the buffer
126 * and NULL will be returned.
127 * If an error buffer is not specified, the error will be copied to an internal buffer and
128 * a valid (but error-stated) CPlugin will be returned.
130 static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
133 * Starts the initial compilation of a plugin.
134 * Returns false if another compilation exists or there is a current context set.
136 ICompilation *StartMyCompile(IVirtualMachine *vm);
138 * Finalizes a compilation. If error buffer is NULL, the error is saved locally.
140 bool FinishMyCompile(char *error, size_t maxlength);
141 void CancelMyCompile();
144 * Sets an error state on the plugin
146 void SetErrorState(PluginStatus status, const char *error_fmt, ...);
149 * Initializes the plugin's identity information
154 * Calls the OnPluginLoad function, and sets any failed states if necessary.
155 * NOTE: Valid pre-states are: Plugin_Created
156 * NOTE: If validated, plugin state is changed to Plugin_Loaded
158 * If the error buffer is NULL, the error message is cached locally.
160 bool Call_AskPluginLoad(char *error, size_t maxlength);
163 * Calls the OnPluginStart function.
164 * NOTE: Valid pre-states are: Plugin_Created
165 * NOTE: Post-state will be Plugin_Running
167 void Call_OnPluginStart();
170 * Calls the OnPluginEnd function.
172 void Call_OnPluginEnd();
175 * Toggles debug mode in the plugin
177 bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
180 * Returns true if a plugin is usable.
182 bool IsRunnable() const;
185 * Adds a language file index to the plugin's list.
187 void AddLangFile(unsigned int index);
190 * Get language file count for this plugin.
192 size_t GetLangFileCount() const;
195 * Get language file index based on the vector index.
197 unsigned int GetLangFileByIndex(unsigned int index) const;
200 * Returns the modification time during last plugin load.
202 time_t GetTimeStamp() const;
205 * Returns the current modification time of the plugin file.
207 time_t GetFileTimeStamp();
210 * Returns true if the plugin was running, but is now invalid.
215 void SetTimeStamp(time_t t);
219 char m_filename[PLATFORM_MAX_PATH+1];
220 PluginStatus m_status;
221 unsigned int m_serial;
222 sm_plugininfo_t m_info;
223 sp_plugin_t *m_plugin;
224 char m_errormsg[256];
226 IdentityToken_t *m_ident;
229 CVector<unsigned int> m_PhraseFiles;
233 class CPluginManager :
234 public IPluginManager,
235 public SMGlobalClass,
236 public IHandleTypeDispatch,
237 public IRootConsoleCommand
239 friend class CPlugin;
244 /* Implements iterator class */
245 class CPluginIterator : public IPluginIterator
248 CPluginIterator(List<CPlugin *> *mylist);
249 virtual ~CPluginIterator();
250 virtual bool MorePlugins();
251 virtual IPlugin *GetPlugin();
252 virtual void NextPlugin();
257 List<CPlugin *> *mylist;
258 List<CPlugin *>::iterator current;
260 friend class CPluginManager::CPluginIterator;
261 public: //IPluginManager
262 IPlugin *LoadPlugin(const char *path,
268 bool UnloadPlugin(IPlugin *plugin);
269 IPlugin *FindPluginByContext(const sp_context_t *ctx);
270 unsigned int GetPluginCount();
271 IPluginIterator *GetPluginIterator();
272 void AddPluginsListener(IPluginsListener *listener);
273 void RemovePluginsListener(IPluginsListener *listener);
274 public: //SMGlobalClass
275 void OnSourceModAllInitialized();
276 void OnSourceModShutdown();
277 public: //IHandleTypeDispatch
278 void OnHandleDestroy(HandleType_t type, void *object);
279 public: //IRootConsoleCommand
280 void OnRootConsoleCommand(const char *command, unsigned int argcount);
283 * Loads all plugins not yet loaded
285 void LoadAll_FirstPass(const char *config, const char *basedir);
288 * Runs the second loading pass for all plugins
290 void LoadAll_SecondPass();
293 * Tests a plugin file mask against a local folder.
294 * The alias is searched backwards from localdir - i.e., given this input:
297 * csdm/ban optional/csdm/ban
298 * All of these will return true for an alias match.
299 * Wildcards are allowed in the filename.
301 bool TestAliasMatch(const char *alias, const char *localdir);
304 * Returns whether anything loaded will be a late load.
306 bool IsLateLoadTime() const;
309 * Adds natives from core into the native pool.
311 void RegisterNativesFromCore(sp_nativeinfo_t *natives);
314 * Converts a Handle to an IPlugin if possible.
316 IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
319 * Finds a plugin based on its index. (starts on index 1)
321 CPlugin *GetPluginByOrder(int num);
324 * Internal version of FindPluginByContext()
326 inline CPlugin *GetPluginByCtx(const sp_context_t *ctx)
328 return reinterpret_cast<CPlugin *>(ctx->user[SM_CONTEXTVAR_MYSELF]);
332 * Gets status text for a status code
334 const char *GetStatusText(PluginStatus status);
337 * Reload or update plugins on level shutdown.
339 void ReloadOrUnloadPlugins();
342 LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t err_max);
344 void LoadAutoPlugin(const char *plugin);
347 * Recursively loads all plugins in the given directory.
349 void LoadPluginsFromDir(const char *basedir, const char *localdir);
352 * Adds a plugin object. This is wrapped by LoadPlugin functions.
354 void AddPlugin(CPlugin *pPlugin);
357 * Runs the second loading pass on a plugin.
359 bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
362 * Adds any globally registered natives to a plugin
364 void AddCoreNativesToPlugin(CPlugin *pPlugin);
367 * Runs an extension pass on a plugin.
369 bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
371 void _SetPauseState(CPlugin *pPlugin, bool pause);
374 * Caching internal objects
376 void ReleaseIterator(CPluginIterator *iter);
377 inline IdentityToken_t *GetIdentity()
382 List<IPluginsListener *> m_listeners;
383 List<CPlugin *> m_plugins;
384 List<sp_nativeinfo_t *> m_natives;
385 CStack<CPluginManager::CPluginIterator *> m_iters;
386 CPluginInfoDatabase m_PluginInfo;
388 bool m_AllPluginsLoaded;
389 IdentityToken_t *m_MyIdent;
392 extern CPluginManager g_PluginSys;
394 #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_