Sign In Register

How can we help you today?

Start a new topic

Storing, Updating and downloading save file

Hey, I've got a few questions about uploading files that I'm hoping you can help me with.


First off, we are moving over to GS from Parse, so we already have a system set up that I would prefer to not deviate from too much if possible, even though I know the approach I'm trying to take isn't necessarily the GS way. Since the game needs to be playable offline, we already have a local save file, so we just uploaded this to Parse which also allowed us to be able to share the save file with other players (download their save file, but can not change it).


We are hoping to do the same thing with GS. I've seen a couple of possible approaches, so wondering which is the best. These are the approaches I'm aware of:

I'm not sure what the best approach is, but the functionality I'd be hoping for is:
  • Ability to share with other players (not necessarily friends)
  • Ability to update/overwrite file. Or at the very least delete old files when new save file is uploaded
  • The save file will be uploaded all in one go, so don't need the ability to do partial updates/downloads.

Sorry about the long post! Thanks!


Hi David, and welcome to GameSparks. 


Seeing as you wish to update/overwrite this data, my recommendation would be to use a Custom Runtime Collection which will allow you to carry out comprehensive queries and operations should you ever need to, along with the ability to easily overwrite data. 


As each doc/record can only be 14mb, utilizing a Runtime collection will allow you to fully utilize that memory along with the ability to query it, and potentially use it for analytics purposes. 


Thank you for a clear post with great usage case examples. I hope this answers your question.

Best Regards, Patrick. 

Hi Patrick, thanks for your quick reply! I'm still learning the ropes of GS, so just wondering is it possible to upload a text file to a runtime collection?


I understand you can send json as an event attribute, and while our save files are json, they are encrypted so it wouldn't be valid json (I can send a decrypted version if needs must). Would sending it as a string attribute cause any issues, such as string being too long?


Thanks for your help!

Hi David,

This data would have to be sent as valid JSON. If it is encrypted then I would highly recommend you don't store it in a Runtime collection as this may cause serious performance issues. 


If you are going to be sending us large JSON documents or encoded data, I'd recommend sending it to us as an uplaodable, especially if you don't need to process it server-side. 


Does this make sense?  Happy to assist further.

Best Regards, Patrick. 


Hi Patrick,


Yeah, we don't need to do any processing server side, we just need to be able to add/update the data and link them to a player (and download it of course). The data itself will most likely be under 500KB, but may go over in some extreme cases. I guess that wouldn't be considered large data.


So when you say uploadable, do you mean upload the data via GetUploadRequest?


Sorry for taking up your time on this!

Hi Patrick,


Yeah, we don't need to do any processing server side, we just need to be able to add/update the data and link them to a player (and download it of course). The data itself will most likely be under 500KB, but may go over in some extreme cases. I guess that wouldn't be considered large data.


So when you say uploadable, do you mean upload the data via GetUploadRequest?


Sorry for taking up your time on this!

Alright, so I've been looking into this more. Trying to send the data to a runtime collection is not working as the data is too big it seems, the request just times out. I've tried sending the data as a string and as a json object (via EventAttribute), but it just times out. I will note that the size of the data is only about 500KB, and Parse has no problem accepting this data. This is what I tried:

GSRequestData gsData = new GSRequestData(data);
LogEventRequest eventRequest = new GameSparks.Api.Requests.LogEventRequest().SetEventKey("SAVE_PLAYER_DATA")
     .SetEventAttribute("SaveData", gsData)
     .SetMaxResponseTimeInSeconds(30);

// Send the request
eventRequest.Send((response) => {
	if (!response.HasErrors) {
		Debug.LogWarning("Player Saved To GameSparks...");
	} else {
		Debug.LogError("Error Saving Player Data: " + response.Errors.JSON);
	}
});

  

I've also tried to send it as an uploadable json file (I've made sure the data is not encrypted), and no matter what I try I just get a 500 error as a response. I'm probably doing something wrong here, setting up the WWW object incorrectly, but I don't see any examples of how to upload json data this way, only binary data. This is how I'm trying to send the data now:

var encoding = new System.Text.UTF8Encoding();

Dictionary<string, string> postHeader = new Dictionary<string, string>();
postHeader.Add("Content-Type", "text/json");
postHeader.Add("Content-Length", saveData.Length.ToString());

WWW request = new WWW(url, encoding.GetBytes(saveData), postHeader);
yield return request;

 

Any links on how to upload json data as an uploadable via GetUploadUrlRequest in unity? For the moment, I'm trying to send it as valid json, it is no longer encrypted.

Having the same problem here, did you have any luck?

Hey, we just ended up saving the data as an uploadable instead, this way the data didn't need to be valid json and also it could be bigger (I think it supports 3.5MB).


To do it, you need to request an Upload URL:

new GetUploadUrlRequest().Send((response) =>
{
	StartCoroutine(UploadAFile(response.Url, encryptedData));
});

Once you get the upload URL, you can then upload your data using UnityWebRequest:

private IEnumerator UploadAFile(string uploadUrl, string encryptedData)
{
	byte[] bytes = Encoding.UTF8.GetBytes(encryptedData);

	WWWForm form = new WWWForm();
	form.AddBinaryData("file", bytes, "save.json", "text/json");

	UnityWebRequest request = UnityWebRequest.Post(uploadUrl, form);
	yield return request.Send();

	if (request.error == null)
	{
		Debug.Log("[GS] Save file uploaded successfully.");
	}
	else
	{
		Debug.LogError("[GS] Error uploading save file: " + request.error);
	}

	request.Dispose();
	request = null;
}

Then in cloud code, in the User -> UploadCompleteMessage message, we get the id for that upload and save it to our runtime collection so we can associate and access uploaded files to players. For us, we are uploading save files, so the player should only ever have one save file. With Uploadables, it doesn't appear possible to update an existing file, so anytime a player uploads a save file, we delete their old file via deleteUploadedFile.


Then, to download the file, we need to get the upload id which we saved to our runtime collection and request a download url for it:

new GetUploadedRequest().SetUploadId(uploadId).Send((response) =>
{
	// Pass the url to our coroutine so that we can download it
	StartCoroutine(DownloadFile(response.Url));
});

Then we use UnityWebRequest once again to download the file from the url returned to us:

private IEnumerator DownloadFile(string url)
{
	// Make the web request
	var fileRequest = new UnityWebRequest(url);
	if (fileRequest == null)
	{
		yield break;
	}

	fileRequest.downloadHandler = new DownloadHandlerBuffer();
	yield return fileRequest.Send();

	if (fileDownloadedCallback != null)
	{
		// Access data via fileRequest.downloadHandler.text
	}
}

And thats how we save players data to gamesparks. Not sure if it's the best way to do things, but it's working for us anyway. 


1 person likes this

Thank you David for sharing the code. It helps me understand a bit better on how GS works under Unity.

Login to post a comment