public/IForwardSys.h
author David Anderson <dvander@alliedmods.net>
Mon May 26 07:52:27 2008 +0000 (2008-05-26)
changeset 2088 c84cd855ca10
parent 1952 b7aa2b626807
child 2181 7c85684253ed
permissions -rw-r--r--
committed two forgotten files and updated the linux makefile
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#ifndef _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_
ds@1952
    33
#define _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_
ds@1952
    34
ds@1952
    35
/**
ds@1952
    36
 * @file IForwardSys.h
ds@1952
    37
 * @brief Defines the interface for managing collections ("forwards") of plugin calls.
ds@1952
    38
 *
ds@1952
    39
 *   The Forward System is responsible for managing automated collections of IPluginFunctions.  
ds@1952
    40
 * It thus provides wrappers to calling many functions at once.  There are two types of such 
ds@1952
    41
 * wrappers: Managed and Unmanaged.  Confusingly, these terms refer to whether the user manages
ds@1952
    42
 * the forwards, not Core.  Managed forwards are completely managed by the user, and are custom
ds@1952
    43
 * editable collections.  Unmanaged forwards are the opposite, and will only work on a single global
ds@1952
    44
 * function name in all plugins.
ds@1952
    45
 */
ds@1952
    46
ds@1952
    47
#include <IPluginSys.h>
ds@1952
    48
#include <sp_vm_api.h>
ds@1952
    49
ds@1952
    50
using namespace SourcePawn;
ds@1952
    51
ds@1952
    52
#define SMINTERFACE_FORWARDMANAGER_NAME		"IForwardManager"
ds@1952
    53
#define SMINTERFACE_FORWARDMANAGER_VERSION	2
ds@1952
    54
ds@1952
    55
/*
ds@1952
    56
 * There is some very important documentation at the bottom of this file.
ds@1952
    57
 * Readers interested in knowing more about the forward system, scrolling down is a must!
ds@1952
    58
 */
ds@1952
    59
ds@1952
    60
