[Tutorial] Determining the type of script (FS/GM) using state
#1

Hello everyone

Preface:
Recently i found a forum topic "how to better structure the anticheat", where i found out that the best way for me to be implemented in include, would hook to both filterscript and to gamemode. But there was a small problem: as ****** write, we can not always know whether the user define in his filterscript "FILTERSCRIPT" (from what one would know that it is FS), or not.
However, I needed a way that will not involve any two different files, not provided above is not very reliable option.
The above-mentioned ****** suggested this method:

pawn Код:
new bool:AC_FILTERSCRIPT = false;

public OnFilterScriptInit()
{
    AC_FILTERSCRIPT = true;
    AC_OnScriptInit();
}

public OnGameModeInit()
{
    if (!AC_FILTERSCRIPT) AC_OnScriptInit();
}
But after analyzing it, I realized that calling callbacks, for example, OnPlayerUpdate need in FS and in GameMode, thus every time in every callback will go check conditions "whether it filterscript or not" (with this method these checks will also be, but implicit, i.e. you don't have to write their every time).

As a result, I made my version based on his ideas and code but using state which I checked for correctness at the moment.

So, the idea of code is as follows:

pawn Код:
public OnFilterScriptInit()
{
    state ScriptType:FilterScript;
    return 1;
}

//All subsequent publics

public OnGameModeInit() <ScriptType:FilterScript> //If FilterScript
{
    print("This is FilterScript!");
    return 1;
}

public OnGameModeInit() <> //Else (GameMode)
{
    print("This is GameMode!");
    return 1;
}
Ok, you can load this script as FS or like GM at the same time depending on your choice, and when you turn on the server, will be written one of two messages (and therefore executed only one of the two OnGameModeInit). Well, as this is just an example, in practice it will work with all the publics.

How can we adapt all this to the include so that when GameMode/FS is started, does it determine accordingly?
Simply! To do this, we will use the above code + Hook Method 7, namely:

pawn Код:
public OnFilterScriptInit()
{
    state ScriptType:FilterScript;
    //Hook Method 7
    #if defined MyLib_OnFilterScriptInit
        return MyLib_OnFilterScriptInit();
    #else
        return 1;
    #endif
}

//Hook Method 7
#if defined _ALS_OnFilterScriptInit
    #undef OnFilterScriptInit
#else
    #define _ALS_OnFilterScriptInit
#endif
#define OnFilterScriptInit MyLib_OnFilterScriptInit
#if defined MyLib_OnFilterScriptInit
    forward MyLib_OnFilterScriptInit();
#endif

public OnGameModeInit() <ScriptType:FilterScript>
{
    print("[Inc] This is FilterScript!");
    //Hook Method 7
    #if defined MyLib_OnGameModeInit
        return MyLib_OnGameModeInit();
    #else
        return 1;
    #endif
}

public OnGameModeInit() <>
{
    print("[Inc] This is GameMode!");
    //Hook Method 7
    #if defined MyLib_OnGameModeInit
        return MyLib_OnGameModeInit();
    #else
        return 1;
    #endif
}

//Hook Method 7
#if defined _ALS_OnGameModeInit
    #undef OnGameModeInit
#else
    #define _ALS_OnGameModeInit
#endif
#define OnGameModeInit MyLib_OnGameModeInit
#if defined MyLib_OnGameModeInit
    forward MyLib_OnGameModeInit();
#endif
In this case, the call to the final public will be the same as if it had been called immediately.
Note, it is important to consider that being called under different states, OnGameModeInit is one public, so the code

pawn Код:
#if defined _ALS_OnGameModeInit
    #undef OnGameModeInit
#else
    #define _ALS_OnGameModeInit
#endif
#define OnGameModeInit MyLib_OnGameModeInit
#if defined MyLib_OnGameModeInit
    forward MyLib_OnGameModeInit();
#endif
We use only once, and at the end.
Again, we can work with any other callbacks as with OnGameModeInit.

By the way: you should specify your own tag for any hook in order to avoid any coincidence between them. The "MyLib_" tag is an example.


If you want to call public only for one case - this macros will be useful (thanks ******):

Quote:
Originally Posted by ******
Посмотреть сообщение
pawn Код:
#define fspublic%0(%1) public%0(%1) <> {} public%0(%1) <ScriptType:FilterScript>
#define gmpublic%0(%1) public%0(%1) <ScriptType:FilterScript> {} public%0(%1) <>
Then you just have:

pawn Код:
fspublic OnPlayerUpdate()
{
}
Outcome:
This method is useful in any case, since is determined the type of script directly while it is running.

P.s. Well, now to see everything is in practice you can download the script below.
You can load the script both as GM and as FS - in any case when the server starts, in console will be written your choice, and when you connect to the server - in the chat

If you have any suggestions, I will be glad to hear them.
Thank U.
Reply
#2

seems good
Reply
#3

Nice Job
Reply
#4

That, is pretty darn inventive...

Surprised no-one actually thought of this before.

Could make a new.pwn that doesn't matter on how it's coded, as it can be used for both... Impressive.
Reply
#5

Quote:
Originally Posted by Sew_Sumi
Посмотреть сообщение
That, is pretty darn inventive...

Surprised no-one actually thought of this before.

Could make a new.pwn that doesn't matter on how it's coded, as it can be used for both... Impressive.
Thx
But as they say: "all genius is simple". Honestly, I've just recently learned about the state, just a lucky coincidence helped me come up this)
And yes, of course, I'll add the script soon.
Reply
#6

It is very interesting, but one question; What difference has this to #if defined FILTERSCRIPT?
Reply
#7

Quote:
Originally Posted by _Zume
Посмотреть сообщение
It is very interesting, but one question; What difference has this to #if defined FILTERSCRIPT?
Because it's not using the define to figure out what its being used as.

This script segment can be used in ANY script, and whether it's loaded as a filterscript, or a gamemode, it will pick it up itself as to what it is, no define from the scripter needed.


I'd say that's the difference.
Reply
#8

Quote:
Originally Posted by ******
Посмотреть сообщение
I'm not sure what you mean by this. Why would OnPlayerUpdate need to check if it is in an FS or not?

However, I like your use of states for this - they are very rarely used in SA:MP, mostly because we tend to deal with multiple players, each of whom need their own state, whereas the PAWN states can only hold one piece of state information at a time.
Ok, I just not as formulated) (although is possible to blame ****** translate )
Is better to describe an example:
I need to execute some code in OnPlayerUpdate, but with the proviso that it is not call in filterscript.
Using your method, I have to insert this code in callback

pawn Код:
public OnPlayerUpdate()
{
    if (!AC_FILTERSCRIPT)
    {
        //Code...
    }
    return 1;
}
But it will be executed every time you call this public that in my opinion not very good.
Although it is possible I missed some important detail, and in your method can be avoided it.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)