[Include] i_pvars – Manage your PVars and create PVar arrays!
#1

i_pvars
Download
Introduction
In my long-term gamemode project, I ran into the issue of maintaining lots and lots of PVars. It was simple – I had troubles remembering which PVar does what, didn't have any list of them, and often put typos or differences hard to notice in them, like "color" vs. "colour". The first of the features of this include is the ability to quicky "declare" a PVar and then use it.
It's really straightforward:
Code:
PVAR:SKIN = "plrskin"; //int
This declares a PVar named "SKIN" and assigns the internal name "plrskin" to it. To use this PVar, simply use PVAR_SKIN:
Code:
SetPVarInt(playerid, PVAR_SKIN, GetPlayerSkin(playerid));
This way, you cannot put a typo in PVar's name, as it would produce a compiler warning. Well, you might ask, what is the difference between PVAR:SKIN and #define PVAR_SKIN or new PVAR_SKIN[]? The advantages are many:
  • It's short – this declaration is shorter than every else, thus saving script size.
  • It's easy to notice – you can even highlight the keyword PVAR if you use a custom script editor. It distinguishes the variable from all others – its internal value is not important, rather that it's a PVar.
  • Its value is stored only once – reusing defines copies their value each time you use them. If you use them many times, you'll have your AMX littered with duplicates. The advantage of being a variable is that the value is stored only once.
  • It's stock – you won't get any warning if you don't use the PVar, and it's internal value will be lost during compilation in that case, saving AMX size.
  • It's const – it will prevent you from accidentally changing the PVar's internal name, which's not what you usually would want.
Thanks to this system, you'll no longer run into bugs caused by not remembering the PVar's name correctly or putting a typo there.

There was only one minor issue during the development of this – SA-MP functions like SetPVarInt etc. have "varname[]" as their parameter and not "const varname[]" as they should (because they're not changing the value). I had to use some #emit tricks to circumvent this limitation, and as a bonus, all PVar functions have "const varname[]" now.

This was the first feature of this plugin, and now comes the most important one:
PVar arrays!
It's probable that you already have a per-player array in your script. Maybe the list of all weapons a player has, for anti-cheat purposes, or something else. However, the size of such array grows rapidly with increasing its size. A complete killer is the following one:
Code:
new plrPickupCommands[MAX_PLAYERS][MAX_PICKUPS][128];
In my gamemode, a player can assign a command to run when they pick up a pickup. However, even when limiting MAX_PLAYERS to 100, the array still contains 52428800 cells = 200 MiB in total. That's a too much for both the file size and the memory size of the script, the reason my script originally didn't have this feature before I invented PVar Arrays. And if you use a streamer, you can't even use an array at all. The number of pickups is practically infinite.

That's why it's advisable to use a PVar for a large array, especially when you don't intend to fill all cells in the array. I've already seen another PVar array system, and it used format to put the index inside the PVar's name. This script doesn't do that. Favouring speed, this script instead modifies a preallocated space inside the PVar's name and puts the index there, converting it to a 4-byte code, and then using the PVar name as usual. Because PVar names are case-insensitive, one character in the code has only 229 possible values (skipping the range of lowercase letters). This limits the total possible number of indices a bit, but it's still higher than the maximum possible value of an integer.

Enough talk, how to use it?

Declaring a PVar array is as simple as declaring a normal PVar:
Code:
PVARR:PICKUP_COMMANDS = "onpickup";
Notice the additional "R" in "PVARR". This stands for "PVar array".

There's a special syntax for accessing a PVar Array:
Code:
SetPVarString(playerid, PVAR_ARRAY<PICKUP_COMMANDS>[pickupid], cmd);
This assigns a string cmd to a PVar Array PICKUP_COMMANDS on the index pickupid for a player playerid. You also cannot use PVAR_PICKUP_COMMANDS as usual, because the declaration is actually prefixed the name with "PVAR_ARR_".

There are also some additional functions in the include:

Code:
IsPVarSet(playerid, const varname[]);
Returns true if the specified PVar is defined on a player. False if not.

Code:
SetPVarBool(playerid, const varname[], bool:bool_value)
A PVar is logically true if it's set. If bool_value is true, this sets the specified PVar to true. If not, it deletes it.

Code:
GetPVarBool(playerid, const varname[]);
In the current implementation, this is the same as IsPVarSet. A trueish PVar is any that is set, even if its set to "false".

Code:
DecodePVarArrayName(varname[], &trim=0);
If varname is a valid internal PVar array name (may be obtained by GetPVarNameAtIndex), this obtains the real index stored in the name, and also stores the length of the name without the index is trim. If varname doesn't contain index information, it returns -1.

Code:
ReformatPVarArrayName(varname[], size = sizeof(varname));
This re-formats varname to include its original index for display (in debugging) purposes as a number. It doesn't do anything if it's not a PVar array name.


I use this system intensively in my script, so it should be bug-free mostly. Still, if you find an issue, I'll gladly fix it.
That's all. Have fun with PVars!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)