namespace SourceMod
ds@1952
    61
{
ds@1952
    62
	/**
ds@1952
    63
	 * @brief Defines the event hook result types plugins can return.
ds@1952
    64
	 */
ds@1952
    65
	enum ResultType
ds@1952
    66
	{
ds@1952
    67
		Pl_Continue = 0,	/**< No result */
ds@1952
    68
		Pl_Changed = 1,		/**< Inputs or outputs have been overridden with new values */
ds@1952
    69
		Pl_Handled = 3,		/**< Result was handled, stop at the end */
ds@1952
    70
		Pl_Stop = 4,		/**< Result was handled, stop now */
ds@1952
    71
	};
ds@1952
    72
ds@1952
    73
	/**
ds@1952
    74
	 * @brief Defines how a forward iterates through plugin functions.
ds@1952
    75
	 */
ds@1952
    76
	enum ExecType
ds@1952
    77
	{
ds@1952
    78
		ET_Ignore = 0,		/**< Ignore all return values, return 0 */
ds@1952
    79
		ET_Single = 1,		/**< Only return the last exec, ignore all others */
ds@1952
    80
		ET_Event = 2,		/**< Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */
ds@1952
    81
		ET_Hook = 3,		/**< Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */
ds@1952
    82
		ET_Custom = 4,		/**< Ignored or handled by an IForwardFilter */
ds@1952
    83
	};
ds@1952
    84
ds@1952
    85
	class IForward;
ds@1952
    86
ds@1952
    87
	/**
ds@1952
    88
	 * @brief Allows interception of how the Forward System executes functions.
ds@1952
    89
	 */
ds@1952
    90
	class IForwardFilter
ds@1952
    91
	{
ds@1952
    92
	public:
ds@1952
    93
		/**
ds@1952
    94
		 * @brief Called when an error occurs executing a plugin.
ds@1952
    95
		 *
ds@1952
    96
		 * @param fwd		IForward pointer.
ds@1952
    97
		 * @param func		IPluginFunction pointer to the failed function.
ds@1952
    98
		 * @param err		Error code.
ds@1952
    99
		 * @return			True to handle, false to pass to global error reporter.
ds@1952
   100
		 */
ds@1952
   101
		virtual bool OnErrorReport(IForward *fwd,
ds@1952
   102
									IPluginFunction *func,
ds@1952
   103
									int err)
ds@1952
   104
		{
ds@1952
   105
			return false;
ds@1952
   106
		}
ds@1952
   107
ds@1952
   108
		/** 
ds@1952
   109
		 * @brief Called after each function return during execution.
ds@1952
   110
		 * NOTE: Only used for ET_Custom.
ds@1952
   111
		 *
ds@1952
   112
		 * @param fwd		IForward pointer.
ds@1952
   113
		 * @param func		IPluginFunction pointer to the executed function.
ds@1952
   114
		 * @param retval	Pointer to current return value (can be modified).
ds@1952
   115
		 * @return			ResultType denoting the next action to take.
ds@1952
   116
		 */
ds@1952
   117
		virtual ResultType OnFunctionReturn(IForward *fwd,
ds@1952
   118
									  IPluginFunction *func,
ds@1952
   119
									  cell_t *retval)
ds@1952
   120
		{
ds@1952
   121
			return Pl_Continue;
ds@1952
   122
		}
ds@1952
   123
ds@1952
   124
		/** 
ds@1952
   125
		 * @brief Called when execution begins.
ds@1952
   126
		 */
ds@1952
   127
		virtual void OnExecuteBegin()
ds@1952
   128
		{
ds@1952
   129
		};
ds@1952
   130
ds@1952
   131
		/**
ds@1952
   132
		 * @brief Called when execution ends.
ds@1952
   133
		 * 
ds@1952
   134
		 * @param final_ret	Final return value (modifiable).
ds@1952
   135
		 * @param success	Number of successful execs.
ds@1952
   136
		 * @param failed	Number of failed execs.
ds@1952
   137
		 */
ds@1952
   138
		virtual void OnExecuteEnd(cell_t *final_ret, unsigned int success, unsigned int failed)
ds@1952
   139
		{
ds@1952
   140
		}
ds@1952
   141
	};
ds@1952
   142
ds@1952
   143
	/**
ds@1952
   144
	 * @brief Unmanaged Forward, abstracts calling multiple functions as "forwards," or collections of functions.
ds@1952
   145
	 * 
ds@1952
   146
	 *  Parameters should be pushed in forward order, unlike the virtual machine/IPluginContext order.
ds@1952
   147
	 * Some functions are repeated in here because their documentation differs from their IPluginFunction equivalents.
ds@1952
   148
	 * Missing are the Push functions, whose only doc change is that they throw SP_ERROR_PARAM on type mismatches.
ds@1952
   149
	 */
ds@1952
   150
	class IForward : public ICallable
ds@1952
   151
	{
ds@1952
   152
	public:
ds@1952
   153
		/** Virtual Destructor */
ds@1952
   154
		virtual ~IForward()
ds@1952
   155
		{
ds@1952
   156
		}
ds@1952
   157
	public:
ds@1952
   158
		/**
ds@1952
   159
		 * @brief Returns the name of the forward.
ds@1952
   160
		 *
ds@1952
   161
		 * @return			Forward name.
ds@1952
   162
		 */
ds@1952
   163
		virtual const char *GetForwardName() =0;
ds@1952
   164
ds@1952
   165
		/**
ds@1952
   166
		 * @brief Returns the number of functions in this forward.
ds@1952
   167
		 *
ds@1952
   168
		 * @return			Number of functions in forward.
ds@1952
   169
		 */
ds@1952
   170
		virtual unsigned int GetFunctionCount() =0;
ds@1952
   171
ds@1952
   172
		/**
ds@1952
   173
		 * @brief Returns the method of multi-calling this forward has.
ds@1952
   174
		 *
ds@1952
   175
		 * @return			ExecType of the forward.
ds@1952
   176
		 */
ds@1952
   177
		virtual ExecType GetExecType() =0;
ds@1952
   178
ds@1952
   179
		/**
ds@1952
   180
		 * @brief Executes the forward.
ds@1952
   181
		 *
ds@1952
   182
		 * @param result		Optional pointer to store result in.
ds@1952
   183
		 * @param filter		Optional pointer to an IForwardFilter.
ds@1952
   184
		 * @return				Error code, if any.
ds@1952
   185
		 */
ds@1952
   186
		virtual int Execute(cell_t *result, IForwardFilter *filter=NULL) =0;
ds@1952
   187
ds@1952
   188
		/**
ds@1952
   189
		 * @brief Pushes an array of cells onto the current call.  Different rules than ICallable.
ds@1952
   190
		 * NOTE: On Execute, the pointer passed will be modified according to the copyback rule.
ds@1952
   191
		 *
ds@1952
   192
		 * @param inarray	Array to copy.  Cannot be NULL, unlike ICallable's version.
ds@1952
   193
		 * @param cells		Number of cells to allocate and optionally read from the input array.
ds@1952
   194
		 * @param flags		Whether or not changes should be copied back to the input array.
ds@1952
   195
		 * @return			Error code, if any.
ds@1952
   196
		 */
ds@1952
   197
		virtual int PushArray(cell_t *inarray, unsigned int cells, int flags=0) =0;
ds@1952
   198
	};
ds@1952
   199
ds@1952
   200
	/**
ds@1952
   201
	 * @brief Managed Forward, same as IForward, except the collection can be modified.
ds@1952
   202
	 */
ds@1952
   203
	class IChangeableForward : public IForward
ds@1952
   204
	{
ds@1952
   205
	public:
ds@1952
   206
		/** 
ds@1952
   207
		 * @brief Removes a function from the call list.
ds@1952
   208
		 * NOTE: Only removes one instance.
ds@1952
   209
		 *
ds@1952
   210
		 * @param func		Function to remove.
ds@1952
   211
		 * @return			Whether or not the function was removed.
ds@1952
   212
		 */
ds@1952
   213
		virtual bool RemoveFunction(IPluginFunction *func) =0;
ds@1952
   214
ds@1952
   215
		/** 
ds@1952
   216
		 * @brief Removes all instances of a plugin from the call list.
ds@1952
   217
		 *
ds@1952
   218
		 * @param plugin	Plugin to remove instances of.
ds@1952
   219
		 * @return			Number of functions removed therein.
ds@1952
   220
		 */
ds@1952
   221
		virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin) =0;
ds@1952
   222
ds@1952
   223
		/**
ds@1952
   224
		 * @brief Adds a function to the call list.
ds@1952
   225
		 * NOTE: Cannot be used during an incomplete call.
ds@1952
   226
		 * NOTE: If used during a call, function is temporarily queued until calls are over.
ds@1952
   227
		 * NOTE: Adding multiple copies of the same function is illegal.
ds@1952
   228
		 *
ds@1952
   229
		 * @param func		Function to add.
ds@1952
   230
		 * @return			True on success, otherwise false.
ds@1952
   231
		 */
ds@1952
   232
		virtual bool AddFunction(IPluginFunction *func) =0;
ds@1952
   233
ds@1952
   234
		/**
ds@1952
   235
		 * @brief Adds a function to the call list.
ds@1952
   236
		 * NOTE: Cannot be used during an incomplete call.
ds@1952
   237
		 * NOTE: If used during a call, function is temporarily queued until calls are over.
ds@1952
   238
		 *
ds@1952
   239
		 * @param ctx		Context to use as a look-up.
ds@1952
   240
		 * @param index		Function id to add.
ds@1952
   241
		 * @return			True on success, otherwise false.
ds@1952
   242
		 */
ds@1952
   243
		virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0;
ds@1952
   244
ds@1952
   245
		/** 
ds@1952
   246
		 * @brief Removes a function from the call list.
ds@1952
   247
		 * NOTE: Only removes one instance.
ds@1952
   248
		 *
ds@1952
   249
		 * @param ctx		Context to use as a look-up.
ds@1952
   250
		 * @param index		Function id to add.
ds@1952
   251
		 * @return			Whether or not the function was removed.
ds@1952
   252
		 */
ds@1952
   253
		virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index) =0;
