API stands for application programming interface. But what is an API? Basically it's an interface that allows multiple programs/scripts to trade data and perform the same functions without having direct access to each other.
There is API functionality in AMXX plugins, implemented through a set of natives. The following natives, built into the core, allow API capabilities:
CreateMultiForward
CreateOneForward
ExecuteForward
PrepareArray
DestroyForward
But what are they used for? Well, let's take a look at an example and then pull it apart to figure out how it works. Please keep in mind that an API is designed for multiple plugins, so every example will be 2 individual scripts instead of 1 (although it's possible to put them both in one)
Code: Select all
#include <amxmodx>
new Float:g_flDelay
public plugin_init()
{
register_plugin("API Test - Core","1.0","Hawk552")
g_flDelay = random_float(0.1,0.5)
set_task(g_flDelay,"fnDoForward")
}
public fnDoForward()
{
new iForward = CreateMultiForward("plugin_init_delay",ET_IGNORE,FP_FLOAT),iReturn
if(iForward < 0)
return log_amx("Forward could not be created.")
if(!ExecuteForward(iForward,iReturn,g_flDelay))
return log_amx("Could not execute forward.")
return DestroyForward(iForward)
}Code: Select all
#include <amxmodx>
public plugin_init()
register_plugin("API Test - Attachment","1.0","Hawk552")
public plugin_init_delay(Float:flDelay)
log_amx("Forward executed %f seconds after plugin_init.",flDelay)In the first script, the important part starts at fnDoForward. What we see is:
Code: Select all
new iForward = CreateMultiForward("plugin_init_delay",ET_IGNORE,FP_FLOAT)NOTE: Difference between CreateMultiForward and CreateOneForward: multi accepts a return value and you must specify upon which condition it'll stop. Multi also sends to all plugins that have a public function after the name of const name[], as shown below. CreateOneForward requires a plugin id, and automatically ignores the return value (although you can still pass it byref)
But as for the parameters:
const name[] - this is the name of the public function you want to call from whatever plugin(s) specified
stop_type - this is what the plugin should obey in terms of stopping. For example, if you register a client command "kill" and then return PLUGIN_HANDLED, it'll stop right there. This parameter allows you to specify whether or not it will stop there, and whether or not the return value from plugins called matters. The possibilities are here:
Code: Select all
#define ET_IGNORE 0 //ignore return val
#define ET_STOP 1 //stop on PLUGIN_HANDLED
#define ET_STOP2 2 //same, except return biggest
#define ET_CONTINUE 3 //no stop, return biggest... - This is where the parameters of the header of the function called should be specified. In the above example, FP_FLOAT was specified. This is to let the AMXX core know that we want to send a floating point int to the functions called.
Here are the possibilities for the previous section (I will explain how to pass an array/string later):
Code: Select all
#define FP_CELL 0
#define FP_FLOAT 1
#define FP_STRING 2
#define FP_ARRAY 4
Next, we execute the forward using ExecuteForward. Picking this function apart:
forward_handle - this is the forward to call. It's the handle returned from CreateMultiForward / CreateOneForward.
&ret - this is the return value, passed by reference. It is effectively the value that the function being called returns (ex. return PLUGIN_HANDLED -> &ret == 1) It usually is effected by the stop_type in CreateMultiForward.
... - this is the param(s) where you can input the data that will be passed onto the function header for the function being called. In the example above, g_flDelay is passed and in the second plugin, the plugin_init_delay function recieves it in the header as Float:flDelay. NOTE: You can theoretically have infinite parameters, but they must match with the types passed into CreateOneForward / CreateMultiForward.
If ExecuteForward returns 0 (false) then we stop there and inform the server of this error. Otherwise, we continue onward to DestroyForward.
The next part we find is DestroyForward. The functionality for this is quite obvious, and can be used on any forward but should be used by the time plugin_end is called (or the FM forward for server shutting down) otherwise memory leaks can occur.
Now, what was the point of that? Not really much, that was pretty damn useless. Here's something a little more useful:
Code: Select all
#include <amxmodx>
#include <fakemeta>
new g_iForward
new g_iReturn
public plugin_init()
{
register_plugin("API Test 2 - Core","1.0","Hawk552")
g_iForward = CreateMultiForward("client_PreThink",ET_IGNORE,FP_CELL)
if(g_iForward < 0)
log_amx("Error creating forward")
register_forward(FM_PlayerPreThink,"fnForwardPlayerPreThink")
register_forward(FM_Sys_Error,"fnForwardSysError")
}
public fnForwardPlayerPreThink(id)
if(!ExecuteForward(g_iForward,g_iReturn,id))
log_amx("Could not execute forward")
public fnForwardSysError()
plugin_end()
public plugin_end()
DestroyForward(g_iForward)
Code: Select all
#include <amxmodx>
public plugin_init()
register_plugin("API Test - Attachment 2","1.0","Hawk552")
public client_PreThink(id)
log_amx("PreThink called on %d",id)But one thing remains unanswered: how do you pass an array/string?
A special native has been implemented for this, PrepareArray. Here's an example of how to use it:
Code: Select all
#include <amxmodx>
#include <fakemeta>
new g_iForward
new g_iReturn
public plugin_init()
{
register_plugin("API Test 2 - Core","1.0","Hawk552")
g_iForward = CreateMultiForward("client_PreThink",ET_IGNORE,FP_ARRAY)
if(g_iForward < 0)
log_amx("Error creating forward")
register_forward(FM_PlayerPreThink,"fnForwardPlayerPreThink")
register_forward(FM_Sys_Error,"fnForwardSysError")
}
public fnForwardPlayerPreThink(id)
{
new iRand = random(5),iArray[2]
iArray[0] = id
iArray[1] = iRand
new iArrayPass = PrepareArray(iArray,2,0)
if(!ExecuteForward(g_iForward,g_iReturn,iArrayPass))
log_amx("Could not execute forward")
}
public fnForwardSysError()
plugin_end()
public plugin_end()
DestroyForward(g_iForward)Code: Select all
#include <amxmodx>
public plugin_init()
register_plugin("API Test - Attachment 2","1.0","Hawk552")
public client_PreThink(iArray[2])
log_amx("PreThink called on %d, random value is %d",iArray[0],iArray[1])Now, to pick this apart:
We created an array and then packed it with data. You should know how to already do this.
We then use:
Code: Select all
new iArrayPass = PrepareArray(iArray,2,0)array[] - this is the array to be prepared
size - this is the amount of cells in the array (the same amount as when declaring it, not the highest cell)
copyback=0 - this is whether or not changing the array will result in the calling function's array being changed as well. This defaults to 0.
PrepareArray returns a handle as well that can be passed into ExecuteForward under the param of FP_ARRAY or FP_STRING. The difference between these two is that FP_STRING stops reading at the null terminator (and does not need to be prepared using PrepareArray), but FP_ARRAY must be prepared and only stops reading at the "size" cell.
