Do you ever wondered
how to add custom properties to the CPlayer class?For example, like
function onPlayerSpawn(player)
{
if(player.Registered)
//do something
else
//do something
}
I will show you how to add properties like '
Registered' used above.
an array and two linesF<-array(GetMaxPlayers(),0);
CPlayer.__getTable.test<-function(){return ::F[this.ID]}
CPlayer.__setTable.test<-function(val){::F[this.ID]=val}
- Added property 'test'. So you could do player.test=100
- F is any name of array.
- This can be done to the CVehicle, CPickup, CObject, CCheckpoint classes
- Where to put this? Possibly onScriptLoad
How all this works?By reading the code of squirrel plugin, it was found that
1. There is a class called CPlayer whose instances are FindPlayer(0), FindPlayer(1), etc.
2. Surprisingly it has a table called __getTable
3. If you try something like player.property and if CPlayer class do not have that property, then it will look in table mentioned in (2).
4. So if you add a
function in __getTable, you can use a new property.
This has been a top secret. There is a complete example below.
Complete Example (Spawn Protection)function onScriptLoad()
{
rawset("CPlayerProperties",{} );
AddProperty("SpawnProtection",true);
}
AddProperty<-function( property, initialval=null )
{
CPlayerProperties.rawset(property, array(GetMaxPlayers(), initialval) );
CPlayer.__getTable.rawset(property,function(){return ::CPlayerProperties.rawget(property)[this.ID]});
CPlayer.__setTable.rawset(property,function(val){::CPlayerProperties.rawget(property)[this.ID]=val});
}
function onPlayerSpawn(player)
{
player.SpawnProtection=true;
player.Immunity=31;
MessagePlayer("You have spawn protection for five seconds", player);
NewTimer("Off",5000,1,player.ID);
}
function Off(id)
{
if(FindPlayer(id))
{
FindPlayer(id).SpawnProtection=false;
FindPlayer(id).Immunity=0;
}
}
Notes about the code:
1. AddProperty <- function ( a, b) is same as function AddProperty( a, b )
2. New properties can be added to CPlayer class by calling 'AddProperty'
3. The function created for adding property needs to be modified for pickups, checkpoints and vehicles.
Edit: In the following topic, i have created a plugin for this
topic=9212.0 (https://forum.vc-mp.org/index.php?topic=9212.0)
awesome ;D
new way to write long lasting codes
There's another way to do this:
CPlayer.rawnewmember("<member name>", <default val>);
Quote from: http://squirrel-lang.org/doc/squirrel3.htmlrawnewmember(key,val,[attrs],[bstatic])
sets/adds the slot 'key' with the value 'val' and attributes 'attrs'.If bstatic is true the slot will be added as static. If the slot does not exists , it will be created. It doesn't invoke any metamethod.
Ultimately, all of the code written above could be changed to a simple:
CPlayer.rawnewmember("SpawnProtection", false);
function onPlayerSpawn(player) {
player.SpawnProtection = true;
player.Immunity = 31;
MessagePlayer("You have spawn protection for five seconds", player);
NewTimer("TurnOffSpawnProtection", 5000, 1, player.ID);
}
function TurnOffSpawnProtection(player) {
if ((player = FindPlayer(player)) != null) {
player.SpawnProtection = false;
player.Immunity = 0;
}
}
i disagree
If you use function FindPlayer in console, each time it appears you are getting a new instance. So the property will be false.
This is the same problem why 'false' is printed on console after spawning:
QuoteCPlayer.rawnewmember("SpawnProtection", false);
function onPlayerSpawn(player) {
player.SpawnProtection = true;
player.Immunity = 31;
MessagePlayer("You have spawn protection for five seconds", player);
NewTimer("TurnOffSpawnProtection", 5000, 1, player.ID);
}
function TurnOffSpawnProtection(player) {
if ((player = FindPlayer(player)) != null) {
print(player.SpawnProtection);
player.SpawnProtection = false;
player.Immunity = 0;
}
}
Quote from: habi on May 19, 2023, 04:47 PMi disagree
If you use function FindPlayer in console, each time it appears you are getting a new instance. So the property will be false.
This is the same problem why 'false' is printed on console after spawning:
QuoteCPlayer.rawnewmember("SpawnProtection", false);
function onPlayerSpawn(player) {
player.SpawnProtection = true;
player.Immunity = 31;
MessagePlayer("You have spawn protection for five seconds", player);
NewTimer("TurnOffSpawnProtection", 5000, 1, player.ID);
}
function TurnOffSpawnProtection(player) {
if ((player = FindPlayer(player)) != null) {
print(player.SpawnProtection);
player.SpawnProtection = false;
player.Immunity = 0;
}
}
I did not know of the official plugin's behavior in this regard. In SqMod we have a much better and decent approach to this whole idea, we are provided with a "Data" member of every instance (which is basically a table). One more reason to just shift :-X
Here you go :)
LUA_DELEGATE <-
{
function _get(index) {
return null;
}
function _set(index, value) {
rawset(index, value);
}
}
CPlayer.rawnewmember("data", {}.setdelegate(LUA_DELEGATE))
if(!player.data.someKey) player.data.someKey = "some value";
print(player.data.someKey); // some value
Disclaimer: Might not work on official squirrel plugin due to new instances of CPlayer getting generated and returned sometimes
But this do not work.
The table is shared with all instances, and when you rawset, it happens for all players.
Me and
@Anish87 tried playing around with this in the past, I can't recall what exactly was the approach but we had some luck. Don't think we saved it anywhere because we then soon moved the hell away from official plugin.