dvander@372: /** dvander@375: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1226: * SourceMod ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= dvander@372: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@379: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1226: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1226: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . dvander@372: * dvander@372: * Version: $Id$ dvander@372: */ dvander@372: dvander@324: #ifndef _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ dvander@324: #define _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ dvander@324: dvander@324: #include dvander@324: #include dvander@324: dvander@372: /** dvander@372: * @file IExtensionSys.h dvander@372: * @brief Defines the interface for loading/unloading/managing extensions. dvander@372: */ dvander@372: faluco@1993: struct edict_t; faluco@1993: dvander@324: namespace SourceMod dvander@324: { dvander@324: class IExtensionInterface; dvander@372: typedef void * ITERATOR; /**< Generic pointer for dependency iterators */ dvander@324: dvander@324: /** dvander@372: * @brief Encapsulates an IExtensionInterface and its dependencies. dvander@324: */ dvander@324: class IExtension dvander@324: { dvander@324: public: dvander@324: /** dvander@324: * @brief Returns whether or not the extension is properly loaded. dvander@324: */ dvander@324: virtual bool IsLoaded() =0; dvander@324: dvander@324: /** dvander@324: * @brief Returns the extension's API interface dvander@324: * dvander@324: * @return An IExtensionInterface pointer. dvander@324: */ dvander@324: virtual IExtensionInterface *GetAPI() =0; dvander@324: dvander@324: /** dvander@324: * @brief Returns the filename of the extension, relative to the dvander@1648: * extension folder. If the extension is an "external" extension, dvander@1648: * the file path is specified by the extension itself, and may be dvander@1648: * arbitrary (not real). dvander@324: * dvander@324: * @return A string containing the extension file name. dvander@324: */ dvander@324: virtual const char *GetFilename() =0; dvander@324: dvander@324: /** dvander@324: * @brief Returns the extension's identity token. dvander@324: * dvander@324: * @return An IdentityToken_t pointer. dvander@324: */ dvander@324: virtual IdentityToken_t *GetIdentity() =0; dvander@324: dvander@324: /** dvander@324: * @brief Retrieves the extension dependency list for this extension. dvander@324: * dvander@324: * @param pOwner Optional pointer to store the first interface's owner. dvander@324: * @param pInterface Optional pointer to store the first interface. dvander@324: * @return An ITERATOR pointer for the results, or NULL if no results at all. dvander@324: */ dvander@324: virtual ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface) =0; dvander@324: dvander@324: /** dvander@324: * @brief Finds the next dependency in the dependency list. dvander@324: * dvander@324: * @param iter Pointer to iterator from FindFirstDependency. dvander@324: * @param pOwner Optional pointer to store the interface's owner. dvander@324: * @param pInterface Optional pointer to store the interface. dvander@324: * @return True if there are more results after this, false otherwise. dvander@324: */ dvander@324: virtual bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface) =0; dvander@324: dvander@324: /** dvander@324: * @brief Frees an ITERATOR handle from FindFirstDependency. dvander@324: * dvander@324: * @param iter Pointer to iterator to free. dvander@324: */ dvander@324: virtual void FreeDependencyIterator(ITERATOR *iter) =0; dvander@324: dvander@324: /** dvander@324: * @brief Queries the extension to see its run state. dvander@324: * dvander@324: * @param error Error buffer (may be NULL). dvander@324: * @param maxlength Maximum length of buffer. dvander@324: * @return True if extension is okay, false if not okay. dvander@324: */ dvander@324: virtual bool IsRunning(char *error, size_t maxlength) =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Returns whether the extension is local (from the extensions dvander@1648: * folder), or is from an external source (such as Metamod:Source). dvander@1648: * dvander@1648: * @return True if from an external source, dvander@1648: * false if local to SourceMod. dvander@1648: */ dvander@1648: virtual bool IsExternal() =0; dvander@324: }; dvander@324: dvander@372: /** dvander@372: * @brief Version code of the IExtensionInterface API itself. dvander@1689: * dvander@1689: * Note: This is bumped when IShareSys is changed, because IShareSys dvander@1689: * itself is not versioned. dvander@372: */ faluco@1993: #define SMINTERFACE_EXTENSIONAPI_VERSION 4 dvander@324: dvander@324: /** dvander@324: * @brief The interface an extension must expose. dvander@324: */ dvander@324: class IExtensionInterface dvander@324: { dvander@324: public: dvander@372: /** Returns the interface API version */ dvander@324: virtual unsigned int GetExtensionVersion() dvander@324: { dvander@324: return SMINTERFACE_EXTENSIONAPI_VERSION; dvander@324: } dvander@324: public: dvander@324: /** dvander@324: * @brief Called when the extension is loaded. dvander@324: * dvander@324: * @param me Pointer back to extension. dvander@324: * @param sys Pointer to interface sharing system of SourceMod. dvander@324: * @param error Error buffer to print back to, if any. ds@755: * @param maxlength Maximum size of error buffer. dvander@324: * @param late If this extension was loaded "late" (i.e. manually). dvander@324: * @return True if load should continue, false otherwise. dvander@324: */ dvander@324: virtual bool OnExtensionLoad(IExtension *me, dvander@1648: IShareSys *sys, dvander@1648: char *error, dvander@1648: size_t maxlength, dvander@1648: bool late) =0; dvander@324: dvander@324: /** dvander@324: * @brief Called when the extension is about to be unloaded. dvander@324: */ dvander@324: virtual void OnExtensionUnload() =0; dvander@324: dvander@324: /** dvander@324: * @brief Called when all extensions are loaded (loading cycle is done). dvander@324: * If loaded late, this will be called right after OnExtensionLoad(). dvander@324: */ dvander@324: virtual void OnExtensionsAllLoaded() =0; dvander@324: dvander@324: /** dvander@324: * @brief Called when your pause state is about to change. dvander@324: * dvander@324: * @param pause True if pausing, false if unpausing. dvander@324: */ dvander@324: virtual void OnExtensionPauseChange(bool pause) =0; dvander@324: dvander@324: /** dvander@1648: * @brief Asks the extension whether it's safe to remove an external dvander@1648: * interface it's using. If it's not safe, return false, and the dvander@1648: * extension will be unloaded afterwards. dvander@1648: * dvander@2134: * NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean dvander@2134: * up resources. dvander@324: * dvander@2134: * @param pInterface Pointer to interface being dropped. This dvander@2134: * pointer may be opaque, and it should not dvander@2134: * be queried using SMInterface functions unless dvander@2134: * it can be verified to match an existing dvander@2134: * pointer of known type. dvander@2134: * @return True to continue, false to unload this dvander@2134: * extension afterwards. dvander@324: */ dvander@324: virtual bool QueryInterfaceDrop(SMInterface *pInterface) dvander@324: { dvander@329: return false; dvander@324: } dvander@324: dvander@324: /** dvander@324: * @brief Notifies the extension that an external interface it uses is being removed. dvander@324: * dvander@2134: * @param pInterface Pointer to interface being dropped. This dvander@2134: * pointer may be opaque, and it should not dvander@2134: * be queried using SMInterface functions unless dvander@2134: * it can be verified to match an existing dvander@324: */ dvander@324: virtual void NotifyInterfaceDrop(SMInterface *pInterface) dvander@324: { dvander@324: } dvander@324: dvander@324: /** ds@755: * @brief Return false to tell Core that your extension should be considered unusable. dvander@324: * dvander@324: * @param error Error buffer. dvander@324: * @param maxlength Size of error buffer. dvander@324: * @return True on success, false otherwise. dvander@324: */ dvander@324: virtual bool QueryRunning(char *error, size_t maxlength) dvander@324: { dvander@324: return true; dvander@324: } dvander@324: public: dvander@1648: /** dvander@1648: * @brief For extensions loaded through SourceMod, this should return true dvander@1648: * if the extension needs to attach to Metamod:Source. If the extension dvander@1648: * is loaded through Metamod:Source, and uses SourceMod optionally, it must dvander@1648: * return false. dvander@1648: * dvander@1648: * @return True if Metamod:Source is needed. dvander@1648: */ dvander@324: virtual bool IsMetamodExtension() =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Must return a string containing the extension's short name. dvander@1648: * dvander@1648: * @return String containing extension name. dvander@1648: */ dvander@324: virtual const char *GetExtensionName() =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Must return a string containing the extension's URL. dvander@1648: * dvander@1648: * @return String containing extension URL. dvander@1648: */ dvander@324: virtual const char *GetExtensionURL() =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Must return a string containing a short identifier tag. dvander@1648: * dvander@1648: * @return String containing extension tag. dvander@1648: */ dvander@324: virtual const char *GetExtensionTag() =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Must return a string containing a short author identifier. dvander@1648: * dvander@1648: * @return String containing extension author. dvander@1648: */ dvander@324: virtual const char *GetExtensionAuthor() =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Must return a string containing version information. dvander@1648: * dvander@1648: * Any version string format can be used, however, SourceMod dvander@1648: * makes a special guarantee version numbers in the form of dvander@1648: * A.B.C.D will always be fully displayed, where: dvander@1648: * dvander@1648: * A is a major version number of at most one digit. dvander@1648: * B is a minor version number of at most two digits. dvander@1648: * C is a minor version number of at most two digits. dvander@1648: * D is a build number of at most 5 digits. dvander@1648: * dvander@1648: * Thus, thirteen characters of display is guaranteed. dvander@1648: * dvander@1648: * @return String containing extension version. dvander@1648: */ dvander@324: virtual const char *GetExtensionVerString() =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Must return a string containing description text. dvander@1648: * dvander@1648: * The description text may be longer than the other identifiers, dvander@1648: * as it is only displayed when viewing one extension at a time. dvander@1648: * However, it should not have newlines, or any other characters dvander@1648: * which would otherwise disrupt the display pattern. dvander@1648: * dvander@1648: * @return String containing extension description. dvander@1648: */ dvander@324: virtual const char *GetExtensionDescription() =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Must return a string containing the compilation date. dvander@1648: * dvander@1648: * @return String containing the compilation date. dvander@1648: */ dvander@324: virtual const char *GetExtensionDateString() =0; faluco@1993: faluco@1993: /** faluco@1993: * @brief Called on server activation before plugins receive the OnServerLoad forward. faluco@1993: * faluco@1993: * @param pEdictList Edicts list. faluco@1993: * @param edictCount Number of edicts in the list. faluco@1993: * @param clientMax Maximum number of clients allowed in the server. faluco@1993: */ faluco@1993: virtual void OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) faluco@1993: { faluco@1993: } dvander@324: }; dvander@324: dvander@1655: /** dvander@1655: * @brief Returned via OnMetamodQuery() to get an IExtensionManager pointer. dvander@1655: */ dvander@1655: #define SOURCEMOD_INTERFACE_EXTENSIONS "SM_ExtensionManager" dvander@1655: dvander@1655: /** dvander@1655: * @brief Fired through OnMetamodQuery() to notify plugins that SourceMod is dvander@1655: * loaded. dvander@1655: * dvander@1655: * Plugins should not return an interface pointer or IFACE_OK, instead, dvander@1655: * they should attach as needed by searching for SOURCEMOD_INTERFACE_EXTENSIONS. dvander@1655: * dvander@1655: * This may be fired more than once; if already attached, an extension should dvander@1655: * not attempt to re-attach. The purpose of this is to notify Metamod:Source dvander@1655: * plugins which load after SourceMod loads. dvander@1655: */ dvander@1655: #define SOURCEMOD_NOTICE_EXTENSIONS "SM_ExtensionsAttachable" dvander@1655: dvander@324: #define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager" dvander@1648: #define SMINTERFACE_EXTENSIONMANAGER_VERSION 2 dvander@324: dvander@372: /** dvander@372: * @brief Manages the loading/unloading of extensions. dvander@372: */ dvander@324: class IExtensionManager : public SMInterface dvander@324: { dvander@324: public: dvander@324: virtual const char *GetInterfaceName() dvander@324: { dvander@324: return SMINTERFACE_EXTENSIONMANAGER_NAME; dvander@324: } dvander@324: virtual unsigned int GetInterfaceVersion() dvander@324: { dvander@324: return SMINTERFACE_EXTENSIONMANAGER_VERSION; dvander@324: } dvander@1648: virtual bool IsVersionCompatible(unsigned int version) dvander@1648: { dvander@1648: if (version < 2) dvander@1648: { dvander@1648: return false; dvander@1648: } dvander@1648: return SMInterface::IsVersionCompatible(version); dvander@1648: } dvander@324: public: dvander@324: /** dvander@324: * @brief Loads a extension into the extension system. dvander@324: * dvander@1648: * @param path Path to extension file, relative to the dvander@1648: * extensions folder. dvander@1648: * @param error Error buffer. dvander@1648: * @param maxlength Maximum error buffer length. dvander@1648: * @return New IExtension on success, NULL on failure. dvander@1648: * If NULL is returned, the error buffer will be dvander@1648: * filled with a null-terminated string. dvander@324: */ dvander@324: virtual IExtension *LoadExtension(const char *path, dvander@1648: char *error, dvander@1648: size_t maxlength) =0; dvander@324: dvander@324: /** dvander@1648: * @brief Loads an extension into the extension system, directly, dvander@1648: * as an external extension. dvander@1648: * dvander@1648: * The extension receives all normal callbacks. However, it is dvander@1648: * never opened via LoadLibrary/dlopen or closed via FreeLibrary dvander@1648: * or dlclose. dvander@324: * dvander@1648: * @param pInterface Pointer to an IExtensionInterface instance. dvander@1669: * @param filepath Relative path to the extension's file, from dvander@1669: * mod folder. dvander@1648: * @param filename Name to use to uniquely identify the extension. dvander@1648: * The name should be generic, without any dvander@1648: * platform-specific suffices. For example, dvander@1648: * sdktools.ext instead of sdktools.ext.so. dvander@1648: * This filename is used to detect if the dvander@1648: * extension is already loaded, and to verify dvander@1648: * plugins that require the same extension. dvander@1648: * @param error Buffer to store error message. dvander@1648: * @param maxlength Maximum size of the error buffer. dvander@1648: * @return IExtension pointer on success, NULL on failure. dvander@1648: * If NULL is returned, the error buffer will be dvander@1648: * filled with a null-terminated string. dvander@1648: */ dvander@1648: virtual IExtension *LoadExternal(IExtensionInterface *pInterface, dvander@1648: const char *filepath, dvander@1648: const char *filename, dvander@1648: char *error, dvander@1648: size_t maxlength) =0; dvander@1648: dvander@1648: /** dvander@1648: * @brief Attempts to unload an extension. External extensions must dvander@1648: * call this before unloading. dvander@1648: * dvander@1648: * @param pExt IExtension pointer. dvander@1648: * @return True if successful, false otherwise. dvander@324: */ dvander@324: virtual bool UnloadExtension(IExtension *pExt) =0; dvander@324: }; dvander@1649: dvander@1649: #define SM_IFACEPAIR(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION dvander@1649: dvander@1649: #define SM_FIND_IFACE_OR_FAIL(prefix, variable, errbuf, errsize) \ dvander@1649: if (!sharesys->RequestInterface(SM_IFACEPAIR(prefix), myself, (SMInterface **)&variable)) \ dvander@1649: { \ dvander@1649: if (errbuf) \ dvander@1649: { \ dvander@1649: size_t len = snprintf(errbuf, \ dvander@1649: errsize, \ dvander@1649: "Could not find interface: %s (version: %d)", \ dvander@1649: SM_IFACEPAIR(prefix)); \ dvander@1649: if (len >= errsize) \ dvander@1649: { \ dvander@1668: errbuf[errsize - 1] = '\0'; \ dvander@1649: } \ dvander@1649: } \ dvander@1649: return false; \ dvander@1649: } dvander@1649: dvander@1649: #define SM_FIND_IFACE(prefix, variable) \ dvander@1655: sharesys->RequestInterface(SM_IFACEPAIR(prefix), myself, (SMInterface **)&variable); ds@432: } dvander@324: dvander@324: #endif //_INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_ dvander@1657: