GameMaker JSON Load File Issue

king javo

Member
I'm trying to load a json file using the below code and I don't understand where to place the file while running the game in GMS2's IDE. The working_directory variable seems to be looking in the \AppData\Local\GameMakerStudio2\GMS2TEMP but every time I run the project it creates a new folder inside of here and this is where it's looking.

Am I missing something? Also, when trying to use json_decode(string) using a valid json text block, the GMS2 throws an error not liking the string. Anyone have a clue why this works in GMS1.4 and not GMS2?

Code:
show_message(working_directory);
if(file_exists(working_directory + "\teams.json")) {
    show_message("Found save file!");
  
    var jsonFile = file_text_read_string(working_directory + "\teams.json");
    return json_decode(jsonFile);
    }
    else
    {
  
    show_message("Found no save file!");
    }
Example json below...
Code:
///get_class_data()
// This may end up in an external file, for now it is here
return json_decode('
{
    "teams": {
        "id": 0
   }
}');
 
Last edited:

FrostyCat

Redemption Seeker
That reading code shouldn't have worked in GMS 1.4 to start with, you gave file_text_read_string() the wrong argument.
Code:
var f = file_text_open_read(working_directory + "teams.json"),
    jsonStr = "";
while (!file_text_eof(f)) {
  jsonStr += file_text_read_string(f);
  file_text_readln(f);
}
file_text_close(f);
return json_decode(jsonStr);
Maybe you should have checked out the Manual's example for it before taking it for a spin?
 

king javo

Member
That reading code shouldn't have worked in GMS 1.4 to start with, you gave file_text_read_string() the wrong argument.
Code:
var f = file_text_open_read(working_directory + "teams.json"),
    jsonStr = "";
while (!file_text_eof(f)) {
  jsonStr += file_text_read_string(f);
  file_text_readln(f);
}
file_text_close(f);
return json_decode(jsonStr);
Maybe you should have checked out the Manual's example for it before taking it for a spin?
Sorry, guess I should have been more clear... the second code snippet is what works in GMS1.4, but it's simply a script and not an actual external file.

The fist code snippet is me just trying to get the if block to find my file in that directory and it fails. The part you mentioned is something I could use next, so thanks! :)
 

king javo

Member
Figured out my problem with the file not existing... you need to include it in the "Included Files" folder inside your project and just do if(file_exists("teams.json"))

Still not sure as to why I can't use json_decode(string) in a script like I did in GMS1.4 though.
 

king javo

Member
Would someone out there happen to know how to load data using JSON would you? I'm using a parent/child structure with teams > players > bio, stats, abilities. I'm not sure if JSON is the easiest way to bring this data in or some other type of file structure and I can't seem to find any tutorials on this type of JSON structure with 1 to many.
 

FrostyCat

Redemption Seeker
Still not sure as to why I can't use json_decode(string) in a script like I did in GMS1.4 though.
That's because the syntax in GMS 2 no longer allows strings to be delimited with single quotes. To use the legacy string syntax, you need to put @ before the starting quote (single or double).

Would someone out there happen to know how to load data using JSON would you? I'm using a parent/child structure with teams > players > bio, stats, abilities. I'm not sure if JSON is the easiest way to bring this data in or some other type of file structure and I can't seem to find any tutorials on this type of JSON structure with 1 to many.
JSON excels at nested structures, it's the primary reason why I advocate it over INI.

One-to-many relationships in JSON are typically expressed as JSON arrays (lists) or JSON objects (maps). Which one you choose depends on what the main point of the relationship is.
  • If the relationship makes sense as an ordered sequence of things or if there is no obvious labelling scheme, use a JSON array to gather the things.
  • If the relationship is a group of individually labelled things, use a JSON object to gather the things, with the labels as keys and the things as values.
Here is a video that describes general best practices in JSON data modelling. It's made for a specific third-party program, but the ideas within can be taken anywhere JSON is used.
 

king javo

Member
That's because the syntax in GMS 2 no longer allows strings to be delimited with single quotes. To use the legacy string syntax, you need to put @ before the starting quote (single or double).


JSON excels at nested structures, it's the primary reason why I advocate it over INI.

One-to-many relationships in JSON are typically expressed as JSON arrays (lists) or JSON objects (maps). Which one you choose depends on what the main point of the relationship is.
  • If the relationship makes sense as an ordered sequence of things or if there is no obvious labelling scheme, use a JSON array to gather the things.
  • If the relationship is a group of individually labelled things, use a JSON object to gather the things, with the labels as keys and the things as values.
Here is a video that describes general best practices in JSON data modelling. It's made for a specific third-party program, but the ideas within can be taken anywhere JSON is used.
Thanks for the help.

