14.04.2015, 21:11
YSI Secrets
IntroductionThere 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,_}:...);
pawn Код:
native printf(const format[], {Float, Text, Menu, _}:...);
pawn Код:
native printf(const format[], GLOBAL_TAG_TYPES:...);
pawn Код:
{_, Language, Bit, Text, Menu, Style, XML, Bintree, Group, Timer, File, Float, Text3D}
"PP_LOOP" is a pre-processor loop, so generates multiple blocks of code. For example:
pawn Код:
PP_LOOP<5>(printf("hi");)()
pawn Код:
printf("hi");printf("hi");printf("hi");printf("hi");printf("hi");
pawn Код:
PP_LOOP<loop count>(output)(separator)
pawn Код:
PP_LOOP<10>(55)(, )
pawn Код:
55, 55, 55, 55, 55, 55, 55, 55, 55, 55
__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
pawn Код:
#if COMPILER_1ST_PASS
#else // Or COMPILER_2ND_PASS
#endif
This is a library for fast bit-manipulation of cells:
- pawn Код:Cell_ReverseBits(cell);
Example: 0b11110000000000000000000000000000
Becomes: 0b00000000000000000000000000001111
Example: 0b10110011100011110000111110000010
Becomes: 0b01000001111100001111000111001101
Example: 0b01010101010101010101010101010101
Becomes: 0b10101010101010101010101010101010 - pawn Код:Cell_ReverseNibbles(cell);
Example: 0x12345678
Becomes: 0x87654321
Example: 0x010F0703
Becomes: 0x3070F010
Example: 0xF0F0F0F0
Becomes: 0x0F0F0F0F - pawn Код:Cell_ReverseBytes(cell);
Example: 0x12345678
Becomes: 0x78563412
Example: 0x01020304
Becomes: 0x04030201
Example: 0xFF00FF00
Becomes: 0x00FF00FF
- pawn Код:Cell_CountBits(cell);
Example: 0
Returns: 0
Example: 1
Returns: 1
Example: 0x01010101
Returns: 4 - pawn Код:Cell_GetLowestBit(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);
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)
{
} - foreign - Goes with "global" to inform a script that this function is in a different script.
pawn Код:foreign AC_GiveWeapon(playerid, weaponid, ammo);
pawn Код:
public OnScriptInit()
{
}
OnScriptExit
pawn Код:
public OnScriptExit()
{
}
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]);
}
{
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);
pawn Код:
SetMaxConnections(5, e_FLOOD_ACTION_BAN);
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@)
pawn Код:
J@ = j;
GetSomeData();
printf("%d", J@);
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
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
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).
To output your own debug prints use "P:<level>(message)":
pawn Код:
P:5("This will be printed at debug levels 5 and higher.");
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).
pawn Код:
state ysi_debug : off;
A recent addition to y_debug added level "-1":
pawn Код:
#define _DEBUG -1
pawn Код:
P:3("Message");
pawn Код:
if (gDebugLevel >= 3) printf("Message");
pawn Код:
DebugLevel(3);
pawn Код:
DebugLevel(0);
pawn Код:
new level = DebugLevel();
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.
}
- 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.
}
IS_IN_RANGE
If you have some code like this:
pawn Код:
if (a >= 0 && a < 10)
pawn Код:
if (0 <= a < 10)
pawn Код:
if (IS_IN_RANGE(a, 0, 10))
pawn Код:
if (IS_IN_RANGE(character, '0', '9' + 1))
pawn Код:
if ('0' <= character <= '9')
pawn Код:
if ('0' <= character < '9' + 1)
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;
}
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
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)