SA-MP Forums Archive
[Tutorial] ALS Hook Method 7 - Printable Version

+- SA-MP Forums Archive (https://sampforum.blast.hk)
+-- Forum: SA-MP Scripting and Plugins (https://sampforum.blast.hk/forumdisplay.php?fid=8)
+--- Forum: Scripting Help (https://sampforum.blast.hk/forumdisplay.php?fid=12)
+---- Forum: Tutorials (https://sampforum.blast.hk/forumdisplay.php?fid=70)
+---- Thread: [Tutorial] ALS Hook Method 7 (/showthread.php?tid=574534)



ALS Hook Method 7 - !damo!spiderman - 18.05.2015

Since ****** removed a bunch of his posts I used internet black magic and found this one and decided to repost it as it is a handy thing to have around.

ALS 4 (Hook Method 7)
Introduction

This technique is entirely thanks to lipsBruno. They proposed it in a post in the previous ALS topic and it took me a long time to figure out WHY it worked (because it shouldn't have - at least not with a standard PRE-processor). All my work up till that point had assumed that the pre-processor runs first linearly, but this method seemed to have knowledge of the future, which it turns out is because "#if defined" is handled specially in a second round of pre-processing. I frequently tell people not to treat C and PAWN as the same or they will have problems, but I fell foul of exactly that here. Anyway, the only place this was documented was a random conversation in a random topic, despite being the best ALS method to date.

This method makes callback hooking exactly as fast as a regular function call. That means that creating a function called, say "MyLib_Init" and telling people to place it in their "OnGameModeInit" function is no longer faster than ALS and (as ever) very awkward. As I said, this is the best ALS method there is, but the latest version of y_hooks is actually even faster than standard function calls because of extensive code rewriting. However, ALS is still supported because some people seem to think that using well tested efficient libraries is a bad thing...


Review

Technically "ALS" (Advanced Library System) is not a hook, it is a method of determining that another function has already been hooked, but hook methods using this macro set are collectively referred to as ALS anyway.

The basic structure is:

Код:
<function>()
{
    <chained call>();
}
<does a hook exist?>
    <yes - remove the old one>
<else>
    <no - it does now>
<end>
<rename chain>
<forward the function>
Hooking is done by having a function call another function of apparently the same name, thus "chaining" all these identical functions together so that calling one calls them all. When hooking functions this is easy because the chain calls the previous function of the same name; however, hooking callbacks is complicated by the fact that the chain calls the next function of the same name - a function that hasn't been defined yet and might not even exist. The reason ALS v3 is in a topic called "Hook Method 4" is because one of the other 3 is y_hooks. The reason this topic is called "Hook Method 7" is because I forgot about 2 other methods previously.

No hooks:


Код:
public OnGameModeInit()
{
    MyLib_Init();
    Streamer_Init();
    // etc...
}
YSI v0.1 hooks:


Код:
// Replaces "public OnGameModeInit" and calls all YSI internal functions.
Script_OnGameModeInit()
{
}
Callbacks

To chain callbacks, simply check if the next function in the chain exists, and if it does then call it:


Код:
public OnGameModeInit()
{
    #if defined MyLib_OnGameModeInit
        MyLib_OnGameModeInit();
    #endif
    return 1;
}
This is still followed by the standard ALS checks (note that, as ever, using "_ALS_" is VERY important - don't change that or your hooks will be incompatible with other includes):


Код:
#if defined _ALS_OnGameModeInit
    #undef OnGameModeInit
#else
    #define _ALS_OnGameModeInit
#endif
#define OnGameModeInit MyLib_OnGameModeInit
Finally, forward the next function in the chain if it exists:


Код:
#if defined MyLib_OnGameModeInit
    forward MyLib_OnGameModeInit();
#endif
The complete code for "OnPlayerConnect" is:


Код:
public OnPlayerConnect(playerid)
{
    #if defined MyLib_OnPlayerConnect
        MyLib_OnPlayerConnect(playerid);
    #endif
    return 1;
}
#if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
#else
    #define _ALS_OnPlayerConnect
#endif
#define OnPlayerConnect MyLib_OnPlayerConnect
#if defined MyLib_OnPlayerConnect
    forward MyLib_OnPlayerConnect(playerid);
#endif
If any parts that should be protected by "#if defined" checks are not then your code may give errors if a mode doesn't use that callback (and you won't see those errors if you don't test that case).

Functions

Function hooking is not affected by this new version - it has actually never changed because it wasn't hard in the first place, but it was never documented in a tutorial just sort of known by some. In this case, the hook does NOT have the same name as the function being hooked, so to hook GivePlayerMoney looks like:


Код:
stock MyLib_GivePlayerMoney(playerid, amount)
{
    // Call the old version, no need to check if it exists.
    GivePlayerMoney(playerid, amount);
    return 1;
}
// Has this been hooked already?
#if defined _ALS_GivePlayerMoney
    #undef GivePlayerMoney
#else
    #define _ALS_GivePlayerMoney
#endif
// Reroute future calls to our function.
#define GivePlayerMoney MyLib_GivePlayerMoney



Re: ALS Hook Method 7 - Crayder - 18.05.2015

Nice, you should try bringing the other hook methods too.


Re: ALS Hook Method 7 - Gammix - 18.05.2015

Код:
public OnPlayerConnect(playerid)
{
    #if defined MyLib_OnPlayerConnect
        MyLib_OnPlayerConnect(playerid);
    #endif
    return 1;
}
#if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
#else
    #define _ALS_OnPlayerConnect
#endif
#define OnPlayerConnect MyLib_OnPlayerConnect
#if defined MyLib_OnPlayerConnect
    forward MyLib_OnPlayerConnect(playerid);
#endif
You should add an else statement in case of returning 1 in callbacks; Because we don't always have to return 1 in callbacks.

Код:
public OnPlayerConnect(playerid)
{
    #if defined MyLib_OnPlayerConnect
        MyLib_OnPlayerConnect(playerid);
    #else
   	 	return 1;
	#endif

}
#if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
#else
    #define _ALS_OnPlayerConnect
#endif
#define OnPlayerConnect MyLib_OnPlayerConnect
#if defined MyLib_OnPlayerConnect
    forward MyLib_OnPlayerConnect(playerid);
#endif



Re: ALS Hook Method 7 - Yashas - 18.05.2015

Quote:
Originally Posted by Gammix
Посмотреть сообщение
Код:
public OnPlayerConnect(playerid)
{
    #if defined MyLib_OnPlayerConnect
        MyLib_OnPlayerConnect(playerid);
    #endif
    return 1;
}
#if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
#else
    #define _ALS_OnPlayerConnect
#endif
#define OnPlayerConnect MyLib_OnPlayerConnect
#if defined MyLib_OnPlayerConnect
    forward MyLib_OnPlayerConnect(playerid);
#endif
You should add an else statement in case of returning 1 in callbacks; Because we don't always have to return 1 in callbacks.

Код:
public OnPlayerConnect(playerid)
{
    #if defined MyLib_OnPlayerConnect
        MyLib_OnPlayerConnect(playerid);
    #else
   	 	return 1;
	#endif

}
#if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
#else
    #define _ALS_OnPlayerConnect
#endif
#define OnPlayerConnect MyLib_OnPlayerConnect
#if defined MyLib_OnPlayerConnect
    forward MyLib_OnPlayerConnect(playerid);
#endif
Even this needs modification.This is the correct way.

Код:
public OnPlayerConnect(playerid)
{
    #if defined MyLib_OnPlayerConnect
         return MyLib_OnPlayerConnect(playerid);
    #else
   	 	return 1;
	#endif

}
#if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
#else
    #define _ALS_OnPlayerConnect
#endif
#define OnPlayerConnect MyLib_OnPlayerConnect
#if defined MyLib_OnPlayerConnect
    forward MyLib_OnPlayerConnect(playerid);
#endif
You must return what MyLib_OnPlayerConnect returns.Must return 1 only if the callback is not defined.
Returning 1 will allow the callback to be called in other scripts.If you don't return anything, I don't know what will happen.I guess what ever was stored in pri just before returning will be returned.Or maybe pri is zeroed before returning.

Someone please let me know.


Re: ALS Hook Method 7 - Jonny5 - 07.06.2015

I never knew about this method,
I have converted to using this and it is the simplest of the methods.

I will be upgrading my als generator soon to use this method

thx