Curious feature for onEnteringState and length of arrays in args

Game development with Board Game Arena Studio
Post Reply
User avatar
CuriousTerran
Posts: 21
Joined: 12 July 2020, 21:03

Curious feature for onEnteringState and length of arrays in args

Post by CuriousTerran »

On the game php side my state uses an argument function to pass valid locations to play like the reversi tutorial.
I build the locations in php scetched like this
$objData = self::getObjectListFromDB(...)
$objArr = array();
foreach ($objData as $idx => $Data)
{
...do some calcs and filter entries to valid ones...
$objArr[] = array('key1'=>$val1, 'key2'=>$val2,....)
}
$objArr is an array of arrays with indices/keys of 0,1,2,... that is returned from the argument function.

Then, this argument function is named as the "args" function in the state file, so this array shows up on the java side as part of onEnteringState.
Most of the time this works, I see objArr and it has the correct contents and important for my checks in onEnteringState , I can get the length of objArr from args.objArr.length.
However, on the php side I have another filtering step where I remove array elements from $objArr using the php unset() function. This again works most of the time on the js side and I get the correct length from args.objArr.length.

However, there is catch, if on the php side I use unset() on the first element of $objArr (e.g., unset($objArr[0])), then on the js side args.objArr.length becomes 'undefined' :shock: even if there are plenty of elements left in $objArr. This has caused some deal of hunting down this oddity since unset() in php does not reindex the entries after removing one. I am guessing that something is not quite correct in the hand off between php and js for this scenario.

Summary: avoid unset() for arrays generated in the argument function on the php side handed over to javascript. The length property of the array can become undefined in onEnteringState when you don't expect it to.
User avatar
Tisaac
Posts: 2743
Joined: 26 August 2014, 21:28

Re: Curious feature for onEnteringState and length of arrays in args

Post by Tisaac »

My advice : always do an array_values on the backend if you want to make sure the frontend will parse it as an array and not à generic object
User avatar
CuriousTerran
Posts: 21
Joined: 12 July 2020, 21:03

Re: Curious feature for onEnteringState and length of arrays in args

Post by CuriousTerran »

Sounds like good advice. Thank you.
User avatar
joezg
Posts: 70
Joined: 16 June 2011, 17:17

Re: Curious feature for onEnteringState and length of arrays in args

Post by joezg »

If your JS variable has no length property defined, it means it is not an array.
My first thought is that you received that value as an object on JS. And that is indeed the case.

I made a small test with this method on php side:

Code: Select all

    function TestRemove() {
        $arr = [0, 1, 2, 3, 4, 5, 6];

        unset($arr[3]);
        $this->notifyAllPlayers( "test", "", [
            "arr" => $arr
        ]);
    }
and a notification handler on JS side:

Code: Select all

notif_test: function(notif){
	console.log(notif.args);
 },
and indeed I saw an object in js console. If I remove unset statement I receive an array.

Values from php are encoded as json when transfered over HTTP and are decoded back to JS values on the client. JS (and similarly JSON) arrays cannot have missing indexes and are, in that case, treated as objects.

Php object: [0, 1, 2, 3, 4]
is received as array in JS: [0, 1, 2, 3, 4].

If you remove an element from php object, JSON (and JS) don't know how to treat a value other than as object:
{
0: 0,
1: 1,
3: 3,
4: 4
}

You can solve this problem on either side.
On php you can use array_values (as advised by tisaac) which is recommended way, but you can also use Object.values(notif.args.arr) on JS side to get all own properties of an object as array.
Post Reply

Return to “Developers”