ds@1952
   254
	};
ds@1952
   255
ds@1952
   256
	#define SP_PARAMTYPE_ANY	0
ds@1952
   257
	#define SP_PARAMFLAG_BYREF	(1<<0)
ds@1952
   258
	#define SP_PARAMTYPE_CELL	(1<<1)
ds@1952
   259
	#define SP_PARAMTYPE_FLOAT	(2<<1)
ds@1952
   260
	#define SP_PARAMTYPE_STRING	(3<<1)|SP_PARAMFLAG_BYREF
ds@1952
   261
	#define SP_PARAMTYPE_ARRAY	(4<<1)|SP_PARAMFLAG_BYREF
ds@1952
   262
	#define SP_PARAMTYPE_VARARG	(5<<1)
ds@1952
   263
ds@1952
   264
	/**
ds@1952
   265
	 * @brief Describes the various ways to pass parameters to plugins.
ds@1952
   266
	 */
ds@1952
   267
	enum ParamType
ds@1952
   268
	{
ds@1952
   269
		Param_Any = SP_PARAMTYPE_ANY,				/**< Any data type can be pushed */
ds@1952
   270
		Param_Cell = SP_PARAMTYPE_CELL,				/**< Only basic cells can be pushed */
ds@1952
   271
		Param_Float = SP_PARAMTYPE_FLOAT,			/**< Only floats can be pushed */
ds@1952
   272
		Param_String = SP_PARAMTYPE_STRING,			/**< Only strings can be pushed */
ds@1952
   273
		Param_Array = SP_PARAMTYPE_ARRAY,			/**< Only arrays can be pushed */
ds@1952
   274
		Param_VarArgs = SP_PARAMTYPE_VARARG,		/**< Same as "..." in plugins, anything can be pushed, but it will always be byref */
ds@1952
   275
		Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF,		/**< Only a cell by reference can be pushed */
ds@1952
   276
		Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF,	/**< Only a float by reference can be pushed */
ds@1952
   277
	};
