[Tutorial] YSI Secrets
#1

YSI Secrets
Introduction

There are loads of topics and tutorials on the big bits of YSI, but frequently there are small details scattered all over that make using and developing YSI easier, but which aren't really used at all. This topic aims to bring some of these little points together.

GLOBAL_TAG_TYPES

This is used in place of tags for variable argument functions. For example, "printf" is defined as:

pawn Код:
native printf(const format[], {Float,_}:...);
Using "{Float, _}:" means that this function can accept a range of "Float" and "_" (normal) variables. But what about "Text:" or "Group:" or "Menu:"? You could write:

pawn Код:
native printf(const format[], {Float, Text, Menu, _}:...);
To avoid getting tag mismatch warnings when trying to print those variable types, or you can do:

pawn Код:
native printf(const format[], GLOBAL_TAG_TYPES:...);
Which is defined in YSI as:

pawn Код:
{_, Language, Bit, Text, Menu, Style, XML, Bintree, Group, Timer, File, Float, Text3D}
PP_LOOP

"PP_LOOP" is a pre-processor loop, so generates multiple blocks of code. For example:

pawn Код:
PP_LOOP<5>(printf("hi");)()
Will compile as:

pawn Код:
printf("hi");printf("hi");printf("hi");printf("hi");printf("hi");
The definition of this macro is:

pawn Код:
PP_LOOP<loop count>(output)(separator)
The separator goes BETWEEN instances of "output", but not at the end. So you can make a list as:

pawn Код:
PP_LOOP<10>(55)(, )
And that will compile as:

pawn Код:
55, 55, 55, 55, 55, 55, 55, 55, 55, 55
Note the lack of ", " on the end because that's not separating anything.

__COMPILER_PASS

The PAWN compiler does TWO pre-processing stages. It's rare that this is a problem, but if you need to know which stage is being run you can do:

pawn Код:
#if __COMPILER_PASS == 0
#else // 1 for second pass.
#endif
Alternatively:

pawn Код:
#if COMPILER_1ST_PASS
#else // Or COMPILER_2ND_PASS
#endif
y_cell

This is a library for fast bit-manipulation of cells:
  • pawn Код:
    Cell_ReverseBits(cell);
    Reverse all the bits in a cell:

    Example: 0b11110000000000000000000000000000
    Becomes: 0b00000000000000000000000000001111

    Example: 0b10110011100011110000111110000010
    Becomes: 0b01000001111100001111000111001101

    Example: 0b01010101010101010101010101010101
    Becomes: 0b10101010101010101010101010101010
  • pawn Код:
    Cell_ReverseNibbles(cell);
    Reverse all the nibbles in a cell:

    Example: 0x12345678
    Becomes: 0x87654321

    Example: 0x010F0703
    Becomes: 0x3070F010

    Example: 0xF0F0F0F0
    Becomes: 0x0F0F0F0F
  • pawn Код:
    Cell_ReverseBytes(cell);
    Reverse all the bytes in a cell:

    Example: 0x12345678
    Becomes: 0x78563412

    Example: 0x01020304
    Becomes: 0x04030201

    Example: 0xFF00FF00
    Becomes: 0x00FF00FF

  • pawn Код:
    Cell_CountBits(cell);
    Count all the "1s" in a cell.

    Example: 0
    Returns: 0

    Example: 1
    Returns: 1

    Example: 0x01010101
    Returns: 4
  • pawn Код:
    Cell_GetLowestBit(cell);
    Returns a number between 0 and 31, representing the least significant set bit in a cell:

    Example: 0b00000000000000000000000000000001
    Returns: 0

    Example: 0b00000000000000000000000000001000
    Returns: 3

    Example: 0b00010001100011000011100010001000
    Returns: 3

    NOTE THAT THIS FUNCTION RETURNS 0 IF THERE ARE NO BITS SET.
  • pawn Код:
    Cell_GetLowestComponent(cell);
    Returns the lowest set bit in a cell:

    Example: 0b00000000000000000000000000000001
    Returns: 0b00000000000000000000000000000001

    Example: 0b00000000000000000000000000001000
    Returns: 0b00000000000000000000000000001000

    Example: 0b00010001100011000011100010001000
    Returns: 0b00000000000000000000000000001000

    Keywords

    Most people know that YSI adds "foreach" to the PAWN language, but here is a list of other keywords added by it:
  • foreach - Efficiently looping over sparse arrays and iterators.

    pawn Код:
    foreach (new i : Player) printf("Player %d", i);
  • task - Timer function that is always running as long as the server is up.

    pawn Код:
    task Ping[1000]()
    {
        printf("Ping");
    }
  • ptask - Similar to "task", but has a "playerid" parameter.

    pawn Код:
    ptask PlayerPing[1000](playerid)
    {
        printf("Ping %d", playerid);
    }
  • loadtext - Load localised string data for displaying text.

    pawn Код:
    loadtext core[ysi_properties];
  • remote - A public function that can be called from other scripts with compile-time parameter checking.

    pawn Код:
    remote MyFunc(a, b[])
    {
    }
  • broadcastfunc - Call a remote function in all other scripts.

    pawn Код:
    broadcastfunc MyFunc(42, "Hello World.");
  • inline - Declare a function inside another function, and get access to the enclosing function's variables.

    pawn Код:
    stock Outer(a)
    {
        inline Inner(b)
        {
            printf("%d %d", a, b);
        }
    }
  • using - Pass an inline function to another function as a callback.

    pawn Код:
    INI_Parse(file, using inline Local_Parse);

  • hook - Use a callback multiple times in multiple files without conflict.

    pawn Код:
    hook OnPlayerConnect(playerid)
    {
    }

  • global - When running multiple scripts, only one should be in charge of, say, the anti-cheat. This declares a function as "global", such that all scripts can use it but only one script will be in charge.

    pawn Код:
    global AC_GiveWeapon(playerid, weaponid, ammo)
    {
    }
    "remote" functions are called in ALL other scripts, "global" functions are called in just one.
  • foreign - Goes with "global" to inform a script that this function is in a different script.

    pawn Код:
    foreign AC_GiveWeapon(playerid, weaponid, ammo);
