Adding custom properties to CPlayer class

Started by habi, May 11, 2023, 04:50 PM

Previous topic - Next topic

habi

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 lines
F<-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

Peppo

awesome ;D
new way to write long lasting codes

Xmair

#2
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;
    }
}

Credits to Boystang!

VU Full Member | VCDC 6 Coordinator & Scripter | EG A/D Contributor | Developer of VCCNR | Developer of KTB | Ex-Scripter of EAD

habi

#3
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;
    }
}

Xmair

#4
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

Credits to Boystang!

VU Full Member | VCDC 6 Coordinator & Scripter | EG A/D Contributor | Developer of VCCNR | Developer of KTB | Ex-Scripter of EAD

DizzasTeR

#5
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

habi

But this do not work.
The table is shared with all instances, and when you rawset, it happens for all players.

Spiller

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.