1.1 --- a/core/systems/PluginSys.h Fri Mar 28 06:21:34 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,515 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
1.36 -#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
1.37 -
1.38 -#include <time.h>
1.39 -#include <errno.h>
1.40 -#include <sys/stat.h>
1.41 -#include <IPluginSys.h>
1.42 -#include <IHandleSys.h>
1.43 -#include <IForwardSys.h>
1.44 -#include <sh_list.h>
1.45 -#include <sh_stack.h>
1.46 -#include <sh_vector.h>
1.47 -#include <sh_string.h>
1.48 -#include "sm_globals.h"
1.49 -#include "vm/sp_vm_basecontext.h"
1.50 -#include "PluginInfoDatabase.h"
1.51 -#include "sm_trie.h"
1.52 -#include "sourcemod.h"
1.53 -#include <IRootConsoleMenu.h>
1.54 -#if defined ORANGEBOX_BUILD
1.55 -#include "convar_sm_ob.h"
1.56 -#else
1.57 -#include "convar_sm.h"
1.58 -#endif
1.59 -
1.60 -using namespace SourceHook;
1.61 -
1.62 -/**
1.63 - * NOTES:
1.64 - *
1.65 - * Currently this system needs a lot of work but it's good skeletally. Plugin creation
1.66 - * is done without actually compiling anything. This is done by Load functions in the
1.67 - * manager. This will need a rewrite when we add context switching.
1.68 - *
1.69 - * The plugin object itself has a few things to note. The most important is that it stores
1.70 - * a table of function objects. The manager marshals allocation and freeing of these objects.
1.71 - * The plugin object can be in erroneous states, they are:
1.72 - * Plugin_Error --> Some error occurred any time during or after compilation.
1.73 - * This error can be cleared since the plugin itself is valid.
1.74 - * However, the state itself being set prevents any runtime action.
1.75 - * Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
1.76 - *
1.77 - * If a plugin fails to load externally, it is never added to the internal tracker. However,
1.78 - * plugins that failed to load from the internal loading mechanism are always tracked. This
1.79 - * allows users to see which automatically loaded plugins failed, and makes the interface a bit
1.80 - * more flexible.
1.81 - *
1.82 - * Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
1.83 - * for execution. SourceMod is a two pass system, and even though the second pass is not implemented
1.84 - * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
1.85 - * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
1.86 - *
1.87 - * The two pass loading mechanism is described below. Modules/natives are not implemented yet.
1.88 - * PASS ONE: All loadable plugins are found and have the following steps performed:
1.89 - * 1. Loading and compilation is attempted.
1.90 - * 2. If successful, all natives from Core are added.
1.91 - * 3. OnPluginLoad() is called.
1.92 - * 4. If failed, any user natives are scrapped and the process halts here.
1.93 - * 5. If successful, the plugin is ready for Pass 2.
1.94 - * INTERMEDIATE:
1.95 - * 1. All forced modules are loaded.
1.96 - * PASS TWO: All loaded plugins are found and have these steps performed:
1.97 - * 1. Any modules referenced in the plugin that are not already loaded, are loaded.
1.98 - * 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
1.99 - * 3. If any natives are unresolved, check if they are found in the user-natives pool.
1.100 - * 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
1.101 - * 5. If the filter fails, the plugin is marked as failed.
1.102 - * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
1.103 - * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
1.104 - * PASS THREE (not a real pass):
1.105 - * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
1.106 - */
1.107 -
1.108 -#define SM_CONTEXTVAR_MYSELF 0
1.109 -
1.110 -struct ContextPair
1.111 -{
1.112 - ContextPair() : base(NULL), ctx(NULL), co(NULL)
1.113 - {
1.114 - };
1.115 - BaseContext *base;
1.116 - sp_context_t *ctx;
1.117 - ICompilation *co;
1.118 - IVirtualMachine *vm;
1.119 -};
1.120 -
1.121 -struct FakeNative
1.122 -{
1.123 - IPluginContext *ctx;
1.124 - IPluginFunction *call;
1.125 - String name;
1.126 - SPVM_NATIVE_FUNC func;
1.127 -};
1.128 -
1.129 -enum LoadRes
1.130 -{
1.131 - LoadRes_Successful,
1.132 - LoadRes_AlreadyLoaded,
1.133 - LoadRes_Failure,
1.134 - LoadRes_NeverLoad
1.135 -};
1.136 -
1.137 -struct AutoConfig
1.138 -{
1.139 - String autocfg;
1.140 - String folder;
1.141 - bool create;
1.142 -};
1.143 -
1.144 -class CPlugin;
1.145 -struct WeakNative
1.146 -{
1.147 - WeakNative(CPlugin *plugin, uint32_t index)
1.148 - {
1.149 - pl = plugin;
1.150 - idx = index;
1.151 - }
1.152 - CPlugin *pl;
1.153 - uint32_t idx;
1.154 -};
1.155 -
1.156 -class CPlugin : public IPlugin
1.157 -{
1.158 - friend class CPluginManager;
1.159 - friend class CFunction;
1.160 -public:
1.161 - CPlugin(const char *file);
1.162 - ~CPlugin();
1.163 -public:
1.164 - PluginType GetType();
1.165 - SourcePawn::IPluginContext *GetBaseContext();
1.166 - sp_context_t *GetContext();
1.167 - const sm_plugininfo_t *GetPublicInfo();
1.168 - const char *GetFilename();
1.169 - bool IsDebugging();
1.170 - PluginStatus GetStatus();
1.171 - bool SetPauseState(bool paused);
1.172 - unsigned int GetSerial();
1.173 - const sp_plugin_t *GetPluginStructure();
1.174 - IdentityToken_t *GetIdentity();
1.175 - bool SetProperty(const char *prop, void *ptr);
1.176 - bool GetProperty(const char *prop, void **ptr, bool remove=false);
1.177 -public:
1.178 - /**
1.179 - * Creates a plugin object with default values.
1.180 - * If an error buffer is specified, and an error occurs, the error will be copied to the buffer
1.181 - * and NULL will be returned.
1.182 - * If an error buffer is not specified, the error will be copied to an internal buffer and
1.183 - * a valid (but error-stated) CPlugin will be returned.
1.184 - */
1.185 - static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
1.186 -public:
1.187 - /**
1.188 - * Starts the initial compilation of a plugin.
1.189 - * Returns false if another compilation exists or there is a current context set.
1.190 - */
1.191 - ICompilation *StartMyCompile(IVirtualMachine *vm);
1.192 - /**
1.193 - * Finalizes a compilation. If error buffer is NULL, the error is saved locally.
1.194 - */
1.195 - bool FinishMyCompile(char *error, size_t maxlength);
1.196 - void CancelMyCompile();
1.197 -
1.198 - /**
1.199 - * Sets an error state on the plugin
1.200 - */
1.201 - void SetErrorState(PluginStatus status, const char *error_fmt, ...);
1.202 -
1.203 - /**
1.204 - * Initializes the plugin's identity information
1.205 - */
1.206 - void InitIdentity();
1.207 -
1.208 - /**
1.209 - * Calls the OnPluginLoad function, and sets any failed states if necessary.
1.210 - * NOTE: Valid pre-states are: Plugin_Created
1.211 - * NOTE: If validated, plugin state is changed to Plugin_Loaded
1.212 - *
1.213 - * If the error buffer is NULL, the error message is cached locally.
1.214 - */
1.215 - bool Call_AskPluginLoad(char *error, size_t maxlength);
1.216 -
1.217 - /**
1.218 - * Calls the OnPluginStart function.
1.219 - * NOTE: Valid pre-states are: Plugin_Created
1.220 - * NOTE: Post-state will be Plugin_Running
1.221 - */
1.222 - void Call_OnPluginStart();
1.223 -
1.224 - /**
1.225 - * Calls the OnPluginEnd function.
1.226 - */
1.227 - void Call_OnPluginEnd();
1.228 -
1.229 - /**
1.230 - * Calls the OnAllPluginsLoaded function.
1.231 - */
1.232 - void Call_OnAllPluginsLoaded();
1.233 -
1.234 - /**
1.235 - * Toggles debug mode in the plugin
1.236 - */
1.237 - bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
1.238 -
1.239 - /**
1.240 - * Returns true if a plugin is usable.
1.241 - */
1.242 - bool IsRunnable();
1.243 -
1.244 - /**
1.245 - * Adds a language file index to the plugin's list.
1.246 - */
1.247 - void AddLangFile(unsigned int index);
1.248 -
1.249 - /**
1.250 - * Get language file count for this plugin.
1.251 - */
1.252 - size_t GetLangFileCount();
1.253 -
1.254 - /**
1.255 - * Get language file index based on the vector index.
1.256 - */
1.257 - unsigned int GetLangFileByIndex(unsigned int index);
1.258 -public:
1.259 - /**
1.260 - * Returns the modification time during last plugin load.
1.261 - */
1.262 - time_t GetTimeStamp();
1.263 -
1.264 - /**
1.265 - * Returns the current modification time of the plugin file.
1.266 - */
1.267 - time_t GetFileTimeStamp();
1.268 -
1.269 - /**
1.270 - * Returns true if the plugin was running, but is now invalid.
1.271 - */
1.272 - bool WasRunning();
1.273 -
1.274 - Handle_t GetMyHandle();
1.275 -
1.276 - void AddConfig(bool autoCreate, const char *cfg, const char *folder);
1.277 - unsigned int GetConfigCount();
1.278 - AutoConfig *GetConfig(unsigned int i);
1.279 - inline void AddLibrary(const char *name)
1.280 - {
1.281 - m_Libraries.push_back(name);
1.282 - }
1.283 - void LibraryActions(bool dropping);
1.284 -protected:
1.285 - void UpdateInfo();
1.286 - void SetTimeStamp(time_t t);
1.287 - void DependencyDropped(CPlugin *pOwner);
1.288 -private:
1.289 - ContextPair m_ctx;
1.290 - PluginType m_type;
1.291 - char m_filename[PLATFORM_MAX_PATH];
1.292 - PluginStatus m_status;
1.293 - unsigned int m_serial;
1.294 - sm_plugininfo_t m_info;
1.295 - sp_plugin_t *m_plugin;
1.296 - char m_errormsg[256];
1.297 - time_t m_LastAccess;
1.298 - IdentityToken_t *m_ident;
1.299 - Handle_t m_handle;
1.300 - bool m_WasRunning;
1.301 - CVector<unsigned int> m_PhraseFiles;
1.302 - List<CPlugin *> m_dependents;
1.303 - List<CPlugin *> m_dependsOn;
1.304 - List<FakeNative *> m_fakeNatives;
1.305 - List<WeakNative> m_WeakNatives;
1.306 - List<String> m_RequiredLibs;
1.307 - List<String> m_Libraries;
1.308 - Trie *m_pProps;
1.309 - bool m_FakeNativesMissing;
1.310 - bool m_LibraryMissing;
1.311 - CVector<AutoConfig *> m_configs;
1.312 - bool m_bGotAllLoaded;
1.313 -};
1.314 -
1.315 -class CPluginManager :
1.316 - public IPluginManager,
1.317 - public SMGlobalClass,
1.318 - public IHandleTypeDispatch,
1.319 - public IRootConsoleCommand
1.320 -{
1.321 - friend class CPlugin;
1.322 -public:
1.323 - CPluginManager();
1.324 - ~CPluginManager();
1.325 -public:
1.326 - /* Implements iterator class */
1.327 - class CPluginIterator : public IPluginIterator
1.328 - {
1.329 - public:
1.330 - CPluginIterator(List<CPlugin *> *mylist);
1.331 - virtual ~CPluginIterator();
1.332 - virtual bool MorePlugins();
1.333 - virtual IPlugin *GetPlugin();
1.334 - virtual void NextPlugin();
1.335 - void Release();
1.336 - public:
1.337 - void Reset();
1.338 - private:
1.339 - List<CPlugin *> *mylist;
1.340 - List<CPlugin *>::iterator current;
1.341 - };
1.342 - friend class CPluginManager::CPluginIterator;
1.343 -public: //IPluginManager
1.344 - IPlugin *LoadPlugin(const char *path,
1.345 - bool debug,
1.346 - PluginType type,
1.347 - char error[],
1.348 - size_t maxlength,
1.349 - bool *wasloaded);
1.350 - bool UnloadPlugin(IPlugin *plugin);
1.351 - IPlugin *FindPluginByContext(const sp_context_t *ctx);
1.352 - unsigned int GetPluginCount();
1.353 - IPluginIterator *GetPluginIterator();
1.354 - void AddPluginsListener(IPluginsListener *listener);
1.355 - void RemovePluginsListener(IPluginsListener *listener);
1.356 -public: //SMGlobalClass
1.357 - void OnSourceModAllInitialized();
1.358 - void OnSourceModShutdown();
1.359 -public: //IHandleTypeDispatch
1.360 - void OnHandleDestroy(HandleType_t type, void *object);
1.361 -public: //IRootConsoleCommand
1.362 - void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
1.363 -public:
1.364 - /**
1.365 - * Loads all plugins not yet loaded
1.366 - */
1.367 - void LoadAll_FirstPass(const char *config, const char *basedir);
1.368 -
1.369 - /**
1.370 - * Runs the second loading pass for all plugins
1.371 - */
1.372 - void LoadAll_SecondPass();
1.373 -
1.374 - /**
1.375 - * Tests a plugin file mask against a local folder.
1.376 - * The alias is searched backwards from localdir - i.e., given this input:
1.377 - * csdm/ban csdm/ban
1.378 - * ban csdm/ban
1.379 - * csdm/ban optional/csdm/ban
1.380 - * All of these will return true for an alias match.
1.381 - * Wildcards are allowed in the filename.
1.382 - */
1.383 - bool TestAliasMatch(const char *alias, const char *localdir);
1.384 -
1.385 - /**
1.386 - * Returns whether anything loaded will be a late load.
1.387 - */
1.388 - bool IsLateLoadTime() const;
1.389 -
1.390 - /**
1.391 - * Adds natives from core into the native pool.
1.392 - */
1.393 - void RegisterNativesFromCore(sp_nativeinfo_t *natives);
1.394 -
1.395 - /**
1.396 - * Converts a Handle to an IPlugin if possible.
1.397 - */
1.398 - IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
1.399 -
1.400 - /**
1.401 - * Finds a plugin based on its index. (starts on index 1)
1.402 - */
1.403 - CPlugin *GetPluginByOrder(int num);
1.404 -
1.405 - int GetOrderOfPlugin(IPlugin *pl);
1.406 -
1.407 - /**
1.408 - * Internal version of FindPluginByContext()
1.409 - */
1.410 - inline CPlugin *GetPluginByCtx(const sp_context_t *ctx)
1.411 - {
1.412 - return reinterpret_cast<CPlugin *>(ctx->user[SM_CONTEXTVAR_MYSELF]);
1.413 - }
1.414 -
1.415 - /**
1.416 - * Gets status text for a status code
1.417 - */
1.418 - const char *GetStatusText(PluginStatus status);
1.419 -
1.420 - /**
1.421 - * Reload or update plugins on level shutdown.
1.422 - */
1.423 - void ReloadOrUnloadPlugins();
1.424 -
1.425 - /**
1.426 - * Add public functions from all running or paused
1.427 - * plugins to the specified forward if the names match.
1.428 - */
1.429 - void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
1.430 -
1.431 - /**
1.432 - * Iterates through plugins to call OnAllPluginsLoaded.
1.433 - */
1.434 - void AllPluginsLoaded();
1.435 -
1.436 - CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
1.437 -
1.438 - void Shutdown();
1.439 -
1.440 - void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
1.441 -
1.442 - bool LibraryExists(const char *lib);
1.443 -
1.444 - bool ReloadPlugin(CPlugin *pl);
1.445 -
1.446 - void UnloadAll();
1.447 -private:
1.448 - LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
1.449 -
1.450 - void LoadAutoPlugin(const char *plugin);
1.451 -
1.452 - /**
1.453 - * Recursively loads all plugins in the given directory.
1.454 - */
1.455 - void LoadPluginsFromDir(const char *basedir, const char *localdir);
1.456 -
1.457 - /**
1.458 - * Adds a plugin object. This is wrapped by LoadPlugin functions.
1.459 - */
1.460 - void AddPlugin(CPlugin *pPlugin);
1.461 -
1.462 - /**
1.463 - * Runs the second loading pass on a plugin.
1.464 - */
1.465 - bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
1.466 -
1.467 - /**
1.468 - * Adds any globally registered natives to a plugin
1.469 - */
1.470 - void AddCoreNativesToPlugin(CPlugin *pPlugin);
1.471 -
1.472 - /**
1.473 - * Runs an extension pass on a plugin.
1.474 - */
1.475 - bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
1.476 -
1.477 - /**
1.478 - * Manages required natives.
1.479 - */
1.480 - bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
1.481 -
1.482 - void _SetPauseState(CPlugin *pPlugin, bool pause);
1.483 -protected:
1.484 - /**
1.485 - * Caching internal objects
1.486 - */
1.487 - void ReleaseIterator(CPluginIterator *iter);
1.488 -public:
1.489 - inline IdentityToken_t *GetIdentity()
1.490 - {
1.491 - return m_MyIdent;
1.492 - }
1.493 -public:
1.494 - bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
1.495 - SPVM_NATIVE_FUNC FindCoreNative(const char *name);
1.496 -private:
1.497 - void AddFakeNativesToPlugin(CPlugin *pPlugin);
1.498 - void TryRefreshDependencies(CPlugin *pOther);
1.499 -private:
1.500 - List<IPluginsListener *> m_listeners;
1.501 - List<CPlugin *> m_plugins;
1.502 - CStack<CPluginManager::CPluginIterator *> m_iters;
1.503 - CPluginInfoDatabase m_PluginInfo;
1.504 - Trie *m_LoadLookup;
1.505 - bool m_AllPluginsLoaded;
1.506 - IdentityToken_t *m_MyIdent;
1.507 - Trie *m_pCoreNatives;
1.508 -
1.509 - /* Dynamic native stuff */
1.510 - List<FakeNative *> m_Natives;
1.511 - Trie *m_pNativeLookup;
1.512 -
1.513 - bool m_LoadingLocked;
1.514 -};
1.515 -
1.516 -extern CPluginManager g_PluginSys;
1.517 -
1.518 -#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_