Appsurd
Member
Google Play services cloud saving on Android
GM version: GMStudio 2.2.5
Target platform: Android
Download: https://marketplace.yoyogames.com/assets/5485/cloud-saving-example
Links: https://marketplace.yoyogames.com/assets/2008/google-play-services
Latest change: 2020-07-29
Level: Advanced
Summary
In this tutorial we will be exploring the setup of cloud saving on Android devices. You can save any information in your game to the server, and keep the variables updated whenever needed. The complete implementation is actually rather simple, since I made all scripts for you and you only need to add them to your game. Don’t forget to add the Play Services extension from YoYo Games: https://marketplace.yoyogames.com/assets/2008/google-play-services. Additionally read the official guide from YoYo Games first: https://help.yoyogames.com/hc/en-us/articles/360003087452-Android-Google-Cloud-Saving.
Table of contents
Introduction
Chapter 1: Setting up the Google Play Console part 1
Chapter 2: Setting up GameMaker Studio
Chapter 3: Setting up the Google Play Console part 2
Chapter 4: Cloud saving in practice
Conclusion
Error solving: Common issues
Changelog
Introduction
Hey there and welcome to another tutorial from Appsurd. Today I will discuss the topic of cloud saving on Android devices. This feature is really useful when you have a big app and you want to have the player keep his progress after he/she swapped device. Simply inviting users to use the Google Play Games on the device ensures that this method is possible! Please also read the official guide from YoYo Games on the topic: https://help.yoyogames.com/hc/en-us/articles/360003087452-Android-Google-Cloud-Saving. If you want to implement Cloud Saving on iOS, check out our extension on the Marketplace: https://marketplace.yoyogames.com/assets/9111/cloud-saving-for-ios.
We will first be covering the setup in the Google Play Store. For testing out this tutorial you need to have your own Google Play Dev account, so if you don’t have one, you can’t test it I’m afraid. After that, we will head for GameMaker Studio to put in some code and finally, we will finish the job in the Google Play Console. I made a small example which can be downloaded in the Marketplace: https://marketplace.yoyogames.com/assets/5485/cloud-saving-example. In the last chapter, I will be discussing some real-life implementations of how one could use this system in a handy way in your own app.
This tutorial and all its assets are completely free, there is no need for any credit at all to Appsurd. We do appreciate if you rate the script in the Marketplace such that we know what can be improved. Thanks in advance and enjoy the tutorial!
Chapter 1: Setting up the Google Play Console part 1
Since we want to make use of Google’s build-in functionality, we need to enable this for our app. Unfortunately, we cannot test this functionality without actually making a whole project, so we will be going through this process quickly. Naturally we will be skipping parts like adding screens and other game info, but for your final app you definitely want to fill that in. Now let’s start.
Just go to your Google Play Console and login. Then choose in the left column for “Game services”. Now we wish to create a new app. See Figure 1.
Figure 1: The Google Play Console. Select the “Game services” in the left column. Then press “Add new game” as indicated by the orange frame.
Now a screen pops up asking you for the name of the game. I will call him “Tutorial Cloud Saving” but you might as well be giving it the name of your game! Then choose a category of your game, it doesn’t really matter for the tutorial, but again, in case you are planning to use this project for your real app, just choose the correct category. Then press “Continue”, see Figure 2 for more details.
Figure 2: The setup for the Play Services. Fill in the name of your game and below that, choose its category. Then press “Continue”.
After pressing “Continue”, you might need to wait for a couple of seconds or maybe a minute, since Google is setting up the game services. We now wish to go to “Linked apps”. Select it from the menu on the left. In the middle at the top of the page, just below the title of your project, you will see a number. This is your App ID and you need to save this number somewhere, as we will need it to link your game to this project in the Google Play Console. See Figure 3 for the scheme.
Then select “Android” to start linking an Android app. This is shown in Figure 3.
Figure 3. Select the “Linked apps” in the left column. Your App ID is just below your chosen project name, and is indicated where with an orange frame. Choose “Android” as device. All others are not possible, since GameMaker Studio doesn’t support them.
You will now see the following screen, see Figure 4.
Figure 4. Linking an Android app.
Now we need to select a package name for the app. In case you plan to use the services directly in an already existing app, select it from the list by clicking in the box containing the small magnifying glass. But if you have no app yet, or you just want to test this out, we need to create a new app.
This small paragraph is for users which want to create a new app. Open the spoiler to see how to create a new project, just for testing the tutorial.
I think you already know how to do this, but I’ll quickly go through it.
1. Select in the left menu the upper option, which is “Game services” which will redirect you to the main “Game services” screen.
2. Then select “All applications” in the top left menu.
3. Now choose for “Create application” somewhere at the top of the screen.
4. Give as a title the future name of your game, I will choose “Tutorial Cloud Saving”.
5. Then click “Create” and wait for a couple of seconds for your app to be created. We now need to add the APK to the Play Store. We don’t have one yet so we need to create it first.
1. Select in the left menu the upper option, which is “Game services” which will redirect you to the main “Game services” screen.
2. Then select “All applications” in the top left menu.
3. Now choose for “Create application” somewhere at the top of the screen.
4. Give as a title the future name of your game, I will choose “Tutorial Cloud Saving”.
5. Then click “Create” and wait for a couple of seconds for your app to be created. We now need to add the APK to the Play Store. We don’t have one yet so we need to create it first.
Hint: Make sure you have checked the box “Saved games” in the “Game details” tab of your project. In most cases this is done automatically.
For now, we haven’t written a single line of code so we’ll do that first and then return to the Play Store to finish the job.
Chapter 2: Setting up GameMaker Studio
Let’s head over to GameMaker Studio to create an APK. Please note that you can download a sample project from the Marketplace: https://marketplace.yoyogames.com/assets/5485/cloud-saving-example, but I will also explain the code in more detail below.
Let’s create an object called controller and make this object persistent and put in into the very first room of your game. This is very important since the login in Play Games cannot be handled by us, so the exact time of loading is unknown, so the game should always be prepared to catch the response. You therefore need to make sure that the object is always available to catch this response.
Now put the following code into the Create Event:
Code:
/// @description Initialise Google Play Games
// Google Play Games
if achievement_available() achievement_login();
if achievement_login_status() show_message_async("Google Play Games login OK");
// Load Dsmap
scr_dsmap_load();
// Initialise check variables
cloud_check_string = 0;
cloud_check_file = 0;
save_check_string = 0;
save_check_file = 0;
Code:
/// @description scr_dsmap_load()
//
// Script: Loads the user data from a ds_map file
// Date: 2018-08-07
// Copyright: Appsurd
// Define variables
global.topscore = 0;
if (file_exists("dsmap.dat"))
{
var map = ds_map_secure_load("dsmap.dat");
// Load data if it exists
if (ds_map_exists(map, "topscore")) global.topscore = ds_map_find_value(map, "topscore");
ds_map_destroy(map);
}
// Save the data again to prevent loss of data
scr_dsmap_save();
Note that this script uses a new script called scr_dsmap_save() at the last line. As expected, this script saves all data to the .dat file. This script is shown here:
Code:
/// @description scr_dsmap_save()
//
// Script: Saves the user data in a ds_map
// Date: 2018-08-07
// Copyright: Appsurd
var map = ds_map_create();
ds_map_add(map, "topscore", global.topscore);
ds_map_secure_save(map, "dsmap.dat");
ds_map_destroy(map);
Alright, we have set up the initialisation process. But we wish to receive something as well. Simply add the Asynchronous Cloud Event to the controller object and put in the following code.
Code:
/// @description Receive async messages from the cloud saving service
if ds_map_find_value(async_load, "id") == cloud_check_string
{
if ds_map_find_value(async_load, "status") < 0
{
show_message_async("Cloud Services not available.");
}
else
{
if ds_map_find_value(async_load, "status") == 0
{
// Saving a string
var data = ds_map_find_value(async_load, "resultString");
show_message_async("String loaded data: "+string(data));
global.topscore = real(data);
scr_dsmap_save();
}
}
}
Whenever the return is correct, the response will be saved in the variable global.topscore and after that, the file is saved on the device. This completes the code in the controller object.
Now we wish to make two buttons: one for saving the variables from the game to the cloud and one for synchronising the data in the cloud with the game (which is the same as downloading the variables from the cloud into the game). Let’s start with obj_button_synchronise_string. Just create a sprite and create a Left Released Event. Put in the following code.
Code:
/// @description Synchronise with the cloud
with (controller)
{
cloud_check_string = cloud_synchronise();
show_message_async("cloud_check_string = "+string(cloud_check_string));
}
Code:
/// @description Save the data
get = get_string_async("Enter score to save", "");
Code:
/// @description Get the user input and save
if (ds_map_find_value(async_load, "id") == get)
{
if ds_map_find_value(async_load, "status")
{
var data = string(ds_map_find_value(async_load, "result"));
with (controller)
{
save_check_string = cloud_string_save(data, "test data for cloud save");
show_message_async("save_check_string = "+string(save_check_string));
}
}
}
But we need to enable the Google Play Services in our project. Therefore go to the Marketplace and download https://marketplace.yoyogames.com/assets/2008/google-play-services to add it to your project. In case you don’t know how to do this, look up the information on the forums or one of Yoyo Games’s tutorials: https://help.yoyogames.com/hc/en-us .
Now head over to the Android Game Options and click the Android section. Then select in the left menu the “Social” tab. Now check the button “Enable Google Cloud saving” is checked. Below that, enter the App ID which we extracted from the Google Play Console and copy paste it in. See Figure 5.
Figure 5. The Android Game Options in GameMaker Studio, the Android / Fire tab. Click “Social” on the left. Be sure to check the box in the orange frame and enter your App ID as we found in the Google Play Console.
And that’s it for the GameMaker Studio side. Now compile your app for Android and save the APK as we will need it later on. Now let’s continue to finish the job.
Chapter 3: Setting up the Google Play Console part 2
Since we created an APK, we can start uploading it to the Google Play Console. Go back to your Dashboard and select your app, in my case “Tutorial Cloud Saving”. Then select “App releases” from the left menu. We need to upload an APK but users should not be able to see it, so under “Open track” click on “Create open track”. I already created one, but it should be on the spot indicated in Figure 6.
Figure 6. Select “App releases” in the left menu and then choose “CREATE OPEN TRACK”.
Then select “Create release” and upload the APK. There is no need to enter any pictures or descriptions, since the app won’t be published. Now go back to the “All applications” in the top left corner and select the “Game services” again. Now select your project name and select the “Linked apps” again as shown in Figure 3. Then choose “Android” and select the right “Package name”, in my case: com.appsurd.cloudsaving. Now click “Save and continue” at the top of the page.
You are prompted to authorise your app. Simply click “Authorise your app now” and follow the instructions. Don’t forget to copy the Sha-1 code and save it, I’m not completely aware of what it’s used for, but you can save it anyway.
Now your app is ready for testing! Select “Testing” in the menu on the left. Now add your own email address with which you login to the Google Play Games to the testers list. Press “Continue to next step” at the top of the page to continue and save the mail address. The Google Play Console will show you a message that your app is not ready to be published since it contains no images, description, etc. This is no problem, just ignore it.
Now transfer your APK to your phone and install it. Now let’s start testing if the app works.
Step 1. Open the app and login with Google Play Games.
Step 2. Click the save button to send your data to the server.
Step 3. Exit the game.
Step 4. Remove the app.
Step 5. Reinstall the app.
Step 6. Open the app again, and login again.
Step 7. Now press the synchronise button to download the content from the server. You should now receive the data you entered in step 2. If you followed the tutorial correctly, the procedure should work
I would love to provide you with a sample APK to test the functionality, but I would need to add your mail address by hand for every user separately and I’m not keen to publish such a sample app on the Play Store, so I’m afraid you have to follow the tutorial by yourself and implement everything before you can test it. However, I have made a sample project which you can download directly and see the code instead of having to type it yourself. It can be downloaded in the Marketplace: https://marketplace.yoyogames.com/assets/5485/cloud-saving-example.
In the next chapter, I will discuss the practical implementation of the Cloud Saving in your app and how you can handle it.
Chapter 4: Cloud Saving in practice
I want to stress that the content of the first three chapters completely covers the actual working of the cloud saving procedure. But in this last chapter, I want to address several concrete steps to implement this system into your game.
The first issue one could observe is that the standard method saves a string to the database. Although this is fine, this is inconvenient in practise. Mostly, your game is bigger than only one variable, so you would need to concatenate all those variables and separate them by a special character like “@”. Then save the whole string to the server. And when synchronising, you would need to split the complete string again on the special character, e.g. “@” and extract all data again. You could do the splitting by using https://marketplace.yoyogames.com/assets/4069/simple-string_split-script ). I personally find this inconvenient, but there are other methods too.
Normally, you also save all variables locally to a INI file, ds_map file or something like that. So why not use json_encode() to convert your file to a string and send it to the server? And when synchronising, use json_decode() again to get it back?
But there is an even easier option, that is by using cloud_file_save(). You require to edit some of the previous code, so I’ll quickly show it to you. It is shown in the spoiler below. PS: In case you want to spend your time a little more useful, don’t waste it to copy this code but simply head for the Marketplace to download the example belonging to this asset. It contains both methods, so no need to copy anything manually: https://marketplace.yoyogames.com/assets/5485/cloud-saving-example
You can test these scripts in the same way as for strings, see section 3 for the complete procedure.
Change the Asychronous Cloud Event from the controller to
Change the Left Button Released from the obj_button_synchronise_file to
And finally, change the Asynchronous Dialog Event from the obj_button_save_file to
Code:
if ds_map_find_value(async_load, "id") == cloud_check_file
{
if ds_map_find_value(async_load, "status") < 0
{
show_message_async("Cloud Services not available.");
}
else
{
if ds_map_find_value(async_load, "status") == 0
{
// Saving a file
var data = ds_map_find_value(async_load, "resultString");
show_message_async(data);
var file = file_text_open_write("dsmap.dat");
file_text_write_string(file, data);
file_text_close(file);
scr_dsmap_load();
}
}
}
Code:
/// @description Synchronise with the cloud
with (controller)
{
cloud_check_file = cloud_synchronise();
show_message_async("cloud_check_file = "+string(cloud_check_file));
}
Code:
/// @description Get the user input
if (ds_map_find_value(async_load, "id") == get)
{
if ds_map_find_value(async_load, "status")
{
global.topscore = string(ds_map_find_value(async_load, "result"));
scr_dsmap_save();
with (controller)
{
save_check_file = cloud_file_save("dsmap.dat", "Just for testing");
show_message_async("save_check = "+string(save_check_file));
}
}
}
The next issue you run into is the moment when to save and when to synchronise. In my opinion, you should always save whenever something (big) changed (don’t save multiple times per second, but once in ten seconds is fine). But the loading option is different. In my opinion, you have two main options: always loading at launch of the app (and possibly even in between switching to the menu or so) or only on user request.
Loading at launch or more often (Example: Bloons Monkey City, https://play.google.com/store/apps/details?id=com.ninjakiwi.monkeycity )
Loading the data from the cloud at every launch of the app or even more often, has the advantage that you can check whether incompatibilities occur between client (your app) and server (the cloud saving database). You can add a timestamp to see which variables are the same as the server version and client version and which are different. You may also check if a user has cheated if his number of coins has increased by a million in one minute, for example. A clear disadvantage is that you need to develop a system for this checking method, and this will take time and will never be perfect. For example, what to do if the user saved data is different than the data on the cloud? Did the user have no internet connection? Did the user cheat? Did the app crash or maybe even the cloud service? All these questions are far tougher to answer than most of us would want to think about. So there’s another option.
Loading on user request (Example: King of Thieves, https://play.google.com/store/apps/details?id=com.zeptolab.thieves.google )
What if you would only load the data upon user request? Typically, a user would request the data to be loaded if he/she switched device, or rebooted his phone because of (un)known reasons. Programmatically, this is also super easy, just add a button for it in the settings menu and you’re done. Some disadvantages include the not being able to check for cheating, as loading is only done on user request (note that cheating not only includes the adding 1M coins to his account but also includes a user decision which was not smart (for example, your app includes a mystery box and the user bought it 100 times but got nothing. He then decides to quickly load the data to prevent him from losing his money for the boxes)). This last example can possibly be prevented by saving at every change in the game, but calling the cloud saving extension more often than once in ten seconds is not preferable, and I also don’t know in which time interval the string / file on the cloud saving server changed so that, on the next call, you receive the updated version, but I can imagine this not being instantaneously, so you could load older versions on a quick press on the loading button.
The content in this section is open for discussion, so feel free to post your opinion on the matter in the discussing section below!
Conclusion
The tutorial is finished by now, I hope you learned how you can implement cloud saving on Android devices using the Google Play Console and how to implement it in GameMaker Studio. If there are any questions or if you find anything unclear, please post your response in the comments below. Thanks for reading the tutorial and have fun with your cloud saving system!
Frequently Asked Questions
I can't get cloud saving to work
This is a small list of common mistakes in the implementation:
- Make sure you have checked the box “Saved games” in the “Game details” tab of your project in the Google Play Store.
- Fill in the App ID in GameMaker’s Global Game Settings.
- Enable yourself as a testing user to be able to use the Google Play Games in the Google Play Store.
Since there is no official extension, we have implemented an iOS extension, which you can buy from the Marketplace.
Changelog
Changelog, huh? Yes, it’s actually just for me to check when and what I changed in the tutorial. Any people contributing something will be added too.
V1.2.1 (2020-07-29)
- Fix: The return from the Cloud Saving comes into resultString, but the tutorial still used description. The sample project already contained the right code. This was pointed out to me by MagicHero.
V1.2.0 (2020-05-23)
- Updated to GMS2
V1.1.1 (2018-08-10)
- Added extra async message in project
- Small text fixes
V1.1.0 (2017-07-15)
- Included extra information about the possibility to save files and multiple variables at once
- Improved example code downloadable from the Marketplace explaining both saving strings and files
- Added common issues
- Small text fixes
V1.0.0 (2017-05-30)
First English version of the tutorial was written.
Last edited: