GMCloud and GameMaker Part 5: Cloud Save and Cloud Load

The meat of the GMCloud service: Cloud saving and loading. Assuming you’ve completed and understood Part 1, Part 2 and Part 3, you’re now able to make cloud saves and cloud loads to save and load game data to/from the player’s account.

This tutorial assumes you’ve already grabbed the linkId and linkSecret, as described in Part 4. The structure of making the request and dealing with the results are identical to that in previous parts, and so will be omitted going forward. The only changes are in the arguments used to make the request, and the returned data.

Cloud save and loads are able to save and load a string to the user profile. Because the data is a string, you have a variety of choice of encodings, perhaps the most common choice would be a json, making use of the json_encode() and json_decode() functions to convert to and from ds_maps. But just like the Game Config, multiple formats are possible, for example:

  • json: you can store ds_maps using json_encode(), and later decode using json_decode()
  • ini: you could transfer your saved ini file on disk to the cloud save
  • buffer: you could store a base64-encoded buffer, and have gamemaker use buffer_base64_encode() and buffer_base64_decode()
  • ds_grid or other datastructures: gamemaker’s ds_grid_write()and ds_grid_read() functions, and their equivalents for other datastructures, can be used.
  • any other string-serialized data: as long as it’s a string, and you have the appropriate deserializers, any data is possible

Size limit overall is approximately 1MB.

Cloud Save

Cloud saves require the user’s linkId and linkSecret as arguments, as well as the save string as described above. If you followed the previous parts, you’ll see that in our example we are currently storing the user’s linkId and Secret in a ds_map that was recently created, though in your code, you can use whichever method you like to store and pass that data on as arguments.

uuid = gmcloud_cloud_save(data[? "linkId"], data[? "linkSecret"], save_string);

The result of this request has no data, but will nevertheless generate an empty result to signify a successful save. It is still desirable to pop the result to avoid a memory leak. A failure would generate an error result, which can be checked for:

if (gmcloud_result_exists(uuid)) {
gmcloud_result_pop(uuid);
// the save was successful
}
else if (gmcloud_error_exists(uuid)) {
var error = gmcloud_error_pop(uuid));
// here was an error
}

Cloud Load

Cloud load just require the user’s linkId and linkSecret as arguments

uuid = gmcloud_cloud_load(data[? "linkId"], data[? "linkSecret"]);

The result will contain the data previously saved. As usual, It is desirable to check for errors.

if (gmcloud_result_exists(uuid)) {
var load = gmcloud_result_pop(uuid);
// the load was successful
}
else if (gmcloud_error_exists(uuid)) {
var error = gmcloud_error_pop(uuid));
// here was an error
}

At this point, you would want to parse load using the appropriate functions, such as json_decode(), buffer_base64_read(), ds_grid_read() etc.

That’s it! You can now save and load to and from the cloud, allowing your players peace of mind that their local copy won’t be corrupted, and able to sync their data across different devices. Take a look at the demos in the marketplace asset for more examples.

Onto Part 6 for High Scores!

Tips for cloud saving

Here are some general tips for cloud saves

Save a format version

As you develop your game, you’ll need to from time to time update or change your save format, whether that’s adding new fields, or changing them around. Players may end up with save data that’s out of date, and could cause unexpected behaviour like crashes, glitches, or other game-breaking and gameplay-breaking issues.

To avoid this, saving a save format value in your save data will help you detect when a save is out of date. You can then decide to run a save file updating script to bring the player’s data up to latest version, or decide to force a wipe of the data. Unfortunate as that may be, it might be slightly better an outcome than a broken game.

Multiple saves

It is possible to have multiple saves for the same user. Although each user gets one save slot to use with your game, you can simply use the same slot to save different distinct game saves by putting them together into the same json/ds_map for example.

Syncing between devices

One of cloud saving strengths is being able to sync game progress between different devices. However, beware! if a player has a game open on one device, and makes a save on the other device, the still-open game may overwrite the other save.

One possible way around this is to make a cloud load of the data, and check that it’s the same data that a game session started with, before saving. Giving the player an opportunity to decide whether to overwrite or not.

Storing the timestamp of the save, and showing the player the save’s time and other stats may help the player make the best decision.

Storing thumbnails

Small thumbnails can be embedded in saves by base64-encoding an image, and using Gamemaker’s buffer functions to decode and save this as an image (or cast straight onto a surface). However, beware of file sizes

Compressing data

Save files can get quite large, fortunately string data tends to be easily compressed. It is possible to save your string to a GM buffer, and then run a buffer_compress() to compress it, and send the buffer as base64. The base64-encoding will be larger by a factor of 4/3, but hopefully the compression more than compensates for that.

Onto Part 6

🤖 Build robots, code in python. Former Electrical Engineer 👨‍💻 Programmer, Chief Technology Officer 🏆 Forbes 30 Under 30 in Enterprise Technology