core/logic/PluginSys.h
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4065 0f85577d23ee
permissions -rw-r--r--
Update CS:GO team score gamedata.
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
    33 #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
    34 
    35 #include <time.h>
    36 #include <errno.h>
    37 #include <sys/stat.h>
    38 #include <IPluginSys.h>
    39 #include <IHandleSys.h>
    40 #include <IForwardSys.h>
    41 #include <sh_list.h>
    42 #include <sh_stack.h>
    43 #include <sh_vector.h>
    44 #include <sh_string.h>
    45 #include "common_logic.h"
    46 #include <IRootConsoleMenu.h>
    47 #include <sm_stringhashmap.h>
    48 #include <sm_namehashset.h>
    49 #include "ITranslator.h"
    50 #include "IGameConfigs.h"
    51 #include "NativeOwner.h"
    52 #include "ShareSys.h"
    53 
    54 class CPlayer;
    55 
    56 using namespace SourceHook;
    57 
    58 /**
    59  * NOTES:
    60  *
    61  * UPDATE 2008-03-11: These comments are horribly out of date.  They paint a good overall 
    62  * picture of how PluginSys works, but things like dependencies and fake natives have 
    63  * complicated things quite a bit.
    64  *
    65  *  Currently this system needs a lot of work but it's good skeletally.  Plugin creation 
    66  * is done without actually compiling anything.  This is done by Load functions in the 
    67  * manager.  This will need a rewrite when we add context switching.
    68  *
    69  *  The plugin object itself has a few things to note.  The most important is that it stores
    70  * a table of function objects.  The manager marshals allocation and freeing of these objects.
    71  * The plugin object can be in erroneous states, they are:
    72  *   Plugin_Error   --> Some error occurred any time during or after compilation.
    73  *						This error can be cleared since the plugin itself is valid.
    74  *						However, the state itself being set prevents any runtime action.
    75  *   Plugin_BadLoad	--> The plugin failed to load entirely and nothing can be done to save it.
    76  *
    77  *  If a plugin fails to load externally, it is never added to the internal tracker.  However, 
    78  * plugins that failed to load from the internal loading mechanism are always tracked.  This 
    79  * allows users to see which automatically loaded plugins failed, and makes the interface a bit
    80  * more flexible.
    81  *
    82  *  Once a plugin is compiled, it sets its own state to Plugin_Created.  This state is still invalid
    83  * for execution.  SourceMod is a two pass system, and even though the second pass is not implemented
    84  * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass.  When
    85  * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
    86  *
    87  *  The two pass loading mechanism is described below.  Modules/natives are not implemented yet.
    88  * PASS ONE: All loadable plugins are found and have the following steps performed:
    89  *			 1.  Loading and compilation is attempted.
    90  *			 2.  If successful, all natives from Core are added.
    91  *			 3.  OnPluginLoad() is called.
    92  *			 4.  If failed, any user natives are scrapped and the process halts here.
    93  *			 5.  If successful, the plugin is ready for Pass 2.
    94  * INTERMEDIATE:
    95  *			 1.  All forced modules are loaded.
    96  * PASS TWO: All loaded plugins are found and have these steps performed:
    97  *			 1. Any modules referenced in the plugin that are not already loaded, are loaded.
    98  *			 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
    99  *			 3. If any natives are unresolved, check if they are found in the user-natives pool.
   100  *			 4. If yes, load succeeds.  If not, natives are passed through a native acceptance filter.
   101  *			 5. If the filter fails, the plugin is marked as failed.
   102  *			 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
   103  *			    Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
   104  * PASS THREE (not a real pass):
   105  *			 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
   106  */
   107 
   108 enum LoadRes
   109 {
   110 	LoadRes_Successful,
   111 	LoadRes_AlreadyLoaded,
   112 	LoadRes_Failure,
   113 	LoadRes_SilentFailure,
   114 	LoadRes_NeverLoad
   115 };
   116 
   117 enum APLRes
   118 {
   119 	APLRes_Success,
   120 	APLRes_Failure,
   121 	APLRes_SilentFailure
   122 };
   123 
   124 class CPlugin : 
   125 	public SMPlugin,
   126 	public CNativeOwner
   127 {
   128 	friend class CPluginManager;
   129 	friend class CFunction;
   130 public:
   131 	CPlugin(const char *file);
   132 	~CPlugin();
   133 public:
   134 	PluginType GetType();
   135 	SourcePawn::IPluginContext *GetBaseContext();
   136 	sp_context_t *GetContext();
   137 	void *GetPluginStructure();
   138 	const char *GetFilename();
   139 	bool IsDebugging();
   140 	PluginStatus GetStatus();
   141 	bool IsSilentlyFailed();
   142 	void SetSilentlyFailed(bool sf);
   143 	const sm_plugininfo_t *GetPublicInfo();
   144 	bool SetPauseState(bool paused);
   145 	unsigned int GetSerial();
   146 	IdentityToken_t *GetIdentity();
   147 	unsigned int CalcMemUsage();
   148 	bool SetProperty(const char *prop, void *ptr);
   149 	bool GetProperty(const char *prop, void **ptr, bool remove=false);
   150 	void DropEverything();
   151 	SourcePawn::IPluginRuntime *GetRuntime();
   152 	CNativeOwner *ToNativeOwner() {
   153 		return this;
   154 	}
   155 public:
   156 	/**
   157 	 * Creates a plugin object with default values.
   158 	 *   If an error buffer is specified, and an error occurs, the error will be copied to the buffer
   159 	 * and NULL will be returned.
   160 	 *   If an error buffer is not specified, the error will be copied to an internal buffer and 
   161 	 * a valid (but error-stated) CPlugin will be returned.
   162 	 */
   163 	static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
   164 
   165 	static inline bool matches(const char *file, const CPlugin *plugin)
   166 	{
   167 		return strcmp(plugin->m_filename, file) == 0;
   168 	}
   169 public:
   170 
   171 	/**
   172 	 * Sets an error state on the plugin
   173 	 */
   174 	void SetErrorState(PluginStatus status, const char *error_fmt, ...);
   175 
   176 	/**
   177 	 * Initializes the plugin's identity information
   178 	 */
   179 	void InitIdentity();
   180 
   181 	/**
   182 	 * Calls the OnPluginLoad function, and sets any failed states if necessary.
   183 	 * NOTE: Valid pre-states are: Plugin_Created
   184 	 * NOTE: If validated, plugin state is changed to Plugin_Loaded
   185 	 *
   186 	 * If the error buffer is NULL, the error message is cached locally.
   187 	 */
   188 	APLRes Call_AskPluginLoad(char *error, size_t maxlength);
   189 
   190 	/**
   191 	 * Calls the OnPluginStart function.
   192 	 * NOTE: Valid pre-states are: Plugin_Created
   193 	 * NOTE: Post-state will be Plugin_Running
   194 	 */
   195 	void Call_OnPluginStart();
   196 
   197 	/**
   198 	 * Calls the OnPluginEnd function.
   199 	 */
   200 	void Call_OnPluginEnd();
   201 
   202 	/**
   203 	 * Calls the OnAllPluginsLoaded function.
   204 	 */
   205 	void Call_OnAllPluginsLoaded();
   206 
   207 	/**
   208 	 * Returns true if a plugin is usable.
   209 	 */
   210 	bool IsRunnable();
   211 
   212 	/**
   213 	 * Get languages info.
   214 	 */
   215 	IPhraseCollection *GetPhrases();
   216 public:
   217 	/**
   218 	 * Returns the modification time during last plugin load.
   219 	 */
   220 	time_t GetTimeStamp();
   221 
   222 	/**
   223 	 * Returns the current modification time of the plugin file.
   224 	 */
   225 	time_t GetFileTimeStamp();
   226 
   227 	/** 
   228 	 * Returns true if the plugin was running, but is now invalid.
   229 	 */
   230 	bool WasRunning();
   231 
   232 	Handle_t GetMyHandle();
   233 
   234 	bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
   235 	void AddConfig(bool autoCreate, const char *cfg, const char *folder);
   236 	size_t GetConfigCount();
   237 	AutoConfig *GetConfig(size_t i);
   238 	inline void AddLibrary(const char *name)
   239 	{
   240 		m_Libraries.push_back(name);
   241 	}
   242 	void LibraryActions(LibraryAction action);
   243 	void SyncMaxClients(int max_clients);
   244 protected:
   245 	bool UpdateInfo();
   246 	void SetTimeStamp(time_t t);
   247 	void DependencyDropped(CPlugin *pOwner);
   248 private:
   249 	PluginType m_type;
   250 	char m_filename[PLATFORM_MAX_PATH];
   251 	PluginStatus m_status;
   252 	bool m_bSilentlyFailed;
   253 	unsigned int m_serial;
   254 	sm_plugininfo_t m_info;
   255 	char m_errormsg[256];
   256 	time_t m_LastAccess;
   257 	IdentityToken_t *m_ident;
   258 	Handle_t m_handle;
   259 	bool m_WasRunning;
   260 	IPhraseCollection *m_pPhrases;
   261 	List<String> m_RequiredLibs;
   262 	List<String> m_Libraries;
   263 	StringHashMap<void *> m_Props;
   264 	bool m_FakeNativesMissing;
   265 	bool m_LibraryMissing;
   266 	CVector<AutoConfig *> m_configs;
   267 	bool m_bGotAllLoaded;
   268 	int m_FileVersion;
   269 	char m_DateTime[256];
   270 	IPluginRuntime *m_pRuntime;
   271 	IPluginContext *m_pContext;
   272 	sp_pubvar_t *m_MaxClientsVar;
   273 };
   274 
   275 class CPluginManager : 
   276 	public IScriptManager,
   277 	public SMGlobalClass,
   278 	public IHandleTypeDispatch,
   279 	public IRootConsoleCommand
   280 {
   281 	friend class CPlugin;
   282 public:
   283 	CPluginManager();
   284 	~CPluginManager();
   285 public:
   286 	/* Implements iterator class */
   287 	class CPluginIterator : public IPluginIterator
   288 	{
   289 	public:
   290 		CPluginIterator(List<CPlugin *> *mylist);
   291 		virtual ~CPluginIterator();
   292 		virtual bool MorePlugins();
   293 		virtual IPlugin *GetPlugin();
   294 		virtual void NextPlugin();
   295 		void Release();
   296 	public:
   297 		void Reset();
   298 	private:
   299 		List<CPlugin *> *mylist;
   300 		List<CPlugin *>::iterator current;
   301 	};
   302 	friend class CPluginManager::CPluginIterator;
   303 public: //IScriptManager
   304 	IPlugin *LoadPlugin(const char *path, 
   305 								bool debug,
   306 								PluginType type,
   307 								char error[],
   308 								size_t maxlength,
   309 								bool *wasloaded);
   310 	bool UnloadPlugin(IPlugin *plugin);
   311 	IPlugin *FindPluginByContext(const sp_context_t *ctx);
   312 	unsigned int GetPluginCount();
   313 	IPluginIterator *GetPluginIterator();
   314 	void AddPluginsListener(IPluginsListener *listener);
   315 	void RemovePluginsListener(IPluginsListener *listener);
   316 	void LoadAll(const char *config_path, const char *plugins_path);
   317 	void RefreshAll();
   318 	SMPlugin *FindPluginByOrder(unsigned num) {
   319 		return GetPluginByOrder(num);
   320 	}
   321 	SMPlugin *FindPluginByIdentity(IdentityToken_t *ident) {
   322 		return GetPluginFromIdentity(ident);
   323 	}
   324 	SMPlugin *FindPluginByContext(IPluginContext *ctx) {
   325 		return GetPluginByCtx(ctx->GetContext());
   326 	}
   327 	SMPlugin *FindPluginByContext(sp_context_t *ctx) {
   328 		return GetPluginByCtx(ctx);
   329 	}
   330 	SMPlugin *FindPluginByConsoleArg(const char *text);
   331 	SMPlugin *FindPluginByHandle(Handle_t hndl, HandleError *errp) {
   332 		return static_cast<SMPlugin *>(PluginFromHandle(hndl, errp));
   333 	}
   334 	const CVector<SMPlugin *> *ListPlugins();
   335 	void FreePluginList(const CVector<SMPlugin *> *plugins);
   336 public: //SMGlobalClass
   337 	void OnSourceModAllInitialized();
   338 	void OnSourceModShutdown();
   339 	ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
   340 	void OnSourceModMaxPlayersChanged(int newvalue);
   341 public: //IHandleTypeDispatch
   342 	void OnHandleDestroy(HandleType_t type, void *object);
   343 	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
   344 public: //IRootConsoleCommand
   345 	void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
   346 public:
   347 	/**
   348 	 * Loads all plugins not yet loaded
   349 	 */
   350 	void LoadAll_FirstPass(const char *config, const char *basedir);
   351 
   352 	/**
   353 	 * Runs the second loading pass for all plugins
   354 	 */
   355 	void LoadAll_SecondPass();
   356 
   357 	/**
   358 	 * Tests a plugin file mask against a local folder.
   359 	 * The alias is searched backwards from localdir - i.e., given this input:
   360 	 *   csdm/ban        csdm/ban
   361 	 *   ban             csdm/ban
   362 	 *   csdm/ban        optional/csdm/ban
   363 	 * All of these will return true for an alias match.  
   364 	 * Wildcards are allowed in the filename.
   365 	 */
   366 	bool TestAliasMatch(const char *alias, const char *localdir);
   367 
   368 	/** 
   369 	 * Returns whether anything loaded will be a late load.
   370 	 */
   371 	bool IsLateLoadTime() const;
   372 
   373 	/**
   374 	 * Converts a Handle to an IPlugin if possible.
   375 	 */
   376 	IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
   377 
   378 	/**
   379 	 * Finds a plugin based on its index. (starts on index 1)
   380 	 */
   381 	CPlugin *GetPluginByOrder(int num);
   382 
   383 	int GetOrderOfPlugin(IPlugin *pl);
   384 
   385 	/** 
   386 	 * Internal version of FindPluginByContext()
   387 	 */
   388 	CPlugin *GetPluginByCtx(const sp_context_t *ctx);
   389 
   390 	/**
   391 	 * Gets status text for a status code 
   392 	 */
   393 	const char *GetStatusText(PluginStatus status);
   394 
   395 	/**
   396 	 * Add public functions from all running or paused
   397 	 * plugins to the specified forward if the names match.
   398 	 */
   399 	void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
   400 
   401 	/**
   402 	 * Iterates through plugins to call OnAllPluginsLoaded.
   403 	 */
   404 	void AllPluginsLoaded();
   405 
   406 	CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
   407 
   408 	void Shutdown();
   409 
   410 	void OnLibraryAction(const char *lib, LibraryAction action);
   411 
   412 	bool LibraryExists(const char *lib);
   413 
   414 	bool ReloadPlugin(CPlugin *pl);
   415 
   416 	void UnloadAll();
   417 
   418 	void SyncMaxClients(int max_clients);
   419 
   420 	void ListPluginsToClient(CPlayer *player, const CCommand &args);
   421 private:
   422 	LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
   423 
   424 	void LoadAutoPlugin(const char *plugin);
   425 
   426 	/**
   427 	 * Recursively loads all plugins in the given directory.
   428 	 */
   429 	void LoadPluginsFromDir(const char *basedir, const char *localdir);
   430 
   431 	/**
   432 	 * Adds a plugin object.  This is wrapped by LoadPlugin functions.
   433 	 */
   434 	void AddPlugin(CPlugin *pPlugin);
   435 
   436 	/**
   437 	 * Runs the second loading pass on a plugin.
   438 	 */
   439 	bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
   440 
   441 	/**
   442 	 * Runs an extension pass on a plugin.
   443 	 */
   444 	bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
   445 
   446 	/**
   447 	* Manages required natives.
   448 	*/
   449 	bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
   450 
   451 	void _SetPauseState(CPlugin *pPlugin, bool pause);
   452 protected:
   453 	/**
   454 	 * Caching internal objects
   455 	 */
   456 	void ReleaseIterator(CPluginIterator *iter);
   457 public:
   458 	inline IdentityToken_t *GetIdentity()
   459 	{
   460 		return m_MyIdent;
   461 	}
   462 	IPluginManager *GetOldAPI();
   463 private:
   464 	void TryRefreshDependencies(CPlugin *pOther);
   465 private:
   466 	List<IPluginsListener *> m_listeners;
   467 	List<CPlugin *> m_plugins;
   468 	CStack<CPluginManager::CPluginIterator *> m_iters;
   469 	NameHashSet<CPlugin *> m_LoadLookup;
   470 	bool m_AllPluginsLoaded;
   471 	IdentityToken_t *m_MyIdent;
   472 
   473 	/* Dynamic native stuff */
   474 	List<FakeNative *> m_Natives;
   475 
   476 	bool m_LoadingLocked;
   477 	
   478 	// Config
   479 	bool m_bBlockBadPlugins;
   480 	
   481 	// Forwards
   482 	IForward *m_pOnLibraryAdded;
   483 	IForward *m_pOnLibraryRemoved;
   484 };
   485 
   486 extern CPluginManager g_PluginSys;
   487 
   488 #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
   489