[Tutorial] Detecting native SA-MP functions
#1

WARNING: This tutorial is not for PAWN newbies!
Introduction:

OK, first - I want to tell you I wanted to post this, because I recently began scripting for a MiniGames server, and there are like 100 gamemode scripts (The MiniGames themselves). And this surely helps on not having to actually replace all the functions. That's why I thought it would be useful to post it. Please don't start saying "OMG It's shit" and stuff.

This tutorial is a tutorial on how to detect native SA-MP functions which aren't detected by default, like: SetPlayerScore, GivePlayerMoney, GetPlayerScore and etc. and add new functions to them. This is useful if you've got a gamemode and you want to do something every time the server calls the default function. I'll now show you with my example function: SetPlayerScore(playerid, score);

Why you need this?

Well, let's imagine you've got a gamemode, in which you're using SetPlayerScore() like 100+ times. Now, you want to detect when this SetPlayerScore() function is called. Well, wouldn't it be a pain in the ass to add a CallRemoteFunction EVERY TIME you need to add this, plus you'll need a variable every time to save the score... Well, this tutorial solves it all. This method is used to hook a callback with default SA-MP functions and execute a piece of code WHILE doing what the function does by default. And all of that, when you type the original function code.

Tutorial:

1st. Open "a_players.inc". You can find it in your "YourServer/pawno/include" folder. Now, find the line
pawn Код:
native SetPlayerScore(playerid,score);
Now, on a new line below it, type this:
pawn Код:
native CUSTOM_SetPlayerScore = SetPlayerScore;
This piece of code initiates the new function "CUSTOM_SetPlayerScore" to act like "SetPlayerScore" and to actually set your score. Save the .inc file with the name "a_players.inc" (Yes, the same name of the file you opened).


2nd. Open the "a_samp.inc", located in the same directory as "a_players.inc". Go to the bottom line (Something like 330 by default in 0.3d). In a new line (The last line for the file) type:
pawn Код:
stock My_SetPlayerScore(playerid, score)
{
    new CurScore = score - GetPlayerScore(playerid);
    CUSTOM_SetPlayerScore(playerid, score);
    CallRemoteFunction("OnPlayerScoreStateChange", "iii", playerid, CurScore, GetPlayerScore(playerid));
}
(The simple function) or
pawn Код:
stock My_SetPlayerScore(playerid, score)
{
    CUSTOM_SetPlayerScore(playerid, score);
    CallRemoteFunction("OnPlayerScoreStateChange", "i", playerid);
}
(The advanced function)
Now let me explain the lines above - The
pawn Код:
stock My_SetPlayerScore(playerid, score)
creates a new stock, you'll see what it's used for later. The
pawn Код:
CUSTOM_SetPlayerScore(playerid, score);
calls the custom SetPlayerScore function we created earlier. The
pawn Код:
CallRemoteFunction("OnPlayerScoreStateChange", "i", playerid);
calls the function in which you can add code that will be executed when the function "SetPlayerScore" (For this example) is detected.


3rd. Now, on a new line, below the stock, add
pawn Код:
#if defined _ALS_SetPlayerScore //This checks if SetPlayerScore is defined
    #undef SetPlayerScore //This undefines it, so you can hook it with the function above
#else
    #define _ALS_SetPlayerScore //This defines it if it's not defined
#endif
#define SetPlayerScore My_SetPlayerScore //This defines the default function as our function "My_SetPlayerScore"
You can change all of these to whatever you want (But ALWAYS keep the "_ALS_" in front of the functions)

4th. Under the above line, type
pawn Код:
forward OnPlayerScoreStateChange(playerid);
(The simple example from above) or
pawn Код:
forward OnPlayerScoreStateChange(playerid, difference, newscore);
(The advanced example from above[/pawn]
This is used to declare the function.

5th. Now, save the include. You can place the
pawn Код:
public OnPlayerScoreStateChange(playerid) {//Code here }
(The simple example from above) or
pawn Код:
public OnPlayerScoreStateChange(playerid, difference, newscore) {//Code here }
(The advanced example from above) anywhere in your scripts, and type what you want to happen when "SetPlayerScore" gets detected. My example for this:
pawn Код:
public OnPlayerScoreStateChange(playerid, difference, newscore)
{
    SendClientMessage(playerid, 0xff0000ff, "Your score has changed");
}
(For the simple function) Or:
pawn Код:
public OnPlayerScoreStateChange(playerid, difference, newscore)
{
    new str[64];
    format(str, sizeof(str), "Difference:%i New score:%i", difference, newscore);
    SendClientMessage(playerid, 0xff0000ff, str);
}
(For the advanced function)

NOTE: You HAVE TO recompile all the scripts that use "SetPlayerScore" for this to work.

NOTE: You don't have to add the next part to your scripts! It's just a test

Here's the output of the functions. I put this script under "OnPlayerCommandText":
pawn Код:
if (strcmp("/give", cmdtext, true, 10) == 0)
    {
        SetPlayerScore(playerid, GetPlayerScore(playerid) + 5);
        return 1;
    }
Also, have a look at this: A link for overall use of hooking, supported by ******:
https://sampforum.blast.hk/showthread.php?tid=85907

Here are the results:

*Advanced function:



*Simple function:




I hope this was useful.

Presented to you by: King_Hual
Reply
#2

This is something which hasn't been done before. Nice work!
Reply
#3

Thanks. That hooking actually mindfucked me until I figured it out
Reply
#4

Hi
u are pro
Bai
Reply
#5

Quote:
Originally Posted by Itachi_Avenger
Посмотреть сообщение
Hi
u are pro
Bai
What the....
Reply
#6

It's amazing. Can I make it with SetPlayerHealth and SetPlayerAmour for anti health-hack?
Reply
#7

Quote:
Originally Posted by ******
Посмотреть сообщение
You're joking right? There isn't much documentation on it so a tutorial is useful, but this technique was developed years ago:

https://sampforum.blast.hk/showthread.php?tid=85907

Also, I would advise against modifying the original includes - you don't actually need the second native at all as your method will bypass other hooks despite detecting them. Just call "SetPlayerScore" in your custom function, not "CUSTOM_SetPlayerScore". It comes before the "#define" so won't get replaced.
Ah, well I only found this some time ago. Thanks for the feedback, I didn't really look into the hooks... Also, I'm not sure if I understood you correctly, but I'm using CUSTOM_SetPlayerScore, because later the original SetPlayerScore gets replaced by A_SetPlayerScore... Well, I'm probably wrong, but what can I do lol

EDIT: I read your post once more and now I understand. But when I tested with SetPlayerScore, the compiler crashed...
Reply
#8

Quote:
Originally Posted by ******
Посмотреть сообщение
You're joking right? There isn't much documentation on it so a tutorial is useful, but this technique was developed years ago:

https://sampforum.blast.hk/showthread.php?tid=85907

And used in every decent library since then!

Also, I would advise against modifying the original includes - you don't actually need the second native at all as your method will bypass other hooks despite detecting them. Just call "SetPlayerScore" in your custom function, not "CUSTOM_SetPlayerScore". It comes before the "#define" so won't get replaced.
Never saw that ******. I was also not active on 2010.
Reply
#9

Ah, ******, I read that topic. Gotta admit, it's explained alot better than this one is... There are some other things too, so I'll include the link to the tutorial.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)