OnScriptInit

pawn Код:
public OnScriptInit()
{
}
This is like "OnGameModeInit" or "OnFilterScriptInit", but works the same in both (i.e. is called once at the start). A good option for initialisation code in an include as they it doesn't matter where your include is used.

OnScriptExit

pawn Код:
public OnScriptExit()
{
}
Like "OnScriptInit", but called when a script ends.

Dynamic Memory Allocation

Using YSI you can allocate and free memory when you like (and as much as you like):

pawn Код:
func(arr[], size)
{
    for (new i = 0; i != size; ++i) printf("%d", arr[i]);
}
main()
{
new Alloc:a = malloc(1000); // Allocate 1000 cells.

mset(a, 0, 50); // Write "50" to the first slot.

// Pass our newly allocated array to a function.
func(mget(a, 0), Malloc_SlotSize(a));

// Free the memory (or we will eventually run out).
free(a);
}

Restricting Connections

You can limit how many people can connect to your server from the same IP:

pawn Код:
SetMaxConnections(3);
That lets 3 people connect from the same IP. If any more try join they will fail to connect. You can also change what happens when too many people join:

pawn Код:
SetMaxConnections(5, e_FLOOD_ACTION_BAN);
That will ban an IP if more than 5 people try to connect from it. The available actions are:

e_FLOOD_ACTION_BLOCK - Don't let any more connect (default).
e_FLOOD_ACTION_KICK - Kick everyone using that IP.
e_FLOOD_ACTION_BAN - Ban the IP (the players will time out).
e_FLOOD_ACTION_FBAN - Ban the IP and instantly kick all the players on that IP.

Temp Variables

