When using ini_open()/ini_close() and some other file-writing functions, such as ds_map_secure_save(), etc... in your UWP projects, you will see your game freeze as the file is loaded/saved and processed by the XBox One console in a synchronous manner. This is something that is not permitted when submitting games to that target, and to resolve the issue you need to change the way you save and load files.
The change you will be required to use buffers to read/write the files, using the specialised functions explained below in the article to save and load the files asynchronously. Doing this will mean your saving and loading uses the system the XBox One console requires for maximum performance and compatibility.
How do I save data now?
Data that is to be saved should be "wrapped" in the asynchronous buffer functions, as shown in the example below:
buffer_async_group_option("showdialog",0); // Stop platform dialogues appearing for this auto-save (if you do this your player won't be able to select a slot manually)
buffer_async_group_option("slottitle","SaveForMyGame"); // Set the title of the slot we're going to save into
buffer_async_group_option("subtitle","Save file for my awesome game"); // Set a subtitle that's visible in the XBox UI
global.savebuff = buffer_create(1,buffer_grow,1);
All your usual ini_write_real() or ini_write_string() stuff, as you have it just now.
var inistring = ini_close();
buffer_save_async(global.savebuff,"my_save_file.sav",0,buffer_get_size(global.savebuff)); // Pass the data to be saved
global.saveid = buffer_async_group_end(); // Start the save process and return the save request ID
When is my save finished?
When the save is finished, you'll receive an Asynchronous event of type “Save / Load”. and the async_load map will have a key “id” set to global.saveid (or whatever the variable is that you use to track the save request ID).
How do I know if an error occurred?
async_load has a key “status” set to any error code. Negative numbers indicate an error occurred.
How do I load data back in?
The following is an example of how you would now load code, again, wrapped in the asynchronous buffer functions:
global.loadbuff = buffer_create(1,buffer_grow,1);
buffer_async_group_begin("my_save_folder"); // save folder
buffer_async_group_option("slottitle","SaveForMyGame"); // don't show any dialogues, load from slot 0
buffer_load_async(global.loadbuff,"my_save_file.sav",0,-1); // Say what we want to load and into which buffer
global.loadid = buffer_async_group_end(); // Actually start loading now, and return a request ID value
Where is that data I loaded?
Again, you'll get an Asynchronous event of type Save / Load. the async_load DS map will have a key “id” set to global.loadid (or whatever you used) when the load is done, and then you can get the data from the global.loadbuff.
Here's a further example of how this can be done in the Async Load event, which includes checks for saving too:
var ident = async_load[? "id" ];
var status = async_load[? "status"];
var error = async_load[? "error"];
if (ident == global.saveid)
show_debug_message("saved data status " + string(status) + " error " + string(error));
else if (ident == global.loadid)
var buffstring = buffer_read(global.loadbuff,buffer_string);
All your usual ini_read_real() or ini_read_string() stuff, as you have it just now.
show_debug_message("read string from buffer " + buffstring);
As a final note for loading, if you pass in a filename that begins with working_directory it will skip checking in the save directory for the file and load it directly from the datafiles (the included files in your game). This means that you don't have to mount the save directory and should make it a lot faster. Note that you have to know that you are definitely loading a datafile not a saved file, though.
What should I watch out for?
- Don't start saving when you're still waiting for an Async Load event.
- Don't start loading when you're still waiting for an Async Save event.