Vice City: Multiplayer

Server Development => Scripting and Server Management => Topic started by: EK.IceFlake on Feb 28, 2017, 12:18 PM

Title: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 12:18 PM
Well... I have this code
CPlayer.Account <-
{

};

dAccount <-
{
    function _set(obj, val)
    {
        print(obj + ":" + val);
    }
    function _get(obj)
    {
        print(obj);
        return null;
    }
}

CPlayer.Account.setdelegate(dAccount);

function onPlayerJoin(player)
{
    player.Account.TestVal = "000";
    print(player.Account.TestVal);
}
which I wrote to try and create an account system.
However, for some reason, this line:
    player.Account.TestVal = "000";
is returning a native stack overflow. I'm using the VCMP squirrel plugin.
It doesn't return the error if I don't have the _get function.

How should I resolve this?
Title: Re: Native stack overflow on _get
Post by: jWeb on Feb 28, 2017, 01:11 PM
First of all. You should stop treating classes like tables. Even though they are tables. They do have some differences. To Alter the members of a class one should use somelcass.newmember(...) or somelcass.rawnewmember(...) with the former being recommended.

And second. Please read the documentation:

_set:
Quoteinvoked when the index idx is not present in the object or in its delegate chain. _set must 'throw null' to notify that a key wasn't found but the there were not runtime errors(clean failure). This allows the program to defferentieate between a runtime error and a 'index not found'.

_get:
Quoteinvoked when the index idx is not present in the object or in its delegate chain. _get must 'throw null' to notify that a key wasn't found but the there were not runtime errors(clean failure). This allows the program to defferentieate between a runtime error and a 'index not found'.
Title: Re: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 01:35 PM
Quote from: jWeb on Feb 28, 2017, 01:11 PMFirst of all. You should stop treating classes like tables. Even though they are tables. They do have some differences. To Alter the members of a class one should use somelcass.newmember(...) or somelcass.rawnewmember(...) with the former being recommended.
I want to intercept it, however, so that if I do, for example, player.Account.Password = "something"; I can update the database with it, and when I do player.Account.Password, I could return the value from the database rather than from the table/class.
Title: Re: Native stack overflow on _get
Post by: jWeb on Feb 28, 2017, 01:36 PM
I was talking about:
CPlayer.Account <-
{

};
Title: Re: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 01:41 PM
Quote from: jWeb on Feb 28, 2017, 01:36 PMI was talking about:
CPlayer.Account <-
{

};
Yes, when I use
1.
CPlayer.Account <-
class
{
};
I can't setdelegate to it
2.
CPlayer.Account <-
class
{
    function _set(obj, val)
    {
        print(obj + ":" + val);
    }
    function _get(obj)
    {
        print(obj);
        return null;
    }
}
It returns a 'trying to set class' error on this line:
    player.Account.TestVal = 0;
Title: Re: Native stack overflow on _get
Post by: jWeb on Feb 28, 2017, 01:45 PM
How much do I have to point this out:

CPlayer.newmember("Account", {});
But you should be weary about a behavior unique to Squirrel here. Which is that table and array members of a class are by all instances of that class. If you don't want that then you should create the member as null and initialize it after the instance was created.
Title: Re: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 02:11 PM
Quote from: jWeb on Feb 28, 2017, 01:45 PMHow much do I have to point this out:

CPlayer.newmember("Account", {});
But you should be weary about a behavior unique to Squirrel here. Which is that table and array members of a class are by all instances of that class. If you don't want that then you should create the member as null and initialize it after the instance was created.
Okay. However, I get the same error. How do I fix that?
Title: Re: Native stack overflow on _get
Post by: DizzasTeR on Feb 28, 2017, 02:56 PM
function _set(obj, val) {
    print(obj + ":" + val);
    dAccount.rawset( obj, val );
}
Title: Re: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 02:57 PM
Quote from: Doom_Kill3R on Feb 28, 2017, 02:56 PMfunction _set(obj, val) {
    print(obj + ":" + val);
    dAccount.rawset( obj, val );
}
It's nothing about _set.
The error is caused by the _get function being present.
Title: Re: Native stack overflow on _get
Post by: DizzasTeR on Feb 28, 2017, 03:03 PM
Why are you returning null in it?
Title: Re: Native stack overflow on _get
Post by: jWeb on Feb 28, 2017, 03:27 PM
class CPlayer
{

}

