SOLVED why does 'is_undefined' NOT prevent undefined variable crashs

jobjorgos

Member
I simply have this code:

GML:
if is_undefined( database[i, oPlayers] ) {
      //stop
}

and still the game crashes saying that is_undefined( database[i, oPlayers] ) is not set before reading it!
I acctually USE is_undefined to PREVENT this error! Why does it not work?
 

kburkhart84

Firehammer Games
What you need to do is simply fix the error. As I understand it, is_undefined simply checks if a variable is equal to "undefined" but in order to do that, the variable must still exist. Solution? Don't use any variables that you didn't define. If you are trying to use this to fix some other issue, maybe fix it a different way. As you are the one defining your own variables, there is no reason you shouldn't be able to code correctly.
 

samspade

Member
I simply have this code:

GML:
if is_undefined( database[i, oPlayers] ) {
      //stop
}

and still the game crashes saying that is_undefined( database[i, oPlayers] ) is not set before reading it!
I acctually USE is_undefined to PREVENT this error! Why does it not work?
There is a difference between a variable holding the value undefined and a variable not being initialized or declared. is_undefined only checks the first and requires the second. If you want the second use variable_instance_exists(instance_id, name); https://manual.yoyogames.com/GameMa...riable_Functions/variable_instance_exists.htm.
 
Last edited:

jobjorgos

