GameMaker: Fixing the JSON functions (2024)

Table of Contents
Solution Related posts:

This post about the issues with GameMaker's built-in JSON functions and an extension I made to address the issues.

Functions to deal with JSON were originally introduced in GameMaker somewhere around 2011 (when the current product was GameMaker HTML5).

Two main functions are pretty simple:

And these would have been perfectly fine, but:

  • GameMaker (currently) stores references to data structures as numeric IDs.
  • GameMaker (still) lacks functions to determine whether a ds_map\ds_list item is marked as a map\list (this information is available internally).

What does that mean for you? Well - you can't validate the parsed JSON. Consider the following:

var q = json_decode('{ "a": [], "b": {}, "c": 1, "d": true }');show_debug_message(q[?"a"]);show_debug_message(q[?"b"]);show_debug_message(q[?"c"]);show_debug_message(q[?"d"]);

The output of that is 0, 1, 1, 1.

So, if you were expecting a JSON object but got a numeric value (be that due to format changes, external errors, or an intentional malformed submission by a user), the game may crash (or do something unusual) unless you had inserted safeguards and checks at literally every corner.

Another shown problem is boolean values - APIs may occasionally require you to pass them an actual true / false as a parameter, but GameMaker's boolean type is numeric, so you end up with 1 / 0 and variously weird workarounds.

Solution

As of writing this post, "data structures as true datatype" item is on GameMaker Studio 2 roadmap and will likely make it into the software in near or semi-near future.

However, future is future, but things might need to be made right now, so I have developed an extension to tackle the problemin a timely matter.

The extension consists of a custom JSON decoder and encoder, and approaches the problems in a slightly more appropriate way:

  • JSON arrays are mapped to GML arrays rather than ds_lists.
  • JSON objects are mapped to array-based structures.
    (on JS-based platforms, stored as actual JS objects for performance)
  • JSON boolean values are mapped to special reference values.
    (on JS-based platforms, stored as actual JS true/false values)

The result is convenient:

  • Since all values are either constant or reference-based, you no longer need to explicitly destroy the values produced by decode-function. No need to worry about memory leaks.
  • Encode/decode functions are more straightforward - if you do tj_decode("[1, 2, 3]"), you get an actual array instead of a map with a ds_list in the "default" field. Similarly, you can call tj_encode on an array, you get a JSON array string "[...]" (which is something that you cannot do with json_encode at all).
  • You can check what any given value is - tj_is_array to check if something is an array, tj_is_object to check if something is a JSON object, and so on.
    This means that you can reliably check if the data is correct, and dynamically iterate over the contents (see web demo on itch.io).

Example of use follows:

var i, q;// To decode a value, pass it to tj_decode, much like with json_decodeq = tj_decode('[1, 2, 3]');// JSON arrays are decoded into regular GML arrays:show_debug_message("An array: " + string(q));// JSON objects are decoded into special array-based structures on native platforms,// and into actual JS Objects on JS-based platforms. This means that you don't have// destroy them after use - that is done automatically.q = tj_decode('{ "a": 1, "b": 2 }');// tj_get returns a field of a TJSON object, much like ds_map_find_value.show_debug_message("q.a = " + string(tj_get(q, "a")));// tj_set changes a field of a TJSON object.tj_set(q, "a", 3);// tj_size returns the number of fields that an object has.show_debug_message("q' size: " + string(tj_size(q)));// tj_keys returns an array containing fields of an object.var keys = tj_keys(q);show_debug_message("q' keys: " + string(keys));// If you need to pick over all fields-values, you can use tj_keys+tj_get:for (i = 0; i < array_length_1d(keys); i++) { show_debug_message("q." + string(keys[i]) + " = " + string(tj_get(q, keys[i])));}// To encode a value, pass it to tj_encode. This works for all supported types:show_debug_message("q encoded: " + tj_encode(q));// If you provide a second parameter, the result will be multi-line and indented:show_debug_message("q indented: " + tj_encode(q, " "));// To construct arrays/objects, you can use tj_array/tj_object:q = tj_object( "number", 4, "array", tj_array(1, 2, 3),);show_debug_message("custom object: " + tj_encode(q, " "));// JavaScript true/false false are converted into tj_true\tj_false// to be able to tell them apart. tj_bool\tj_is_bool are also available.q = tj_decode("true");show_debug_message("js true == tj_true: " + string(q == tj_true));show_debug_message("tj_false encoded: " + tj_encode(tj_false));//show_message("All is well! Check the compile form / output log.");

Output being as following:

An array: { { 1,2,3 }, }q.a = 1q' size: 2q' keys: { { a,b }, }q.a = 3q.b = 2q encoded: {"a":3,"b":2}q indented: { "a": 3, "b": 2}custom object: { "number": 4, "array": [ 1, 2, 3 ]}js true == tj_true: 1tj_false encoded: false

As can be seen, is pretty straightforward to use.

The extension can be downloaded from Marketplace or itch.io.
In-depth documentation is included, and also available online.

Have fun!

Related posts:

  • GameMaker: Beautifying/pretty-printing JSON
  • GameMaker: Minifying JSON
  • GameMaker: filtering strings
  • Variable references in GameMaker (2023 edition)
  • Fixing buffer_set_surface in GameMaker: Studio
GameMaker: Fixing the JSON functions (2024)
Top Articles
Latest Posts
Article information

Author: Manual Maggio

Last Updated:

Views: 5617

Rating: 4.9 / 5 (69 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Manual Maggio

Birthday: 1998-01-20

Address: 359 Kelvin Stream, Lake Eldonview, MT 33517-1242

Phone: +577037762465

Job: Product Hospitality Supervisor

Hobby: Gardening, Web surfing, Video gaming, Amateur radio, Flag Football, Reading, Table tennis

Introduction: My name is Manual Maggio, I am a thankful, tender, adventurous, delightful, fantastic, proud, graceful person who loves writing and wants to share my knowledge and understanding with you.