12.11.2012, 17:44
(
Последний раз редактировалось Lordzy; 23.12.2013 в 06:26.
)
How to hook Functions & Callbacks
IntroductionWell here I'm with my 3rd tutorial regarding hooking functions & callbacks. Yet this is even possible easily using y_hooks created by ****** but I thought of posting a tutorial regarding manual hooking method for users who like to know how to hook through manual way. There are other methods too for hooking callbacks/functions, but here I'm with what I know.
Hooking
Hooking means to add something on a particular thing. Here, we refer it to adding something too on a callback or function. For example, function 'SetPlayerScore' sets the player's score. But if we are using a server sided score system, the 'SetPlayerScore' won't set it. So, we've gotta set that server sided score too by setting variables.
Here's an example
pawn Код:
public OnPlayerSpawn(playerid)
{
SetPlayerScore(playerid, 50);
return 1;
}
pawn Код:
enum g_PLAYER_DATA
{
L_KILLS,
L_DEATHS,
L_SCORE,
L_MONEY,
L_HEALTH,
L_ADMIN,
L_CLAN,
L_VIP
}
new L_PLAYER_INFO[MAX_PLAYERS][g_PLAYER_DATA];
//Example enum ^^
public OnPlayerSpawn(playerid)
{
SetPlayerScore(playerid, 50);
L_PLAYER_INFO[playerid][L_SCORE] = 50; //We've set our server sided score too.
return 1;
}
Tutorial
Hooking Functions
Let's take an example that like the above. We'll hook 'SetPlayerScore' function. Inorder to hook, we can create a simple function as we create in our scripts using 'stock.'
Example stocks(functions)
pawn Код:
stock GetName(playerid)
{
new Lname[MAX_PLAYER_NAME];
GetPlayerName(playerid, Lname, sizeof(Lname));
return Lname;
}
//Now this is a function which gets player's name in one single line.
//Using it.
public OnPlayerDeath(playerid, killerid, reason)
{
new str[128];
format(str, sizeof(str), "%s killed %s", GetName(killerid), GetName(playerid)); //Gets the name of killer and the dead person.
SendClientMessageToAll(0xFF0000FF, str);
return 1;
}
Now, let's hook our 'SetPlayerScore' function. To hook, first we must create a simple function of the server sided score. We can use 'stock' to create the function.
pawn Код:
stock SetPlayerScoreEx(playerid, amount) //Two parameters: playerid, for the player and amount, the amount to set.
{ //Opening brackets to execute the functions below.
//We'll choose our made enum above and set it.
L_PLAYER_INFO[playerid][L_SCORE] = amount; //It sets the server sided score to amount. Amount will be specified on the function by user itself.
SetPlayerScore(playerid, amount); //We'll later undefine 'SetPlayerScore' function and hook it with our current stock. So it's necessary to use this function too or it doesn't make any sense it saying 'hooking SetPlayerScpre.'
return 1; //Returning the function.
} //Closing brackets.
'SetPlayerScoreEx(playerid, amount);'
Example:
pawn Код:
public OnPlayerSpawn(playerid)
{
SetPlayerScoreEx(playerid, 50); //Sets to 50 server sided score and also the original score.
return 1;
}
pawn Код:
stock SetPlayerScoreEx(playerid, amount);
{
L_PLAYER_INFO[playerid][L_SCORE] = amount;
SetPlayerScore(playerid, amount);
return 1;
}
/*Our function created.^^
pawn Код:
stock SetPlayerScoreEx(playerid, amount);
{
L_PLAYER_INFO[playerid][L_SCORE] = amount;
SetPlayerScore(playerid, amount); //We must do this too because we're gonna undefine the SetPlayerScore function later and hook it with our.
return 1;
}
/*Our function created.^^
Hooking:*/
#if defined _ALS_SetPlayerScore //If _ALS_SetPlayerScore is defined. Then:
#undef SetPlayerScore //If yes, it will undefine SetPlayerScore function.
#else //Else if not defined
#define _ALS_SetPlayerScore //If not defined, it will define _ALS_SetPlayerScore.
#endif //As we started a PAWN function with '#if', it's necessary to use #endif or you'll get trouble with errors.
/*SetPlayerScore is now undefined, we can define it to whatever we need :P. Even this:
#define SetPlayerScore 0xFF0000
But here, we must hook it, so we must define it to our function which we have created.*/
#define SetPlayerScore SetPlayerScoreEx //As we have undefined SetPlayerScore, inorder to hook it, we must define it to the stock function which we created.
Example:
pawn Код:
public OnPlayerSpawn(playerid)
{
SetPlayerScore(playerid, amount);
//This do sets the original score as well as the server sided score to 50.
return 1;
}
Hooking Callbacks
This is also almost same as hooking callbacks, though it needs some more stuffs to do too. Lets hook OnPlayerSpawn.
To hook on callbacks, we don't need to create a stock/function for it. While hooking OnPlayerSpawn or any original SAMP callback, we must hook and create a callback inside the callback which needs to get hooked.
pawn Код:
public OnPlayerSpawn(playerid)
{
//This callback is called when a player spawns.
return 1;
}
'public OnPlayerSpawn(playerid, weaponid)'
First, we must create another callback to hook with, like how we created a function to hook.
pawn Код:
public OnPlayerSpawn(playerid)
{
//As we want to get the weaponid as a parameter on spawn callback, let's create a variable to get it.
new weaponid; //Created a variable to get player's weapon.
weaponid = GetPlayerWeapon(playerid);
//To create a callback, we use CallLocalFunction. For more explanation about CallLocalFunction, go to wiki.sa-mp.com/wiki/CallLocalFunction
CallLocalFunction("L_OnPlayerSpawn", "id", playerid, weaponid);
/*"id" are the formats used. 'i' and 'd' stands for the playerid and weaponid as those are integers/number. 'i' and 'd' both, stands same though.
It's done with creating a callback.*/
return 1; //Returning the callback.
} //Closing brackets.
pawn Код:
public OnPlayerSpawn(playerid)
{
new weaponid;
weaponid = GetPlayerWeapon(playerid);
CallLocalFunction("L_OnPlayerSpawn", "id", playerid, weaponid);
}
/*This was those callback and calls for the original callback we done. Now lets hook it.
Same like functions, we do use _ALS_ defining here.
In here, it's used that if _ALS_(callback name) is defined, we will undefine the callback and if it isn't defined, we'll define the _ALS_(callback name).
And then hook the callback.
*/
#if defined _ALS_OnPlayerSpawn //If _ALS_OnPlayerSpawn is defined:
#undef OnPlayerSpawn //If defined, it will undefine OnPlayerSpawn.
#else //Else if not:
#define _ALS_OnPlayerSpawn //If not, we'll define _ALS_OnPlayerSpawn.
#endif //As we started a PAWN function '#if', it's necessary to use #endif or you'll get troubled.
//As the callback 'OnPlayerSpawn' is undefined now, we can define it to whatever but here we are hooking it. So define it to our callback created, 'L_OnPlayerSpawn'.
#define OnPlayerSpawn L_OnPlayerSpawn
//Even though we hooked it, we must forward the callback too inorder to get it used.
forward L_OnPlayerSpawn(playerid, weaponid); //We must forward the callback which created itself.
pawn Код:
public OnPlayerSpawn(playerid, weaponid);
{
new str[128];
SetPlayerScore(playerid, amount); //Sets the server sided score too as we have hooked.
format(str, sizeof(str), "You are using %d weaponid.", weaponid);
SendClientMessage(playerid, 0xFF0000, str);
return 1;
}
Examples
Some examples:
pawn Код:
public OnFilterScriptInit()
{
SetTimer("Loopplayers", 1000, true);
CallLocalFunction("L_OnFilterScriptInit", "");
return 1;
}
forward Loopplayers();
public Loopplayers()
{
for(new i = 0; i< MAX_PLAYERS; i++)
{
if(IsPlayerConnected(i))
{
if(GetPlayerHealth(i) >= 101)
{
SetPlayerHealth(i, 100);
}
}
}
return 1;
}
#if defined _ALS_OnFilterScriptInit
#undef OnFilterScriptInit
#else
#define _ALS_OnFilterScriptInit
#endif
#define OnFilterScriptInit L_OnFilterScriptInit
forward L_OnFilterScriptInit();
pawn Код:
new lhp[MAX_PLAYERS];
stock SetPlayerHp(playerid, amount)
{
lhp[playerid] = amount;
SetPlayerHealth(playerid, amount);
return 1;
}
#if defined _ALS_SetPlayerHealth
#undef SetPlayerHealth
#else
#define _ALS_SetPlayerHealth
#endif
#define SetPlayerHealth SetPlayerHp
public OnFilterScriptInit()
{
SetTimer("Detecthp", 1000, true);
CallLocalFunction("L_OnFilterScriptInit", "");
return 1;
}
forward Detecthp();
public Detecthp()
{
for(new i = 0; i< MAX_PLAYERS; i++)
{
if(GetPlayerHealth(i) > lhp[i])
{
new str[128];
new LName[MAX_PLAYER_NAME];
GetPlayerName(playerid, Lname, sizeof(Lname));
format(str, sizeof(str), "%s has been banned from the server. (Reason:Health hack)", Lname);
Ban(playerid);
}
}
return 1;
}
#if defined _ALS_OnFilterScriptInit
#undef OnFilterScriptInit
#else
#define _ALS_OnFilterScriptInit
#endif
#define OnFilterScriptInit L_OnFilterScriptInit
forward L_OnFilterScriptInit();
Doubts, questions or anything related to this tutorial can be posted here.
-Lordz™.