ds@1952
   278
	
ds@1952
   279
	/**
ds@1952
   280
	 * @brief Provides functions for creating/destroying managed and unmanaged forwards.
ds@1952
   281
	 */
ds@1952
   282
	class IForwardManager : public SMInterface
ds@1952
   283
	{
ds@1952
   284
	public:
ds@1952
   285
		virtual const char *GetInterfaceName()
ds@1952
   286
		{
ds@1952
   287
			return SMINTERFACE_FORWARDMANAGER_NAME;
ds@1952
   288
		}
ds@1952
   289
		virtual unsigned int GetInterfaceVersion()
ds@1952
   290
		{
ds@1952
   291
			return SMINTERFACE_FORWARDMANAGER_VERSION;
ds@1952
   292
		}
ds@1952
   293
		virtual bool IsVersionCompatible(unsigned int version)
ds@1952
   294
		{
ds@1952
   295
			if (version < 2 || version > GetInterfaceVersion())
ds@1952
   296
			{
ds@1952
   297
				return false;
ds@1952
   298
			}
ds@1952
   299
			return true;
ds@1952
   300
		}
ds@1952
   301
	public:
ds@1952
   302
		/**
ds@1952
   303
		 * @brief Creates a managed forward.  This forward exists globally.
ds@1952
   304
		 *  The name used to create the forward is used as its public function in all target plugins.
ds@1952
   305
		 *  As new non-private plugins become loaded or unloaded, they will be automatically added
ds@1952
   306
		 * or removed.  This is ideal for global, static forwards that are never changed.
ds@1952
   307
		 *
ds@1952
   308
		 * @param name			Name of public function to use in forward.
ds@1952
   309
		 * @param et			Execution type to be used.
ds@1952
   310
		 * @param num_params	Number of parameter this function will have.
ds@1952
   311
		 *						NOTE: For varargs, this should include the vararg parameter.
ds@1952
   312
		 * @param types			Array of type information about each parameter.  If NULL, types
ds@1952
   313
		 *						are read off the vararg stream.
ds@1952
   314
		 * @param ...			If types is NULL, num_params ParamTypes should be pushed.
ds@1952
   315
		 * @return				A new IForward on success, NULL if type combination is impossible.
ds@1952
   316
		 */
ds@1952
   317
		virtual IForward *CreateForward(const char *name, 
ds@1952
   318
										ExecType et, 
ds@1952
   319
										unsigned int num_params, 
ds@1952
   320
										const ParamType *types, 
ds@1952
   321
										...) =0;
ds@1952
   322
ds@1952
   323
		/**
ds@1952
   324
		 * @brief Creates an unmanaged forward.  This forward exists privately.
ds@1952
   325
		 * Unlike managed forwards, no functions are ever added by the Manager.
ds@1952
   326
		 * However, functions will be removed automatically if their parent plugin is unloaded.
ds@1952
   327
		 *
ds@1952
   328
		 * @param name			Name of forward (unused except for lookup, can be NULL for anonymous).
ds@1952
   329
		 * @param et			Execution type to be used.
ds@1952
   330
		 * @param num_params	Number of parameter this function will have.
ds@1952
   331
		 *						NOTE: For varargs, this should include the vararg parameter.
ds@1952
   332
		 * @param types			Array of type information about each parameter.  If NULL, types
ds@1952
   333
		 *						are read off the vararg stream.
ds@1952
   334
		 * @param ...			If types is NULL, num_params ParamTypes should be pushed.
ds@1952
   335
		 * @return				A new IChangeableForward on success, NULL if type combination is impossible.
ds@1952
   336
		 */
ds@1952
   337
		virtual IChangeableForward *CreateForwardEx(const char *name, 
ds@1952
   338
													ExecType et, 
ds@1952
   339
													int num_params, 
ds@1952
   340
													const ParamType *types, 
ds@1952
   341
													...) =0;
ds@1952
   342
ds@1952
   343
		/**
ds@1952
   344
		 * @brief Finds a forward by name.  Does not return anonymous forwards (named NULL or "").
ds@1952
   345
		 *
ds@1952
   346
		 * @param name			Name of forward.
ds@1952
   347
		 * @param ifchng		Optionally store either NULL or an IChangeableForward pointer
ds@1952
   348
		 *                      depending on type of forward.
ds@1952
   349
		 * @return				IForward pointer, or NULL if none found matching the name.
ds@1952
   350
		 */
ds@1952
   351
		virtual IForward *FindForward(const char *name, IChangeableForward **ifchng) =0;
ds@1952
   352
ds@1952
   353
		/**
ds@1952
   354
		 * @brief Frees and destroys a forward object.
ds@1952
   355
		 *
ds@1952
   356
		 * @param forward		An IForward created by CreateForward() or CreateForwardEx().
ds@1952
   357
		 */
ds@1952
   358
		virtual void ReleaseForward(IForward *forward) =0;
ds@1952
   359
	};
