public/IExtensionSys.h
author David Anderson <dvander@alliedmods.net>
Thu Aug 22 14:05:44 2013 -0700 (2013-08-22)
changeset 4029 cf8bdfcf6503
parent 3872 4c93f74cae51
permissions -rw-r--r--
Fix various problems with unloading ClientPrefs and SourceMod (bug 5874, r=ds).
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet:
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 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_MODULE_INTERFACE_H_
    33 #define _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_
    34 
    35 #include <IShareSys.h>
    36 #include <ILibrarySys.h>
    37 
    38 /**
    39  * @file IExtensionSys.h
    40  * @brief Defines the interface for loading/unloading/managing extensions.
    41  */
    42 
    43 struct edict_t;
    44 
    45 namespace SourceMod
    46 {
    47 	class IExtensionInterface;
    48 	typedef void *		ITERATOR;		/**< Generic pointer for dependency iterators */
    49 
    50 	/** 
    51 	 * @brief Encapsulates an IExtensionInterface and its dependencies.
    52 	 */
    53 	class IExtension
    54 	{
    55 	public:
    56 		/**
    57 		 * @brief Returns whether or not the extension is properly loaded.
    58 		 */
    59 		virtual bool IsLoaded() =0;
    60 
    61 		/**
    62 		 * @brief Returns the extension's API interface
    63 		 *
    64 		 * @return			An IExtensionInterface pointer.
    65 		 */
    66 		virtual IExtensionInterface *GetAPI() =0;
    67 
    68 		/**
    69 		 * @brief Returns the filename of the extension, relative to the
    70 		 * extension folder.   If the extension is an "external" extension, 
    71 		 * the file path is specified by the extension itself, and may be 
    72 		 * arbitrary (not real).
    73 		 *
    74 		 * @return			A string containing the extension file name.
    75 		 */
    76 		virtual const char *GetFilename() =0;
    77 
    78 		/**
    79 		 * @brief Returns the extension's identity token.
    80 		 *
    81 		 * @return			An IdentityToken_t pointer.
    82 		 */
    83 		virtual IdentityToken_t *GetIdentity() =0;
    84 
    85 		/**
    86 		 * @brief Retrieves the extension dependency list for this extension.
    87 		 *
    88 		 * @param pOwner		Optional pointer to store the first interface's owner.
    89 		 * @param pInterface	Optional pointer to store the first interface.
    90 		 * @return				An ITERATOR pointer for the results, or NULL if no results at all.
    91 		 */
    92 		virtual ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface) =0;
    93 
    94 		/**
    95 		 * @brief Finds the next dependency in the dependency list.
    96 		 *
    97 		 * @param iter			Pointer to iterator from FindFirstDependency.
    98 		 * @param pOwner		Optional pointer to store the interface's owner.
    99 		 * @param pInterface	Optional pointer to store the interface.
   100 		 * @return				True if there are more results after this, false otherwise.
   101 		 */
   102 		virtual bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface) =0;
   103 
   104 		/**
   105 		 * @brief Frees an ITERATOR handle from FindFirstDependency.
   106 		 *
   107 		 * @param iter			Pointer to iterator to free.
   108 		 */
   109 		virtual void FreeDependencyIterator(ITERATOR *iter) =0;
   110 
   111 		/**
   112 		 * @brief Queries the extension to see its run state.
   113 		 *
   114 		 * @param error			Error buffer (may be NULL).
   115 		 * @param maxlength		Maximum length of buffer.
   116 		 * @return				True if extension is okay, false if not okay.
   117 		 */
   118 		virtual bool IsRunning(char *error, size_t maxlength) =0;
   119 
   120 		/**
   121 		 * @brief Returns whether the extension is local (from the extensions 
   122 		 * folder), or is from an external source (such as Metamod:Source).
   123 		 *
   124 		 * @return				True if from an external source, 
   125 		 *						false if local to SourceMod.
   126 		 */
   127 		virtual bool IsExternal() =0;
   128 	};
   129 
   130 	/**
   131 	 * @brief Version code of the IExtensionInterface API itself.
   132 	 *
   133 	 * Note: This is bumped when IShareSys is changed, because IShareSys 
   134 	 * itself is not versioned.
   135 	 *
   136 	 * V6 - added TestFeature() to IShareSys.
   137 	 * V7 - added OnDependenciesDropped() to IExtensionInterface.
   138 	 */
   139 	#define SMINTERFACE_EXTENSIONAPI_VERSION	7
   140 
   141 	/**
   142 	 * @brief The interface an extension must expose.
   143 	 */
   144 	class IExtensionInterface
   145 	{
   146 	public:
   147 		/** Returns the interface API version */
   148 		virtual unsigned int GetExtensionVersion()
   149 		{
   150 			return SMINTERFACE_EXTENSIONAPI_VERSION;
   151 		}
   152 	public:
   153 		/**
   154 		 * @brief Called when the extension is loaded.
   155 		 * 
   156 		 * @param me		Pointer back to extension.
   157 		 * @param sys		Pointer to interface sharing system of SourceMod.
   158 		 * @param error		Error buffer to print back to, if any.
   159 		 * @param maxlength	Maximum size of error buffer.
   160 		 * @param late		If this extension was loaded "late" (i.e. manually).
   161 		 * @return			True if load should continue, false otherwise.
   162 		 */
   163 		virtual bool OnExtensionLoad(IExtension *me,
   164 			IShareSys *sys, 
   165 			char *error, 
   166 			size_t maxlength, 
   167 			bool late) =0;
   168 
   169 		/**
   170 		 * @brief Called when the extension is about to be unloaded.
   171 		 */
   172 		virtual void OnExtensionUnload() =0;
   173 
   174 		/**
   175 		 * @brief Called when all extensions are loaded (loading cycle is done).
   176 		 * If loaded late, this will be called right after OnExtensionLoad().
   177 		 */
   178 		virtual void OnExtensionsAllLoaded() =0;
   179 
   180 		/**
   181 		 * @brief Called when your pause state is about to change.
   182 		 * 
   183 		 * @param pause		True if pausing, false if unpausing.
   184 		 */
   185 		virtual void OnExtensionPauseChange(bool pause) =0;
   186 
   187 		/**
   188 		 * @brief Asks the extension whether it's safe to remove an external 
   189 		 * interface it's using.  If it's not safe, return false, and the 
   190 		 * extension will be unloaded afterwards.
   191 		 *
   192 		 * NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean 
   193 		 * up resources.
   194 		 *
   195 		 * @param pInterface		Pointer to interface being dropped.  This 
   196 		 * 							pointer may be opaque, and it should not 
   197 		 *							be queried using SMInterface functions unless 
   198 		 *							it can be verified to match an existing 
   199 		 *							pointer of known type.
   200 		 * @return					True to continue, false to unload this 
   201 		 * 							extension afterwards.
   202 		 */
   203 		virtual bool QueryInterfaceDrop(SMInterface *pInterface)
   204 		{
   205 			return false;
   206 		}
   207 
   208 		/**
   209 		 * @brief Notifies the extension that an external interface it uses is being removed.
   210 		 *
   211 		 * @param pInterface		Pointer to interface being dropped.  This
   212 		 * 							pointer may be opaque, and it should not 
   213 		 *							be queried using SMInterface functions unless 
   214 		 *							it can be verified to match an existing 
   215 		 */
   216 		virtual void NotifyInterfaceDrop(SMInterface *pInterface)
   217 		{
   218 		}
   219 
   220 		/**
   221 		 * @brief Return false to tell Core that your extension should be considered unusable.
   222 		 *
   223 		 * @param error				Error buffer.
   224 		 * @param maxlength			Size of error buffer.
   225 		 * @return					True on success, false otherwise.
   226 		 */
   227 		virtual bool QueryRunning(char *error, size_t maxlength)
   228 		{
   229 			return true;
   230 		}
   231 	public:
   232 		/**
   233 		 * @brief For extensions loaded through SourceMod, this should return true 
   234 		 * if the extension needs to attach to Metamod:Source.  If the extension 
   235 		 * is loaded through Metamod:Source, and uses SourceMod optionally, it must 
   236 		 * return false.
   237 		 *
   238 		 * @return					True if Metamod:Source is needed.
   239 		 */
   240 		virtual bool IsMetamodExtension() =0;
   241 
   242 		/**
   243 		 * @brief Must return a string containing the extension's short name.
   244 		 *
   245 		 * @return					String containing extension name.
   246 		 */
   247 		virtual const char *GetExtensionName() =0;
   248 
   249 		/**
   250 		 * @brief Must return a string containing the extension's URL.
   251 		 *
   252 		 * @return					String containing extension URL.
   253 		 */
   254 		virtual const char *GetExtensionURL() =0;
   255 
   256 		/**
   257 		 * @brief Must return a string containing a short identifier tag.
   258 		 *
   259 		 * @return					String containing extension tag.
   260 		 */
   261 		virtual const char *GetExtensionTag() =0;
   262 
   263 		/**
   264 		 * @brief Must return a string containing a short author identifier.
   265 		 *
   266 		 * @return					String containing extension author.
   267 		 */
   268 		virtual const char *GetExtensionAuthor() =0;
   269 
   270 		/**
   271 		 * @brief Must return a string containing version information.
   272 		 *
   273 		 * Any version string format can be used, however, SourceMod 
   274 		 * makes a special guarantee version numbers in the form of 
   275 		 * A.B.C.D will always be fully displayed, where:
   276 		 * 
   277 		 * A is a major version number of at most one digit.
   278 		 * B is a minor version number of at most two digits.
   279 		 * C is a minor version number of at most two digits.
   280 		 * D is a build number of at most 5 digits.
   281 		 *
   282 		 * Thus, thirteen characters of display is guaranteed.
   283 		 *
   284 		 * @return					String containing extension version.
   285 		 */
   286 		virtual const char *GetExtensionVerString() =0;
   287 
   288 		/**
   289 		 * @brief Must return a string containing description text.
   290 		 *
   291 		 * The description text may be longer than the other identifiers, 
   292 		 * as it is only displayed when viewing one extension at a time.
   293 		 * However, it should not have newlines, or any other characters 
   294 		 * which would otherwise disrupt the display pattern.
   295 		 * 
   296 		 * @return					String containing extension description.
   297 		 */
   298 		virtual const char *GetExtensionDescription() =0;
   299 
   300 		/**
   301 		 * @brief Must return a string containing the compilation date.
   302 		 *
   303 		 * @return					String containing the compilation date.
   304 		 */
   305 		virtual const char *GetExtensionDateString() =0;
   306 
   307 		/**
   308 		 * @brief Called on server activation before plugins receive the OnServerLoad forward.
   309 		 * 
   310 		 * @param pEdictList		Edicts list.
   311 		 * @param edictCount		Number of edicts in the list.
   312 		 * @param clientMax			Maximum number of clients allowed in the server.
   313 		 */
   314 		virtual void OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
   315 		{
   316 		}
   317 
   318 		/**
   319 		 * @brief Called once all dependencies have been unloaded. This is
   320 		 * called AFTER OnExtensionUnload(), but before the extension library
   321 		 * has been unloaded. It can be used as an alternate unload hook for
   322 		 * cases where having no dependent plugins would make shutdown much
   323 		 * simplier.
   324 		 */
   325 		virtual void OnDependenciesDropped()
   326 		{
   327 		}
   328 	};
   329 
   330 	/**
   331 	 * @brief Returned via OnMetamodQuery() to get an IExtensionManager pointer.
   332 	 */
   333 	#define SOURCEMOD_INTERFACE_EXTENSIONS				"SM_ExtensionManager"
   334 
   335 	/**
   336 	 * @brief Fired through OnMetamodQuery() to notify plugins that SourceMod is 
   337 	 * loaded.  
   338 	 *
   339 	 * Plugins should not return an interface pointer or IFACE_OK, instead, 
   340 	 * they should attach as needed by searching for SOURCEMOD_INTERFACE_EXTENSIONS.
   341 	 *
   342 	 * This may be fired more than once; if already attached, an extension should 
   343 	 * not attempt to re-attach.  The purpose of this is to notify Metamod:Source 
   344 	 * plugins which load after SourceMod loads.
   345 	 */
   346 	#define SOURCEMOD_NOTICE_EXTENSIONS					"SM_ExtensionsAttachable"
   347 
   348 	#define SMINTERFACE_EXTENSIONMANAGER_NAME			"IExtensionManager"
   349 	#define SMINTERFACE_EXTENSIONMANAGER_VERSION		2
   350 
   351 	/**
   352 	 * @brief Manages the loading/unloading of extensions.
   353 	 */
   354 	class IExtensionManager : public SMInterface
   355 	{
   356 	public:
   357 		virtual const char *GetInterfaceName()
   358 		{
   359 			return SMINTERFACE_EXTENSIONMANAGER_NAME;
   360 		}
   361 		virtual unsigned int GetInterfaceVersion()
   362 		{
   363 			return SMINTERFACE_EXTENSIONMANAGER_VERSION;
   364 		}
   365 		virtual bool IsVersionCompatible(unsigned int version)
   366 		{
   367 			if (version < 2)
   368 			{
   369 				return false;
   370 			}
   371 			return SMInterface::IsVersionCompatible(version);
   372 		}
   373 	public:
   374 		/**
   375 		 * @brief Loads a extension into the extension system.
   376 		 *
   377 		 * @param path			Path to extension file, relative to the 
   378 		 *						extensions folder.
   379 		 * @param error			Error buffer.
   380 		 * @param maxlength		Maximum error buffer length.
   381 		 * @return				New IExtension on success, NULL on failure.
   382 		 *						If	NULL is returned, the error buffer will be 
   383 		 *						filled with a null-terminated string.
   384 		 */
   385 		virtual IExtension *LoadExtension(const char *path, 
   386 			char *error,
   387 			size_t maxlength) =0;
   388 
   389 		/**
   390 		 * @brief Loads an extension into the extension system, directly, 
   391 		 * as an external extension.  
   392 		 *
   393 		 * The extension receives all normal callbacks.  However, it is 
   394 		 * never opened via LoadLibrary/dlopen or closed via FreeLibrary
   395 		 * or dlclose.
   396 		 *
   397 		 * @param pInterface	Pointer to an IExtensionInterface instance.
   398 		 * @param filepath		Relative path to the extension's file, from 
   399 		 * 						mod folder.
   400 		 * @param filename		Name to use to uniquely identify the extension. 
   401 		 *						The name should be generic, without any 
   402 		 *						platform-specific suffices.  For example, 
   403 		 *						sdktools.ext instead of sdktools.ext.so.
   404 		 *						This filename is used to detect if the 
   405 		 *						extension is already loaded, and to verify 
   406 		 *						plugins that require the same extension.
   407 		 * @param error			Buffer to store error message.
   408 		 * @param maxlength		Maximum size of the error buffer.
   409 		 * @return				IExtension pointer on success, NULL on failure.
   410 		 *						If NULL is returned, the error buffer will be 
   411 		 *						filled with a null-terminated string.
   412 		 */
   413 		virtual IExtension *LoadExternal(IExtensionInterface *pInterface,
   414 			const char *filepath,
   415 			const char *filename,
   416 			char *error,
   417 			size_t maxlength) =0;
   418 
   419 		/**
   420 		 * @brief Attempts to unload an extension.  External extensions must 
   421 		 * call this before unloading.
   422 		 *
   423 		 * @param pExt			IExtension pointer.
   424 		 * @return				True if successful, false otherwise.
   425 		 */
   426 		virtual bool UnloadExtension(IExtension *pExt) =0;
   427 	};
   428 
   429 	#define SM_IFACEPAIR(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION
   430 
   431 	#define SM_FIND_IFACE_OR_FAIL(prefix, variable, errbuf, errsize) \
   432 		if (!sharesys->RequestInterface(SM_IFACEPAIR(prefix), myself, (SMInterface **)&variable)) \
   433 		{ \
   434 			if (errbuf) \
   435 			{ \
   436 				size_t len = snprintf(errbuf, \
   437 					errsize, \
   438 					"Could not find interface: %s (version: %d)", \
   439 					SM_IFACEPAIR(prefix)); \
   440 				if (len >= errsize) \
   441 				{ \
   442 					errbuf[errsize - 1] = '\0'; \
   443 				} \
   444 			} \
   445 			return false; \
   446 		}
   447 
   448 	#define SM_FIND_IFACE(prefix, variable) \
   449 		sharesys->RequestInterface(SM_IFACEPAIR(prefix), myself, (SMInterface **)&variable);
   450 }
   451 
   452 #endif //_INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_
   453