Sometimes you need a variable for a fraction of a second (or just a few expressions. YSI has 3 of these "temp" variables already to avoid creating more: I@, J@, and Q@[YSI_MAX_STRING].

pawn Код:
#define ReturnPlayerHealth(%0) (GetPlayerHealth((%0), Float:I@), Float:I@)
pawn Код:
#define ReturnPlayerName(%0) (GetPlayerName((%0), Q@, 24), Q@)
These variables can NOT be relied upon over function calls, so this might not work:

pawn Код:
J@ = j;
GetSomeData();
printf("%d", J@);
"GetSomeData" might modify "J@" and you would never know. These are purely for getting some data then using it pretty much straight away.

There is also another one of these short variables: "_@" (yes, the variable is called <underscore><at>). This is the "Master ID" for a script. All currently running scripts have an ID.

Short Functions

Speaking of short variables, there are some short functions too. These are used in complex macros to reduce the length of the generated code to fit in tight line-length restrictions:
  • U@ = setproperty
  • V@ = getproperty
  • W@ = CallRemoteFunction
  • P@ = CallLocalFunction
  • O@ = SetTimerEx
  • K@ = SetTimer
Debug Prints

If you compile a YSI mode with "_DEBUG" set, you get a load of information in the compiler window. This macro means that the prints are ONLY included at the correct level and not any other time, so using "_DEBUG 0" (or none at all) will strip all the print statements from the mode for the best performance.

pawn Код:
#define _DEBUG 3
#include <YSI\y_whatever>

The number after "_DEBUG" is the "debug level" (default 0) and there are 8 levels:
  • 0 = No debugging.
  • 1 = Show public function calls (callbacks and timers).
  • 2 = Show API function calls (main YSI functions).
  • 3 = Show stock function calls (secondary YSI functions).
  • 4 = Show internal function calls.
  • 5 = Show function branches (extra debug information within functions).
  • 6 = Show loop repeats (prints within loops).
  • 7 = Show extra loops (even more prints in loops).
I will warn you - use level 7 VERY rarely, even I try to avoid it as it generates several Mb of log data just for STARTING your server!

To output your own debug prints use "P:<level>(message)":

pawn Код:
P:5("This will be printed at debug levels 5 and higher.");
Special Prints

Besides the 8 levels mentioned above, there are some special levels:

pawn Код:
P:F("Fatal error message");
// Prints "*** YSI Fatal Error: <your message>"
// Beeps 5 times to alert the user.
pawn Код:
P:E("Error message");
// Prints "*** YSI Error: <your message>"
// Beeps 3 times to alert the user.
pawn Код:
P:W("Warning message");
// Prints "*** YSI Warning: <your message>"
// Beeps 1 time to alert the user.
pawn Код:
P:I("Info message");
// Prints "*** YSI Info: <your message>"
// Very similar to doing "P:0" (which is a thing).
These special prints are ALWAYS compiled because they give the user important information about errors in code, and not just random debug information. However, they can be suppressed by doing:

pawn Код:
state ysi_debug : off;
Dynamic Prints

A recent addition to y_debug added level "-1":

pawn Код:
#define _DEBUG -1
This activates run-time debug level selection, so doing:

pawn Код:
P:3("Message");
Compiles as:

pawn Код:
if (gDebugLevel >= 3) printf("Message");
You can then change the level at run-time with:

pawn Код:
DebugLevel(3);
Disable most printing (except special ones - see above) with:

pawn Код:
DebugLevel(0);
And get the current debug level with:

pawn Код:
new level = DebugLevel();
Special Tags

YSI introduces two special tags for functions. These can be used to optimise code in some instances:
  • void - People familiar with "C" might recognise this as "no return", i.e. the function doesn't return anything:

    pawn Код:
    void:Func()
    {
        // No return.
    }
    When using y_master, this will actually make the generated code faster, and give an error if you put "return" in your function and try use that return value. Technically you can still have "return", you just can't use the value.

  • string - This is used all over YSI, not just as a return type. Anything with a "string:" tag is just a normal string, and entirely compatible with regular strings, but there are times when it is useful for the compiler to know the difference between an array and a string:

    pawn Код:
    string:Func(string:a[], b[])
    {
        // Function that takes a string (a) and an array (b), and returns a string.
    }
This is used extensively with YSI keywords - "timer", "global", "inline", and "remotefunc" all rely on "string:" to generate code that uses "s" instead of "a" (arrays must be followed by a length parameter, strings needn't be).

IS_IN_RANGE

If you have some code like this:

pawn Код:
if (a >= 0 && a < 10)
Or the much better:

pawn Код:
if (0 <= a < 10)
You can now use YSI to do it an even better way:

pawn Код:
if (IS_IN_RANGE(a, 0, 10))
This checks that the first parameter is AT LEAST the second parameter, and SMALLER than the third parameter, and is faster than the other two methods. If you want to change the ranges, add or subtract 1. For example to check if something is a numeric character do:

pawn Код:
if (IS_IN_RANGE(character, '0', '9' + 1))
That will do:

pawn Код:
if ('0' <= character <= '9')
Or more strictly it will do:

pawn Код:
if ('0' <= character < '9' + 1)
These being integers, those are the same (they aren't for floats).

RUN_TIMING

This is a simplified way to get many statistics comparing two bits of [pawn]

pawn Код:
RUN_TIMING("Version 1 (+)")
{
    a = b + 5;
}
RUN_TIMING("Version 2 (+=)")
{
    a = b;
    a += 5;
}
Will output something like:

pawn Код:
Timing "Version 1 (+)"...
          Mean = 78.00ns
          Mode = 76.00ns
        Median = 78.00ns
         Range = 9.00ns
Timing "Version 2 (+=)"...
          Mean = 94.00ns
          Mode = 94.00ns
        Median = 94.00ns
         Range = 15.00ns
If you don't understand statistics, pick the one with the lowest "Mean", or better yet learn statistics.

There is an optional second parameter to control the number of loops if the experiments run too quickly or slowly:

pawn Код:
RUN_TIMING("Version 2 (+=)", 100)
More credits to ******..
Reply
#2

Thanks.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)