3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
15 #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
16 #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
21 #include <IPluginSys.h>
22 #include <IHandleSys.h>
23 #include <IForwardSys.h>
26 #include <sh_vector.h>
27 #include <sh_string.h>
28 #include "sm_globals.h"
29 #include "vm/sp_vm_basecontext.h"
30 #include "PluginInfoDatabase.h"
32 #include "sourcemod.h"
33 #include <IRootConsoleMenu.h>
34 #include "convar_sm.h"
36 using namespace SourceHook;
41 * Currently this system needs a lot of work but it's good skeletally. Plugin creation
42 * is done without actually compiling anything. This is done by Load functions in the
43 * manager. This will need a rewrite when we add context switching.
45 * The plugin object itself has a few things to note. The most important is that it stores
46 * a table of function objects. The manager marshals allocation and freeing of these objects.
47 * The plugin object can be in erroneous states, they are:
48 * Plugin_Error --> Some error occurred any time during or after compilation.
49 * This error can be cleared since the plugin itself is valid.
50 * However, the state itself being set prevents any runtime action.
51 * Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
53 * If a plugin fails to load externally, it is never added to the internal tracker. However,
54 * plugins that failed to load from the internal loading mechanism are always tracked. This
55 * allows users to see which automatically loaded plugins failed, and makes the interface a bit
58 * Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
59 * for execution. SourceMod is a two pass system, and even though the second pass is not implemented
60 * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
61 * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
63 * The two pass loading mechanism is described below. Modules/natives are not implemented yet.
64 * PASS ONE: All loadable plugins are found and have the following steps performed:
65 * 1. Loading and compilation is attempted.
66 * 2. If successful, all natives from Core are added.
67 * 3. OnPluginLoad() is called.
68 * 4. If failed, any user natives are scrapped and the process halts here.
69 * 5. If successful, the plugin is ready for Pass 2.
71 * 1. All forced modules are loaded.
72 * PASS TWO: All loaded plugins are found and have these steps performed:
73 * 1. Any modules referenced in the plugin that are not already loaded, are loaded.
74 * 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
75 * 3. If any natives are unresolved, check if they are found in the user-natives pool.
76 * 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
77 * 5. If the filter fails, the plugin is marked as failed.
78 * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
79 * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
80 * PASS THREE (not a real pass):
81 * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
84 #define SM_CONTEXTVAR_MYSELF 0
88 ContextPair() : base(NULL), ctx(NULL), co(NULL)
100 IPluginFunction *call;
102 SPVM_NATIVE_FUNC func;
108 LoadRes_AlreadyLoaded,
119 class CPlugin : public IPlugin
121 friend class CPluginManager;
122 friend class CFunction;
124 CPlugin(const char *file);
127 PluginType GetType();
128 SourcePawn::IPluginContext *GetBaseContext();
129 sp_context_t *GetContext();
130 const sm_plugininfo_t *GetPublicInfo();
131 const char *GetFilename();
133 PluginStatus GetStatus();
134 bool SetPauseState(bool paused);
135 unsigned int GetSerial();
136 const sp_plugin_t *GetPluginStructure();
137 IdentityToken_t *GetIdentity();
138 bool SetProperty(const char *prop, void *ptr);
139 bool GetProperty(const char *prop, void **ptr, bool remove=false);
142 * Creates a plugin object with default values.
143 * If an error buffer is specified, and an error occurs, the error will be copied to the buffer
144 * and NULL will be returned.
145 * If an error buffer is not specified, the error will be copied to an internal buffer and
146 * a valid (but error-stated) CPlugin will be returned.
148 static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
151 * Starts the initial compilation of a plugin.
152 * Returns false if another compilation exists or there is a current context set.
154 ICompilation *StartMyCompile(IVirtualMachine *vm);
156 * Finalizes a compilation. If error buffer is NULL, the error is saved locally.
158 bool FinishMyCompile(char *error, size_t maxlength);
159 void CancelMyCompile();
162 * Sets an error state on the plugin
164 void SetErrorState(PluginStatus status, const char *error_fmt, ...);
167 * Initializes the plugin's identity information
172 * Calls the OnPluginLoad function, and sets any failed states if necessary.
173 * NOTE: Valid pre-states are: Plugin_Created
174 * NOTE: If validated, plugin state is changed to Plugin_Loaded
176 * If the error buffer is NULL, the error message is cached locally.
178 bool Call_AskPluginLoad(char *error, size_t maxlength);
181 * Calls the OnPluginStart function.
182 * NOTE: Valid pre-states are: Plugin_Created
183 * NOTE: Post-state will be Plugin_Running
185 void Call_OnPluginStart();
188 * Calls the OnPluginEnd function.
190 void Call_OnPluginEnd();
193 * Toggles debug mode in the plugin
195 bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
198 * Returns true if a plugin is usable.
203 * Adds a language file index to the plugin's list.
205 void AddLangFile(unsigned int index);
208 * Get language file count for this plugin.
210 size_t GetLangFileCount();
213 * Get language file index based on the vector index.
215 unsigned int GetLangFileByIndex(unsigned int index);
218 * Returns the modification time during last plugin load.
220 time_t GetTimeStamp();
223 * Returns the current modification time of the plugin file.
225 time_t GetFileTimeStamp();
228 * Returns true if the plugin was running, but is now invalid.
232 Handle_t GetMyHandle();
234 void AddConfig(bool autoCreate, const char *cfg, const char *folder);
235 unsigned int GetConfigCount();
236 AutoConfig *GetConfig(unsigned int i);
239 void SetTimeStamp(time_t t);
240 void DependencyDropped(CPlugin *pOwner);
244 char m_filename[PLATFORM_MAX_PATH];
245 PluginStatus m_status;
246 unsigned int m_serial;
247 sm_plugininfo_t m_info;
248 sp_plugin_t *m_plugin;
249 char m_errormsg[256];
251 IdentityToken_t *m_ident;
254 CVector<unsigned int> m_PhraseFiles;
255 List<CPlugin *> m_dependents;
256 List<CPlugin *> m_dependsOn;
257 List<FakeNative *> m_fakeNatives;
259 bool m_FakeNativesMissing;
260 CVector<AutoConfig *> m_configs;
263 class CPluginManager :
264 public IPluginManager,
265 public SMGlobalClass,
266 public IHandleTypeDispatch,
267 public IRootConsoleCommand
269 friend class CPlugin;
274 /* Implements iterator class */
275 class CPluginIterator : public IPluginIterator
278 CPluginIterator(List<CPlugin *> *mylist);
279 virtual ~CPluginIterator();
280 virtual bool MorePlugins();
281 virtual IPlugin *GetPlugin();
282 virtual void NextPlugin();
287 List<CPlugin *> *mylist;
288 List<CPlugin *>::iterator current;
290 friend class CPluginManager::CPluginIterator;
291 public: //IPluginManager
292 IPlugin *LoadPlugin(const char *path,
298 bool UnloadPlugin(IPlugin *plugin);
299 IPlugin *FindPluginByContext(const sp_context_t *ctx);
300 unsigned int GetPluginCount();
301 IPluginIterator *GetPluginIterator();
302 void AddPluginsListener(IPluginsListener *listener);
303 void RemovePluginsListener(IPluginsListener *listener);
304 public: //SMGlobalClass
305 void OnSourceModAllInitialized();
306 void OnSourceModShutdown();
307 public: //IHandleTypeDispatch
308 void OnHandleDestroy(HandleType_t type, void *object);
309 public: //IRootConsoleCommand
310 void OnRootConsoleCommand(const char *command, unsigned int argcount);
313 * Loads all plugins not yet loaded
315 void LoadAll_FirstPass(const char *config, const char *basedir);
318 * Runs the second loading pass for all plugins
320 void LoadAll_SecondPass();
323 * Tests a plugin file mask against a local folder.
324 * The alias is searched backwards from localdir - i.e., given this input:
327 * csdm/ban optional/csdm/ban
328 * All of these will return true for an alias match.
329 * Wildcards are allowed in the filename.
331 bool TestAliasMatch(const char *alias, const char *localdir);
334 * Returns whether anything loaded will be a late load.
336 bool IsLateLoadTime() const;
339 * Adds natives from core into the native pool.
341 void RegisterNativesFromCore(sp_nativeinfo_t *natives);
344 * Converts a Handle to an IPlugin if possible.
346 IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
349 * Finds a plugin based on its index. (starts on index 1)
351 CPlugin *GetPluginByOrder(int num);
354 * Internal version of FindPluginByContext()
356 inline CPlugin *GetPluginByCtx(const sp_context_t *ctx)
358 return reinterpret_cast<CPlugin *>(ctx->user[SM_CONTEXTVAR_MYSELF]);
362 * Gets status text for a status code
364 const char *GetStatusText(PluginStatus status);
367 * Reload or update plugins on level shutdown.
369 void ReloadOrUnloadPlugins();
372 * Add public functions from all running or paused
373 * plugins to the specified forward if the names match.
375 void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
377 CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
380 LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
382 void LoadAutoPlugin(const char *plugin);
385 * Recursively loads all plugins in the given directory.
387 void LoadPluginsFromDir(const char *basedir, const char *localdir);
390 * Adds a plugin object. This is wrapped by LoadPlugin functions.
392 void AddPlugin(CPlugin *pPlugin);
395 * Runs the second loading pass on a plugin.
397 bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
400 * Adds any globally registered natives to a plugin
402 void AddCoreNativesToPlugin(CPlugin *pPlugin);
405 * Runs an extension pass on a plugin.
407 bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
409 void _SetPauseState(CPlugin *pPlugin, bool pause);
411 void ExecAndGenPluginConfs();
414 * Caching internal objects
416 void ReleaseIterator(CPluginIterator *iter);
418 inline IdentityToken_t *GetIdentity()
423 bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
425 void AddFakeNativesToPlugin(CPlugin *pPlugin);
426 void TryRefreshNatives(CPlugin *pOther);
428 List<IPluginsListener *> m_listeners;
429 List<CPlugin *> m_plugins;
430 List<sp_nativeinfo_t *> m_natives;
431 CStack<CPluginManager::CPluginIterator *> m_iters;
432 CPluginInfoDatabase m_PluginInfo;
434 bool m_AllPluginsLoaded;
435 IdentityToken_t *m_MyIdent;
437 /* Dynamic native stuff */
438 List<FakeNative *> m_Natives;
439 Trie *m_pNativeLookup;
443 extern CPluginManager g_PluginSys;
445 #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_