local delegates = {
    function _get(idx) {
        // If we omit :: it'll call _get("print") on `this` environment
        // therefore entering an infinite recursive function
        ::print(idx);
        return null;
    }

    function _set(idx, val) {
        ::print(idx + ":" + val);
        return idx;
    }
};

CPlayer.newmember("Account", {}.setdelegate(delegates));

local p = CPlayer();

p.Account.test = "1";
Title: Re: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 04:48 PM
Now I'm facing a huge problem which I think can't be solved.
The this environment is player.Account instead of player. I thought it should be player as I'm using a table and not a class. I also can't find this anywhere in the documentation. How do I get the player environment? I tried a stack trace using getstackinfos(); but for that to work I need to know the name of the players variable.
Title: Re: Native stack overflow on _get
Post by: jWeb on Feb 28, 2017, 05:23 PM
Why would it be the player if the meta-table is bound to the Account table? The environment is not something which is inherited.
Title: Re: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 05:28 PM
Quote from: jWeb on Feb 28, 2017, 05:23 PMWhy would it be the player if the meta-table is bound to the Account table? The environment is not something which is inherited.
Well... how do I get the player environment? I'm guessing it's impossible, but I just want to confirm.
p.s. SLC @happymint was right in the fact that the official plugin is an incredibly s@#t implementation.
Title: Re: Native stack overflow on _get
Post by: . on Feb 28, 2017, 05:44 PM
With some serious workarounds this is achievable. Not pretty but achievable.

class CPlayer
{
    value = null;
    function constructor(v) { value = v; }
}

// We use this approach so that squirrel can see and use
//  the function names in debug messages even after we clone them.
AccountDelegates <- {
    function _get(idx) {
        ::print(this.value);
        return null;
    }
    function _set(idx, val) {
        ::print(this.value);
        return idx;
    }
};

CPlayer.newmember("Account", null);
// Delegates are referenced with a weak reference.
// Therefore, they must be referenced somewhere with a strong reference.
CPlayer.newmember("AccountDelegates", null);

// Construct an instance
local p = CPlayer(23);

// Forcefully bind a predefined environment
p.AccountDelegates = {
    _get = AccountDelegates._get.bindenv(p),
    _set = AccountDelegates._set.bindenv(p),
};
// Finally, create the table with our delegates
p.Account = {}.setdelegate(p.AccountDelegates);

p.Account.test = "1";
Title: Re: Native stack overflow on _get
Post by: EK.IceFlake on Feb 28, 2017, 05:56 PM
Quote from: happymint on Feb 28, 2017, 05:44 PMWith some serious workarounds this is achievable. Not pretty but achievable.

class CPlayer
{
    value = null;
    function constructor(v) { value = v; }
}

// We use this approach so that squirrel can see and use
//  the function names in debug messages even after we clone them.
AccountDelegates <- {
    function _get(idx) {
        ::print(this.value);
        return null;
    }
    function _set(idx, val) {
        ::print(this.value);
        return idx;
    }
};

CPlayer.newmember("Account", null);
// Delegates are referenced with a weak reference.
// Therefore, they must be referenced somewhere with a strong reference.
CPlayer.newmember("AccountDelegates", null);

// Construct an instance
local p = CPlayer(23);

// Forcefully bind a predefined environment
p.AccountDelegates = {
    _get = AccountDelegates._get.bindenv(p),
    _set = AccountDelegates._set.bindenv(p),
};
// Finally, create the table with our delegates
p.Account = {}.setdelegate(p.AccountDelegates);

p.Account.test = "1";
That would require some changes to the official plugin so that events would work properly. I guess I'd be better off making an account system on your plugin.
Title: Re: Native stack overflow on _get
Post by: . on Feb 28, 2017, 06:29 PM
Quote from: EK.IceFlake on Feb 28, 2017, 05:56 PM... I guess I'd be better off making an account system on your plugin.

I'm working on the same thing. But I just nuked my Windows since my previous post so now I have to set my stuff up before I can do anything again :D