I've figured out how to load JSON data into a ds_grid, but I have one last question... how would I load the following child "class" from JSON?

JSON example
Code:
[
  {
    "id": 0,
    "city": "Buffalo",
    "name": "Beasts",
    "offplaystyle": "run",
    "defplaystyle": "4-3",
    "jersey": "sprRed",
   "player": [
      {
        "fname": "Tyrod",
        "lname": "Jones",
        "nickname": "Beast",
        "college": "FSU",
        "number": 7
      }
    ]
  }
]
Code to load data I'm trying... looping like I was able to do the default parent, but this doesn't work
Code:
var theJsonMap = get_team_data();

theList = ds_map_find_value(theJsonMap, "default");
totalTeams = ds_list_size(theList);
teamData = ds_grid_create(totalTeams,8);
for (var i = 0; i < totalTeams; i++)
{
    var theEntry = ds_list_find_value(theList, i);
    teamData[# i, 0] = theEntry[? "id"];
    teamData[# i, 1] = theEntry[? "city"];
    teamData[# i, 2] = theEntry[? "name"];
    teamData[# i, 3] = theEntry[? "offplaystyle"];
    teamData[# i, 4] = theEntry[? "defplaystyle"];
    teamData[# i, 5] = theEntry[? "jersey"];
    teamData[# i, 6] = theEntry[? "player"];
        theListp = ds_map_find_value(theJsonMap, "player");
        totalTeamsp = ds_list_size(theListp);
        for (var j = 0; j < totalTeamsp; j++)
        {
            var theEntry = ds_list_find_value(theListp, j);
            teamData[# j, 0] = theEntry[? "fname"];
            teamData[# j, 1] = theEntry[? "lname"];
            teamData[# j, 2] = theEntry[? "nickname"];
            teamData[# j, 3] = theEntry[? "college"];
            teamData[# j, 4] = theEntry[? "number"];
        }
}
 

chamaeleon

Member
Code:
var theJsonMap = get_team_data();

theList = ds_map_find_value(theJsonMap, "default");
totalTeams = ds_list_size(theList);
teamData = ds_grid_create(totalTeams,8);
for (var i = 0; i < totalTeams; i++)
{
    var theEntry = ds_list_find_value(theList, i);
    teamData[# i, 0] = theEntry[? "id"];
    teamData[# i, 1] = theEntry[? "city"];
    teamData[# i, 2] = theEntry[? "name"];
    teamData[# i, 3] = theEntry[? "offplaystyle"];
    teamData[# i, 4] = theEntry[? "defplaystyle"];
    teamData[# i, 5] = theEntry[? "jersey"];
    teamData[# i, 6] = theEntry[? "player"];
        theListp = ds_map_find_value(theJsonMap, "player");
        totalTeamsp = ds_list_size(theListp);
        for (var j = 0; j < totalTeamsp; j++)
        {
            var theEntry = ds_list_find_value(theListp, j);
            teamData[# j, 0] = theEntry[? "fname"];
            teamData[# j, 1] = theEntry[? "lname"];
            teamData[# j, 2] = theEntry[? "nickname"];
            teamData[# j, 3] = theEntry[? "college"];
            teamData[# j, 4] = theEntry[? "number"];
        }
}
Doesn't your inner for loop over j overwrite things written for i to some extent, as both start at 0 and you use both variables as indices into the same grid?
 

king javo

Member
Doesn't your inner for loop over j overwrite things written for i to some extent, as both start at 0 and you use both variables as indices into the same grid?
The inner j loop is wrong... I just took a quick stab at it. There has to be some documentation or tutorial which explains how to traverse through child class element inside JSON. I need that! :)
 

chamaeleon

Member
The inner j loop is wrong... I just took a quick stab at it. There has to be some documentation or tutorial which explains how to traverse through child class element inside JSON. I need that! :)
Looks to me like you're successfully traversing the JSON structure but not handling the data properly after you pull it out, or to put it differently, you need to figure out what kind of data representation makes sense in GMS data structures after parsing the JSON. You seem interested in using a grid right now, so maybe teamData[#i, 7] could contain a ds_list of players (represented as individual ds_maps per player) or a single ds_grid with properties similar to how you tried to put it in teamData, copied from the JSON ds_list of players. Don't store the ds_list that is in the JSON data structure, as cleaning up the JSON parsing would delete it, causing problems later on trying to use it).

(Some minor edits to the text above)
 
Last edited:

FrostyCat

Redemption Seeker
The inner j loop is wrong... I just took a quick stab at it. There has to be some documentation or tutorial which explains how to traverse through child class element inside JSON. I need that! :)
Here is a post I wrote some time ago for the thought process of how to traverse nested JSON structures.

There's a reason why computer science students study tree traversal algorithms within the first one or two semesters. Anyone who understands tree traversal would have come up with the exact same thought process themselves.
 

chamaeleon

Member
One bug in the code I saw after actually trying the code is that you were using theJsonMap as argument for finding the player list instead of theEntry. Below is the code I tried that parses the JSON, and after creating the grids, displays the College of the first player in the first team.
Code:
var theJsonMap = json_decode(json_str);

theList = ds_map_find_value(theJsonMap, "default");
totalTeams = ds_list_size(theList);
teamData = ds_grid_create(totalTeams,8);
for (var i = 0; i < totalTeams; i++)
{
    var theEntry = ds_list_find_value(theList, i);
    teamData[# i, 0] = theEntry[? "id"];
    teamData[# i, 1] = theEntry[? "city"];
    teamData[# i, 2] = theEntry[? "name"];
    teamData[# i, 3] = theEntry[? "offplaystyle"];
    teamData[# i, 4] = theEntry[? "defplaystyle"];
    teamData[# i, 5] = theEntry[? "jersey"];
    var theListp = ds_map_find_value(theEntry, "player");
    var totalTeamsp = ds_list_size(theListp);
    var players = ds_grid_create(totalTeamsp, 5);
    teamData[# i, 6] = players;
    for (var j = 0; j < totalTeamsp; j++)
    {
        var theEntryp = ds_list_find_value(theListp, j);
        players[# j, 0] = theEntryp[? "fname"];
        players[# j, 1] = theEntryp[? "lname"];
        players[# j, 2] = theEntryp[? "nickname"];
        players[# j, 3] = theEntryp[? "college"];
        players[# j, 4] = theEntryp[? "number"];
    }
}

var p = teamData[#0, 6];
show_debug_message(p[# 0, 3]);
 

king javo

Member
One bug in the code I saw after actually trying the code is that you were using theJsonMap as argument for finding the player list instead of theEntry. Below is the code I tried that parses the JSON, and after creating the grids, displays the College of the first player in the first team.
Code:
var theJsonMap = json_decode(json_str);

theList = ds_map_find_value(theJsonMap, "default");
totalTeams = ds_list_size(theList);
teamData = ds_grid_create(totalTeams,8);
for (var i = 0; i < totalTeams; i++)
{
    var theEntry = ds_list_find_value(theList, i);
    teamData[# i, 0] = theEntry[? "id"];
    teamData[# i, 1] = theEntry[? "city"];
    teamData[# i, 2] = theEntry[? "name"];
    teamData[# i, 3] = theEntry[? "offplaystyle"];
    teamData[# i, 4] = theEntry[? "defplaystyle"];
    teamData[# i, 5] = theEntry[? "jersey"];
    var theListp = ds_map_find_value(theEntry, "player");
    var totalTeamsp = ds_list_size(theListp);
    var players = ds_grid_create(totalTeamsp, 5);
    teamData[# i, 6] = players;
    for (var j = 0; j < totalTeamsp; j++)
    {
        var theEntryp = ds_list_find_value(theListp, j);
        players[# j, 0] = theEntryp[? "fname"];
        players[# j, 1] = theEntryp[? "lname"];
        players[# j, 2] = theEntryp[? "nickname"];
        players[# j, 3] = theEntryp[? "college"];
        players[# j, 4] = theEntryp[? "number"];
    }
}

var p = teamData[#0, 6];
show_debug_message(p[# 0, 3]);
This really helped to see what I was doing wrong! Thanks.

One last question, can you tell me which data structure works best for my data example? I actually tried setting teamData to a ds_list, but for some reason it wasn't working. I can post the code if needed. I'm thinking a grid is overkill here. I believe I simple need 2D arrays here.
 

chamaeleon

Member
This really helped to see what I was doing wrong! Thanks.

One last question, can you tell me which data structure works best for my data example? I actually tried setting teamData to a ds_list, but for some reason it wasn't working. I can post the code if needed. I'm thinking a grid is overkill here. I believe I simple need 2D arrays here.
Not sure there is a best data structure. Depends on how you end up using it. As for using a ds_list instead of a grid for the teams it would imply you store something like a ds_map inside the list as you need several values for each team, which you currently get from the grid (albeit with a fixed number of properties). On the other hand, having a map as a ds_list member means you can easily get its id and pass it around in scripts rather than passing along index numbers into the grid. Lots simply depend on your expected use cases and what you would consider readable and maintainable for you. Using enums for the property index instead of numbers would go a long way making the grid use more readable of course.
 
Top