00001 /** 00002 * vim: set ts=4 : 00003 * ============================================================================= 00004 * SourceMod 00005 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. 00006 * ============================================================================= 00007 * 00008 * This program is free software; you can redistribute it and/or modify it under 00009 * the terms of the GNU General Public License, version 3.0, as published by the 00010 * Free Software Foundation. 00011 * 00012 * This program is distributed in the hope that it will be useful, but WITHOUT 00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00014 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 00015 * details. 00016 * 00017 * You should have received a copy of the GNU General Public License along with 00018 * this program. If not, see <http://www.gnu.org/licenses/>. 00019 * 00020 * As a special exception, AlliedModders LLC gives you permission to link the 00021 * code of this program (as well as its derivative works) to "Half-Life 2," the 00022 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software 00023 * by the Valve Corporation. You must obey the GNU General Public License in 00024 * all respects for all other code used. Additionally, AlliedModders LLC grants 00025 * this exception to all derivative works. AlliedModders LLC defines further 00026 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), 00027 * or <http://www.sourcemod.net/license.php>. 00028 * 00029 * Version: $Id: IForwardSys.h 2388 2008-07-08 21:17:05Z damagedsoul $ 00030 */ 00031 00032 #ifndef _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ 00033 #define _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ 00034 00035 /** 00036 * @file IForwardSys.h 00037 * @brief Defines the interface for managing collections ("forwards") of plugin calls. 00038 * 00039 * The Forward System is responsible for managing automated collections of IPluginFunctions. 00040 * It thus provides wrappers to calling many functions at once. There are two types of such 00041 * wrappers: Managed and Unmanaged. Confusingly, these terms refer to whether the user manages 00042 * the forwards, not Core. Managed forwards are completely managed by the user, and are custom 00043 * editable collections. Unmanaged forwards are the opposite, and will only work on a single global 00044 * function name in all plugins. 00045 */ 00046 00047 #include <IPluginSys.h> 00048 #include <sp_vm_api.h> 00049 00050 using namespace SourcePawn; 00051 00052 #define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" 00053 #define SMINTERFACE_FORWARDMANAGER_VERSION 3 00054 00055 /* 00056 * There is some very important documentation at the bottom of this file. 00057 * Readers interested in knowing more about the forward system, scrolling down is a must! 00058 */ 00059 00060 namespace SourceMod 00061 { 00062 /** 00063 * @brief Defines the event hook result types plugins can return. 00064 */ 00065 enum ResultType 00066 { 00067 Pl_Continue = 0, /**< No result */ 00068 Pl_Changed = 1, /**< Inputs or outputs have been overridden with new values */ 00069 Pl_Handled = 3, /**< Result was handled, stop at the end */ 00070 Pl_Stop = 4, /**< Result was handled, stop now */ 00071 }; 00072 00073 /** 00074 * @brief Defines how a forward iterates through plugin functions. 00075 */ 00076 enum ExecType 00077 { 00078 ET_Ignore = 0, /**< Ignore all return values, return 0 */ 00079 ET_Single = 1, /**< Only return the last exec, ignore all others */ 00080 ET_Event = 2, /**< Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */ 00081 ET_Hook = 3, /**< Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */ 00082 ET_LowEvent = 4, /**< Same as ET_Event except that it returns the lowest value */ 00083 }; 00084 00085 class IForward; 00086 class IForwardFilter; 00087 00088 /** 00089 * @brief Unmanaged Forward, abstracts calling multiple functions as "forwards," or collections of functions. 00090 * 00091 * Parameters should be pushed in forward order, unlike the virtual machine/IPluginContext order. 00092 * Some functions are repeated in here because their documentation differs from their IPluginFunction equivalents. 00093 * Missing are the Push functions, whose only doc change is that they throw SP_ERROR_PARAM on type mismatches. 00094 */ 00095 class IForward : public ICallable 00096 { 00097 public: 00098 /** Virtual Destructor */ 00099 virtual ~IForward() 00100 { 00101 } 00102 public: 00103 /** 00104 * @brief Returns the name of the forward. 00105 * 00106 * @return Forward name. 00107 */ 00108 virtual const char *GetForwardName() =0; 00109 00110 /** 00111 * @brief Returns the number of functions in this forward. 00112 * 00113 * @return Number of functions in forward. 00114 */ 00115 virtual unsigned int GetFunctionCount() =0; 00116 00117 /** 00118 * @brief Returns the method of multi-calling this forward has. 00119 * 00120 * @return ExecType of the forward. 00121 */ 00122 virtual ExecType GetExecType() =0; 00123 00124 /** 00125 * @brief Executes the forward. 00126 * 00127 * @param result Optional pointer to store result in. 00128 * @param filter Do not use. 00129 * @return Error code, if any. 00130 */ 00131 virtual int Execute(cell_t *result, IForwardFilter *filter=NULL) =0; 00132 00133 /** 00134 * @brief Pushes an array of cells onto the current call. Different rules than ICallable. 00135 * NOTE: On Execute, the pointer passed will be modified according to the copyback rule. 00136 * 00137 * @param inarray Array to copy. Cannot be NULL, unlike ICallable's version. 00138 * @param cells Number of cells to allocate and optionally read from the input array. 00139 * @param flags Whether or not changes should be copied back to the input array. 00140 * @return Error code, if any. 00141 */ 00142 virtual int PushArray(cell_t *inarray, unsigned int cells, int flags=0) =0; 00143 }; 00144 00145 /** 00146 * @brief Managed Forward, same as IForward, except the collection can be modified. 00147 */ 00148 class IChangeableForward : public IForward 00149 { 00150 public: 00151 /** 00152 * @brief Removes a function from the call list. 00153 * NOTE: Only removes one instance. 00154 * 00155 * @param func Function to remove. 00156 * @return Whether or not the function was removed. 00157 */ 00158 virtual bool RemoveFunction(IPluginFunction *func) =0; 00159 00160 /** 00161 * @brief Removes all instances of a plugin from the call list. 00162 * 00163 * @param plugin Plugin to remove instances of. 00164 * @return Number of functions removed therein. 00165 */ 00166 virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin) =0; 00167 00168 /** 00169 * @brief Adds a function to the call list. 00170 * NOTE: Cannot be used during an incomplete call. 00171 * NOTE: If used during a call, function is temporarily queued until calls are over. 00172 * NOTE: Adding multiple copies of the same function is illegal. 00173 * 00174 * @param func Function to add. 00175 * @return True on success, otherwise false. 00176 */ 00177 virtual bool AddFunction(IPluginFunction *func) =0; 00178 00179 /** 00180 * @brief Adds a function to the call list. 00181 * NOTE: Cannot be used during an incomplete call. 00182 * NOTE: If used during a call, function is temporarily queued until calls are over. 00183 * 00184 * @param ctx Context to use as a look-up. 00185 * @param index Function id to add. 00186 * @return True on success, otherwise false. 00187 */ 00188 virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0; 00189 00190 /** 00191 * @brief Removes a function from the call list. 00192 * NOTE: Only removes one instance. 00193 * 00194 * @param ctx Context to use as a look-up. 00195 * @param index Function id to add. 00196 * @return Whether or not the function was removed. 00197 */ 00198 virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index) =0; 00199 }; 00200 00201 #define SP_PARAMTYPE_ANY 0 00202 #define SP_PARAMFLAG_BYREF (1<<0) 00203 #define SP_PARAMTYPE_CELL (1<<1) 00204 #define SP_PARAMTYPE_FLOAT (2<<1) 00205 #define SP_PARAMTYPE_STRING (3<<1)|SP_PARAMFLAG_BYREF 00206 #define SP_PARAMTYPE_ARRAY (4<<1)|SP_PARAMFLAG_BYREF 00207 #define SP_PARAMTYPE_VARARG (5<<1) 00208 00209 /** 00210 * @brief Describes the various ways to pass parameters to plugins. 00211 */ 00212 enum ParamType 00213 { 00214 Param_Any = SP_PARAMTYPE_ANY, /**< Any data type can be pushed */ 00215 Param_Cell = SP_PARAMTYPE_CELL, /**< Only basic cells can be pushed */ 00216 Param_Float = SP_PARAMTYPE_FLOAT, /**< Only floats can be pushed */ 00217 Param_String = SP_PARAMTYPE_STRING, /**< Only strings can be pushed */ 00218 Param_Array = SP_PARAMTYPE_ARRAY, /**< Only arrays can be pushed */ 00219 Param_VarArgs = SP_PARAMTYPE_VARARG, /**< Same as "..." in plugins, anything can be pushed, but it will always be byref */ 00220 Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF, /**< Only a cell by reference can be pushed */ 00221 Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF, /**< Only a float by reference can be pushed */ 00222 }; 00223 00224 /** 00225 * @brief Provides functions for creating/destroying managed and unmanaged forwards. 00226 */ 00227 class IForwardManager : public SMInterface 00228 { 00229 public: 00230 virtual const char *GetInterfaceName() 00231 { 00232 return SMINTERFACE_FORWARDMANAGER_NAME; 00233 } 00234 virtual unsigned int GetInterfaceVersion() 00235 { 00236 return SMINTERFACE_FORWARDMANAGER_VERSION; 00237 } 00238 virtual bool IsVersionCompatible(unsigned int version) 00239 { 00240 if (version < 2 || version > GetInterfaceVersion()) 00241 { 00242 return false; 00243 } 00244 return true; 00245 } 00246 public: 00247 /** 00248 * @brief Creates a managed forward. This forward exists globally. 00249 * The name used to create the forward is used as its public function in all target plugins. 00250 * As new non-private plugins become loaded or unloaded, they will be automatically added 00251 * or removed. This is ideal for global, static forwards that are never changed. 00252 * 00253 * @param name Name of public function to use in forward. 00254 * @param et Execution type to be used. 00255 * @param num_params Number of parameter this function will have. 00256 * NOTE: For varargs, this should include the vararg parameter. 00257 * @param types Array of type information about each parameter. If NULL, types 00258 * are read off the vararg stream. 00259 * @param ... If types is NULL, num_params ParamTypes should be pushed. 00260 * @return A new IForward on success, NULL if type combination is impossible. 00261 */ 00262 virtual IForward *CreateForward(const char *name, 00263 ExecType et, 00264 unsigned int num_params, 00265 const ParamType *types, 00266 ...) =0; 00267 00268 /** 00269 * @brief Creates an unmanaged forward. This forward exists privately. 00270 * Unlike managed forwards, no functions are ever added by the Manager. 00271 * However, functions will be removed automatically if their parent plugin is unloaded. 00272 * 00273 * @param name Name of forward (unused except for lookup, can be NULL for anonymous). 00274 * @param et Execution type to be used. 00275 * @param num_params Number of parameter this function will have. 00276 * NOTE: For varargs, this should include the vararg parameter. 00277 * @param types Array of type information about each parameter. If NULL, types 00278 * are read off the vararg stream. 00279 * @param ... If types is NULL, num_params ParamTypes should be pushed. 00280 * @return A new IChangeableForward on success, NULL if type combination is impossible. 00281 */ 00282 virtual IChangeableForward *CreateForwardEx(const char *name, 00283 ExecType et, 00284 int num_params, 00285 const ParamType *types, 00286 ...) =0; 00287 00288 /** 00289 * @brief Finds a forward by name. Does not return anonymous forwards (named NULL or ""). 00290 * 00291 * @param name Name of forward. 00292 * @param ifchng Optionally store either NULL or an IChangeableForward pointer 00293 * depending on type of forward. 00294 * @return IForward pointer, or NULL if none found matching the name. 00295 */ 00296 virtual IForward *FindForward(const char *name, IChangeableForward **ifchng) =0; 00297 00298 /** 00299 * @brief Frees and destroys a forward object. 00300 * 00301 * @param forward An IForward created by CreateForward() or CreateForwardEx(). 00302 */ 00303 virtual void ReleaseForward(IForward *forward) =0; 00304 }; 00305 } 00306 00307 /* 00308 * In the AMX Mod X model of forwarding, each forward contained a list of pairs, each pair containing 00309 * a function ID and an AMX structure. The forward structure itself did very little but hold parameter types. 00310 * An execution call worked like this: 00311 * - executeForward() took in a function id and a list of parameters 00312 * - for each contained plugin: 00313 * - the list of parameters was preprocessed and pushed 00314 * - the call was made 00315 * - the list was freed and copybacks were made 00316 * - return 00317 * 00318 * The advantages to this is that the system is very easy to implement, and it's fast. The disadvantage is 00319 * varargs tend to be very unforgiving and inflexible, and thus weird problems arose with casting. You also 00320 * lose flexibility, type checking, and the ability to reasonably use variable arguments lists in the VM. 00321 * 00322 * SourceMod replaces this forward system with a far more advanced, but a bit bulkier one. The idea is that 00323 * each plugin has a table of functions, and each function is an ICallable object. As well as being an ICallable, 00324 * each function is an IPluginFunction. An ICallable simply describes the process of adding parameters to a 00325 * function call. An IPluginFunction describes the process of actually calling a function and performing allocation, 00326 * copybacks, and deallocations. 00327 * 00328 * A very powerful forward system emerges: a Forward is just a collection of IPluginFunctions. Thus, the same 00329 * API can be easily wrapped around a simple list, and it will look transparent to the user. 00330 * Advantages: 00331 * 1) "SP Forwards" from AMX Mod X are simply IPluginFunctions without a collection. 00332 * 2) Forwards are function based, rather than plugin based, and are thus far more flexible at runtime.. 00333 * 3) [2] Individual functions can be paused and more than one function from the same plugin can be hooked. 00334 * 4) [2] One hook type that used to map to many SP Forwards can now be centralized as one Forward. 00335 * This helps alleviate messes like Fakemeta. 00336 * 5) Parameter pushing is type-checked and allows for variable arguments. 00337 * 00338 * Note that while #2,3,4 could be added to AMX Mod X, the real binding property is #1, which makes the system 00339 * object oriented, rather than AMX Mod X, which hides the objects behind static functions. It is entirely a design 00340 * issue, rather than a usability one. The interesting part is when it gets to implementation, which has to cache 00341 * parameter pushing until execution. Without this, multiple function calls can be started across one plugin, which 00342 * will result in heap corruption given SourcePawn's implementation. 00343 * 00344 * Observe the new calling process: 00345 * - Each parameter is pushed into a local cache using the ICallable interface. 00346 * - For each function in the collection: 00347 * - Each parameter is decoded and -pushed into the function. 00348 * - The call is made. 00349 * - Return 00350 * 00351 * Astute readers will note the (minor) problems: 00352 * 1) More memory is used. Specifically, rather than N params of memory, you now have N params * M plugins. 00353 * This is because, again, parameters are cached both per-function and per-forward. 00354 * 2) There are slightly more calls going around: one extra call for each parameter, since each push is manual. 00355 * 00356 * HISTORICAL NOTES: 00357 * There used to be a # about copy backs. 00358 * Note that originally, the Forward implementation was a thin wrapper around IForwards. It did not cache pushes, 00359 * and instead immediately fired them to each internal plugin. This was to allow users to know that pointers would 00360 * be immediately resolved. Unfortunately, this became extremely burdensome on the API and exposed many problems, 00361 * the major (and breaking) one was that two separate Function objects cannot be in a calling process on the same 00362 * plugin at once. (:TODO: perhaps prevent that in the IPlugin object?) This is because heap functions lose their order 00363 * and become impossible to re-arrange without some global heap tracking mechanism. It also made iterative copy backs 00364 * for arrays/references overwhelmingly complex, since each plugin had to have its memory back-patched for each copy. 00365 * Therefore, this was scrapped for cached parameters (current implementation), which is the implementation AMX Mod X 00366 * uses. It is both faster and works better. 00367 */ 00368 00369 #endif //_INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_
1.5.1