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,
122 WeakNative(CPlugin *plugin, uint32_t index)
131 class CPlugin : public IPlugin
133 friend class CPluginManager;
134 friend class CFunction;
136 CPlugin(const char *file);
139 PluginType GetType();
140 SourcePawn::IPluginContext *GetBaseContext();
141 sp_context_t *GetContext();
142 const sm_plugininfo_t *GetPublicInfo();
143 const char *GetFilename();
145 PluginStatus GetStatus();
146 bool SetPauseState(bool paused);
147 unsigned int GetSerial();
148 const sp_plugin_t *GetPluginStructure();
149 IdentityToken_t *GetIdentity();
150 bool SetProperty(const char *prop, void *ptr);
151 bool GetProperty(const char *prop, void **ptr, bool remove=false);
154 * Creates a plugin object with default values.
155 * If an error buffer is specified, and an error occurs, the error will be copied to the buffer
156 * and NULL will be returned.
157 * If an error buffer is not specified, the error will be copied to an internal buffer and
158 * a valid (but error-stated) CPlugin will be returned.
160 static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
163 * Starts the initial compilation of a plugin.
164 * Returns false if another compilation exists or there is a current context set.
166 ICompilation *StartMyCompile(IVirtualMachine *vm);
168 * Finalizes a compilation. If error buffer is NULL, the error is saved locally.
170 bool FinishMyCompile(char *error, size_t maxlength);
171 void CancelMyCompile();
174 * Sets an error state on the plugin
176 void SetErrorState(PluginStatus status, const char *error_fmt, ...);
179 * Initializes the plugin's identity information
184 * Calls the OnPluginLoad function, and sets any failed states if necessary.
185 * NOTE: Valid pre-states are: Plugin_Created
186 * NOTE: If validated, plugin state is changed to Plugin_Loaded
188 * If the error buffer is NULL, the error message is cached locally.
190 bool Call_AskPluginLoad(char *error, size_t maxlength);
193 * Calls the OnPluginStart function.
194 * NOTE: Valid pre-states are: Plugin_Created
195 * NOTE: Post-state will be Plugin_Running
197 void Call_OnPluginStart();
200 * Calls the OnPluginEnd function.
202 void Call_OnPluginEnd();
205 * Toggles debug mode in the plugin
207 bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
210 * Returns true if a plugin is usable.
215 * Adds a language file index to the plugin's list.
217 void AddLangFile(unsigned int index);
220 * Get language file count for this plugin.
222 size_t GetLangFileCount();
225 * Get language file index based on the vector index.
227 unsigned int GetLangFileByIndex(unsigned int index);
230 * Returns the modification time during last plugin load.
232 time_t GetTimeStamp();
235 * Returns the current modification time of the plugin file.
237 time_t GetFileTimeStamp();
240 * Returns true if the plugin was running, but is now invalid.
244 Handle_t GetMyHandle();
246 void AddConfig(bool autoCreate, const char *cfg, const char *folder);
247 unsigned int GetConfigCount();
248 AutoConfig *GetConfig(unsigned int i);
249 inline void AddLibrary(const char *name)
251 m_Libraries.push_back(name);
255 void SetTimeStamp(time_t t);
256 void DependencyDropped(CPlugin *pOwner);
260 char m_filename[PLATFORM_MAX_PATH];
261 PluginStatus m_status;
262 unsigned int m_serial;
263 sm_plugininfo_t m_info;
264 sp_plugin_t *m_plugin;
265 char m_errormsg[256];
267 IdentityToken_t *m_ident;
270 CVector<unsigned int> m_PhraseFiles;
271 List<CPlugin *> m_dependents;
272 List<CPlugin *> m_dependsOn;
273 List<FakeNative *> m_fakeNatives;
274 List<WeakNative> m_WeakNatives;
275 List<String> m_RequiredLibs;
276 List<String> m_Libraries;
278 bool m_FakeNativesMissing;
279 bool m_LibraryMissing;
280 CVector<AutoConfig *> m_configs;
283 class CPluginManager :
284 public IPluginManager,
285 public SMGlobalClass,
286 public IHandleTypeDispatch,
287 public IRootConsoleCommand
289 friend class CPlugin;
294 /* Implements iterator class */
295 class CPluginIterator : public IPluginIterator
298 CPluginIterator(List<CPlugin *> *mylist);
299 virtual ~CPluginIterator();
300 virtual bool MorePlugins();
301 virtual IPlugin *GetPlugin();
302 virtual void NextPlugin();
307 List<CPlugin *> *mylist;
308 List<CPlugin *>::iterator current;
310 friend class CPluginManager::CPluginIterator;
311 public: //IPluginManager
312 IPlugin *LoadPlugin(const char *path,
318 bool UnloadPlugin(IPlugin *plugin);
319 IPlugin *FindPluginByContext(const sp_context_t *ctx);
320 unsigned int GetPluginCount();
321 IPluginIterator *GetPluginIterator();
322 void AddPluginsListener(IPluginsListener *listener);
323 void RemovePluginsListener(IPluginsListener *listener);
324 public: //SMGlobalClass
325 void OnSourceModAllInitialized();
326 void OnSourceModShutdown();
327 public: //IHandleTypeDispatch
328 void OnHandleDestroy(HandleType_t type, void *object);
329 public: //IRootConsoleCommand
330 void OnRootConsoleCommand(const char *command, unsigned int argcount);
333 * Loads all plugins not yet loaded
335 void LoadAll_FirstPass(const char *config, const char *basedir);
338 * Runs the second loading pass for all plugins
340 void LoadAll_SecondPass();
343 * Tests a plugin file mask against a local folder.
344 * The alias is searched backwards from localdir - i.e., given this input:
347 * csdm/ban optional/csdm/ban
348 * All of these will return true for an alias match.
349 * Wildcards are allowed in the filename.
351 bool TestAliasMatch(const char *alias, const char *localdir);
354 * Returns whether anything loaded will be a late load.
356 bool IsLateLoadTime() const;
359 * Adds natives from core into the native pool.
361 void RegisterNativesFromCore(sp_nativeinfo_t *natives);
364 * Converts a Handle to an IPlugin if possible.
366 IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
369 * Finds a plugin based on its index. (starts on index 1)
371 CPlugin *GetPluginByOrder(int num);
374 * Internal version of FindPluginByContext()
376 inline CPlugin *GetPluginByCtx(const sp_context_t *ctx)
378 return reinterpret_cast<CPlugin *>(ctx->user[SM_CONTEXTVAR_MYSELF]);
382 * Gets status text for a status code
384 const char *GetStatusText(PluginStatus status);
387 * Reload or update plugins on level shutdown.
389 void ReloadOrUnloadPlugins();
392 * Add public functions from all running or paused
393 * plugins to the specified forward if the names match.
395 void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
397 CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
402 LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
404 void LoadAutoPlugin(const char *plugin);
407 * Recursively loads all plugins in the given directory.
409 void LoadPluginsFromDir(const char *basedir, const char *localdir);
412 * Adds a plugin object. This is wrapped by LoadPlugin functions.
414 void AddPlugin(CPlugin *pPlugin);
417 * Runs the second loading pass on a plugin.
419 bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
422 * Adds any globally registered natives to a plugin
424 void AddCoreNativesToPlugin(CPlugin *pPlugin);
427 * Runs an extension pass on a plugin.
429 bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
432 * Manages required natives.
434 bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
436 void _SetPauseState(CPlugin *pPlugin, bool pause);
438 void ExecAndGenPluginConfs();
441 * Caching internal objects
443 void ReleaseIterator(CPluginIterator *iter);
445 inline IdentityToken_t *GetIdentity()
450 bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
452 void AddFakeNativesToPlugin(CPlugin *pPlugin);
453 void TryRefreshDependencies(CPlugin *pOther);
455 List<IPluginsListener *> m_listeners;
456 List<CPlugin *> m_plugins;
457 List<sp_nativeinfo_t *> m_natives;
458 CStack<CPluginManager::CPluginIterator *> m_iters;
459 CPluginInfoDatabase m_PluginInfo;
461 bool m_AllPluginsLoaded;
462 IdentityToken_t *m_MyIdent;
464 /* Dynamic native stuff */
465 List<FakeNative *> m_Natives;
466 Trie *m_pNativeLookup;
470 extern CPluginManager g_PluginSys;
472 #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_