Member
variable_instance_exists(instance_id, name);
Sadly also with if variable_instance_exists(instance_id, database[i, oPlayers]) { im getting the same error saying that the variable is not set before reading.

And I have oPlayers simply already defined in the create event of the object:
enum oPlayers { Name = 0, Value = 1, Sorting = 2, Rank = 3, UpdatedAt = 4, UserProfileURL = 5, UserIconURL = 6, Key = 7};

So. Does enum not count as a variable or something? I really don't get it.
And sometimes it gives no error, and sometimes does, kinda weird.
 

samspade

Member
An enum isn't a variable. It's a constant (will always be an integer). So that would be like asking whether or not the number 3 exists.

It sounds like you're trying to check if a position in an array is filled, or perhaps filled with a valid possibility. If the first, then you can just check the size of the array. If the second, then it would probably be easiest to have an uninitialized value to check against (such as -1) so you can say something like if (database[i, oPlayers] != -1) . Otherwise, you could also write your own script that manually compares the value stored to all valid possibilities and returns true if there is a match and false if not.
 

chamaeleon

Member
Why is the code written database[i, oPlayers] instead of database[i, oPlayers.Name], etc.? oPlayers by itselfs means nothing much, it is just a namespace for the actual values you define in it.
 

jobjorgos

Member
if (database[i, oPlayers] != -1)
you could also write your own script that manually compares the value stored to all valid possibilities and returns true if there is a match and false if not.
So I also tried all of this... and even that errors saying database[i, oPlayers] is not set yet before reading.

Well I must say, acctually my code sometimes acctually work without errors, and sometimes it just does not! it's complete randomly, something that is really strange in the world of 0's and 1's...

I have a script that simply just counts the number of players that are online, and this updates every 120 steps (4 seconds) in alarm[0].

And every time while running the game, I get after a random number of updates the error that database[i, oPlayers] is unset.
Sometimes the first time, sometimes after 5 updates and sometimes after 50+ updates, so it's complete random.


Why is the code written database[i, oPlayers] instead of database[i, oPlayers.Name], etc.? oPlayers by itselfs means nothing much, it is just a namespace for the actual values you define in it.
That is true! I acctually only showed database[i, oPlayers] here on the forum because I did show only a small cutted part from the complete script.


So for better understanding I think it's better If I just show the script in its whole:


Create Event:
GML:
// initialize enums for the rank and database array (  Name = Playername (a string),   Value = last_online_time (an unixtime integer)  )
enum oPlayers { Name = 0, Value = 1, Sorting = 2, Rank = 3, UpdatedAt = 4, UserProfileURL = 5, UserIconURL = 6, Key = 7};

database = 0; // a two dimensional array for the player database (name, last_online_time)
databaseSize = 0; // nr of players in the database array
online_players = 0;
alarm[0] = 1;

Alarm[0] Event:
GML:
unix_timestamp(); //to get current_unix_time

//this loop go through all players of the database to count how many have shown activity in less than 100 seconds to set online_players
if databaseSize > 0{
    online_players = 0;
    elems = databaseSize;
    for (i = 0; i < elems; i++) {
    var name, last_online_time, last_activity;
        name = database[i, oPlayers.Name];
        last_online_time = database[i, oPlayers.Value];
        last_activity = current_unix_time - last_online_time;
        if last_activity < 100{
            online_players +=1;
        }
    }
}

alarm[0]=120; //to keep online_players up to date

Draw GUI Event:
GML:
draw_text(509,5,string(online_players)+" players online in the game now");

HTTP Event:

GML:
//send to database
if (request == 1) {
    if (getResultStatus()) {
        // request successful.
        // retrieve player database
        valueslist = ds_map_find_value(ResponseMap, "data");
        // this is the list with all players
        // store it in the database array
        database = 0;
        entries = ds_list_size(valueslist);
        databaseSize = entries;
        for (i = 0; i < entries; i++) {
            var map = ds_list_find_value(valueslist, i);
            database[i, oPlayers.Name] = ds_map_find_value(map, "name");
            database[i, oPlayers.Rank] = ds_map_find_value(map, "rank");
            database[i, oPlayers.Value] = ds_map_find_value(map, "value");
            database[i, oPlayers.UserProfileURL] = ds_map_find_value(map, "user_profile");
            database[i, oPlayers.UserIconURL] = ds_map_find_value(map, "user_icon");
        }
    }
    request = -1;
}
 
Last edited:

FrostyCat

Member
Did you actually mean RankResult.Name and RankResult.Value for these two lines?
GML:
        name = database[i, oPlayers.Name];
        last_online_time = database[i, oPlayers.Value];
 

jobjorgos

Member
Did you actually mean RankResult.Name and RankResult.Value for these two lines?
GML:
        name = database[i, oPlayers.Name];
        last_online_time = database[i, oPlayers.Value];
Ah I acctually had some typos while copy/pasting my code to the forum. It should be enum oPlayers and not enum RankResult.
I corrected all typos in the code now
 

FrostyCat

Member
Given your signature, I'm assuming GMS 1.4 code here. In that case, if you want to check if database[i, oPlayers.Name] is accessible, it's actually a series of 4 checks:
  1. database exists as an instance variable in the current instance (which is id, NOT instance_id)
  2. database has the array type
  3. database has a height greater than i
  4. database has a width greater than oPlayers.Name
GML:
if (variable_instance_exists(id, "database") && is_array(database) && array_height_2d(database) > i && array_length_2d(database, i) > oPlayers.Name) {
  /* database[i, oPlayers.Name] is accessible */
}
 

chamaeleon

Member
True. I just added that code in the HTTP event now.
Maybe you could use show_debug_message(json_encode(async_load)) or use breakpoints just before you pull something out of the data structure to verify whether the content you expect is actually present in the map, in the location where you attempt to extract it?
 

jobjorgos

Member
Given your signature, I'm assuming GMS 1.4 code here.
correct

it's actually a series of 4 checks:
  1. database exists as an instance variable in the current instance (which is id, NOT instance_id)
  2. database has the array type
  3. database has a height greater than i
  4. database has a width greater than oPlayers.Name
GML:
if (variable_instance_exists(id, "database") && is_array(database) && array_height_2d(database) > i && array_length_2d(database, i) > oPlayers.Name) {
/* database[i, oPlayers.Name] is accessible */
}
It... just... works! This code you provided with the 4 checks finaly removed any errors and the code can just keep running/updating online_players without any problems now!

Thanks alot for the help since I would not get to this on my self probly. I implended your code on this way now:


Alarm[0] Event:
GML:
unix_timestamp(); //to get current_unix_time

//this loop go through all players of the database to count how many have shown activity in less than 100 seconds to set online_players
if databaseSize > 0{
    online_players = 0;
    elems = databaseSize;
    for (i = 0; i < elems; i++) {
        var name, last_online_time, last_activity;
        stop=0;
        if (variable_instance_exists(id, "database") && is_array(database) &&
        array_height_2d(database) > i && array_length_2d(database, i) > oPlayers.Name) {
            name = database[i, oPlayers.Name];
        }else{ stop=1;}
        if (variable_instance_exists(id, "database") && is_array(database) &&
        array_height_2d(database) > i && array_length_2d(database, i) > oPlayers.Value) {
            last_online_time = database[i, oPlayers.Value];
        }else{ stop=1;}
        if stop==0{
            last_activity = current_unix_time - last_online_time;
            if last_activity < 100{
                online_players +=1;
            }
        }
    }
}

alarm[0]=120; //to keep online_players up to date
 
Last edited:
Top