ds@1952
   360
}
ds@1952
   361
ds@1952
   362
/*
ds@1952
   363
 *  In the AMX Mod X model of forwarding, each forward contained a list of pairs, each pair containing
ds@1952
   364
 * a function ID and an AMX structure.  The forward structure itself did very little but hold parameter types.
ds@1952
   365
 * An execution call worked like this:
ds@1952
   366
 *  - executeForward() took in a function id and a list of parameters
ds@1952
   367
 *  - for each contained plugin:
ds@1952
   368
 *   - the list of parameters was preprocessed and pushed
ds@1952
   369
 *   - the call was made
ds@1952
   370
 *   - the list was freed and copybacks were made
ds@1952
   371
 *  - return
ds@1952
   372
 * 
ds@1952
   373
 *  The advantages to this is that the system is very easy to implement, and it's fast. The disadvantage is 
ds@1952
   374
 * varargs tend to be very unforgiving and inflexible, and thus weird problems arose with casting.  You also 
ds@1952
   375
 * lose flexibility, type checking, and the ability to reasonably use variable arguments lists in the VM.
ds@1952
   376
 *
ds@1952
   377
 *  SourceMod replaces this forward system with a far more advanced, but a bit bulkier one. The idea is that 
ds@1952
   378
 * each plugin has a table of functions, and each function is an ICallable object.  As well as being an ICallable, 
ds@1952
   379
 * each function is an IPluginFunction.  An ICallable simply describes the process of adding parameters to a 
ds@1952
   380
 * function call.  An IPluginFunction describes the process of actually calling a function and performing allocation, 
ds@1952
   381
 * copybacks, and deallocations.
ds@1952
   382
 *
ds@1952
   383
 * A very powerful forward system emerges: a Forward is just a collection of IPluginFunctions.  Thus, the same 
ds@1952
   384
 * API can be easily wrapped around a simple list, and it will look transparent to the user.
ds@1952
   385
 * Advantages:
ds@1952
   386
 * 1) "SP Forwards" from AMX Mod X are simply IPluginFunctions without a collection.
ds@1952
   387
 * 2) Forwards are function based, rather than plugin based, and are thus far more flexible at runtime..
ds@1952
   388
 * 3) [2] Individual functions can be paused and more than one function from the same plugin can be hooked.
ds@1952
   389
 * 4) [2] One hook type that used to map to many SP Forwards can now be centralized as one Forward.
ds@1952
   390
 *    This helps alleviate messes like Fakemeta.
ds@1952
   391
 * 5) Parameter pushing is type-checked and allows for variable arguments.
ds@1952
   392
 *
ds@1952
   393
 *  Note that while #2,3,4 could be added to AMX Mod X, the real binding property is #1, which makes the system
ds@1952
   394
 * object oriented, rather than AMX Mod X, which hides the objects behind static functions.  It is entirely a design
ds@1952
   395
 * issue, rather than a usability one.  The interesting part is when it gets to implementation, which has to cache
ds@1952
   396
 * parameter pushing until execution.  Without this, multiple function calls can be started across one plugin, which
ds@1952
   397
 * will result in heap corruption given SourcePawn's implementation.
ds@1952
   398
 *
ds@1952
   399
 * Observe the new calling process:
ds@1952
   400
 * - Each parameter is pushed into a local cache using the ICallable interface.
ds@1952
   401
 * - For each function in the collection:
ds@1952
   402
 *  - Each parameter is decoded and -pushed into the function.
ds@1952
   403
 *  - The call is made.
ds@1952
   404
 * - Return
ds@1952
   405
 *
ds@1952
   406
 *  Astute readers will note the (minor) problems:
ds@1952
   407
 * 1) More memory is used.  Specifically, rather than N params of memory, you now have N params * M plugins.
ds@1952
   408
 *    This is because, again, parameters are cached both per-function and per-forward.
ds@1952
   409
 * 2) There are slightly more calls going around: one extra call for each parameter, since each push is manual.
ds@1952
   410
 *
ds@1952
   411
 * HISTORICAL NOTES:
ds@1952
   412
 *  There used to be a # about copy backs.  
ds@1952
   413
 *  Note that originally, the Forward implementation was a thin wrapper around IForwards.  It did not cache pushes,
ds@1952
   414
 * and instead immediately fired them to each internal plugin.  This was to allow users to know that pointers would 
ds@1952
   415
 * be immediately resolved.  Unfortunately, this became extremely burdensome on the API and exposed many problems,
ds@1952
   416
 * the major (and breaking) one was that two separate Function objects cannot be in a calling process on the same 
ds@1952
   417
 * plugin at once. (:TODO: perhaps prevent that in the IPlugin object?) This is because heap functions lose their order
ds@1952
   418
 * and become impossible to re-arrange without some global heap tracking mechanism.  It also made iterative copy backs 
ds@1952
   419
 * for arrays/references overwhelmingly complex, since each plugin had to have its memory back-patched for each copy.
ds@1952
   420
 *  Therefore, this was scrapped for cached parameters (current implementation), which is the implementation AMX Mod X 
ds@1952
   421
 * uses.  It is both faster and works better.
ds@1952
   422
 */
ds@1952
   423
ds@1952
   424
#endif //_INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_