Sign In Register

How can we help you today?

Start a new topic
Answered

save data (safely) with logic checking on server side

 

Hello, I'm beginner on GameSparks.
I have a few questions:

I need to save some data from my game and get them (I use Unity3D) and how can I do it safely (cheaters protecting).

Where I can create a Collection in the Runtime area or Metadata area?

How can I add value from collection A with value from collection B (from Cloud Code) and save it all to collection C.

How can I (from Unity) safely and correctly do Insert, Update, Delete any data in right collection?

Thanks!


Best Answer

Hello!


So to store information in a collection, you do so in an event in Cloud Code. In all cases we should use the playerId which is unique to each player and therefore should only return one document when queried. I'll run through the entire flow and add an example bit about adding from multiple documents into another document at the bottom.


On RegistrationResponse you can create a document for each player:


    

//Creates or finds a collection
var playerSavesCollection = Spark.runtimeCollection("playerSaves");

//A Javascript Object containing player information, we'll use this information to search for and update a player's save
var entry = {"playerId" : Spark.getPlayer().getPlayerId()};

//Inserts a document into a collection and returns true or false if the document insertion worked or not
var success = playerSavesCollection.insert(entry);

    


Then when we want to update the player's information we can create a custom event that accepts a JSON attribute, in this example we'll name it "JSONData" and in it's cloud code we can write:


    

//Finds our "playerSaves" collection
var playerSavesCollection = Spark.runtimeCollection("playerSaves");

//Finds the document with our player's Id
var playerSave = playerSavesCollection.findOne({"playerId" : Spark.getPlayer().getPlayerId()}); 

//This gets the JSONData attribute we are passing in
var JSONData = Spark.data.JSONData;

//Overwrite our playerSave with the data we are sending
playerSave = JSONData;

//Re-apply our user's I'd (it just got overwritten)
playerSave.playerId = Spark.getPlayer().getPlayerId();

// Update the document in our collection that contains our playerId with the current playerState
var success = playerSavesCollection.update({"playerId" : Spark.getPlayer().getPlayerId()}, playerSave);

//This will print the information in the response on the TestHarness and send it in the response in Unity.
Spark.setScriptData("playerState", playerSavesCollection.findOne({"playerId" : Spark.getPlayer().getPlayerId()}));

    

Then to update that information from Unity you need to do a few things:


    

using GameSparks.Core;
using GameSparks.Api.Requests:;

//We create a GSRequestData variable
//by using jsonDataToSend.Add() we can add in any variable we choose
//and they will be converted to JSON
			GSRequestData jsonDataToSend = new GSRequestData();
			jsonDataToSend.Add("health", playerHealth);
			jsonDataToSend.Add("strength", playerStrength);
			jsonDataToSend.AddString("name", playerName);
			jsonDataToSend.Add("playerPos", transform.position);

//We then send our LogEventRequest with the event shortcode and the event attrirbute
			new LogEventRequest().SetEventKey("setPlayerDataJSON")
			.SetEventAttribute("JSONData", jsonDataToSend)
			.Send((response) =>
			{

			}); 

    


This should send the data to GameSparks, the Cloud Code will interpret the data and save it to the document of the player stored in our collection.

To get that data back again, we need to create another custom event, we'll have this event take an attribute of "playerId":


   

//You use this to get any other player's current state

//This finds the runtimeCollection in which all the playerState documents are stored
var playerSavesCollection = Spark.runtimeCollection("playerSaves");

//This will find a particular user's state via the player Id we pass in
var playerSaves= playerSavesCollection .findOne({"playerId" : Spark.data.userId});

//This will set the information to ScriptData so it's easily readable in Unity or the Test Harness
Spark.setScriptData("playerState",  playerSaves);

   


If you run that in the test harness it should come back with the user's save.


Do retrieve it in Unity use the following:


   

//Send our logEventRequest to retrive information from the collection
			new LogEventRequest().SetEventKey("getPlayerData").SetEventAttribute("userId", userId).Send((getPlayerStateResponse) =>
			{
				if (getPlayerStateResponse.HasErrors)
				{
					Debug.Log(getPlayerStateResponse.Errors);
				}
				else
				{
					//Assign the variables from our document to our instance
					playerHealth = getPlayerStateResponse.ScriptData.GetObject("playerState").GetNumber("health").ToString();

					playerStrength = getPlayerStateResponse.ScriptData.GetObject("playerState").GetNumber("strength").ToString();

					playerName = getPlayerStateResponse.ScriptData.GetObject("playerState").GetString("name");
					playerPos = getPlayerStateResponse.ScriptData.GetObject("playerState").GetString("playerPos");
				}
			});

   

To get values from multiple collections and save them to another you could do something like:


  

var player1Save = playerSavesCollection.findOne({"player1Id" : Spark.data.userId});

var player2Save = playerSavesCollection.findOne({"player2Id" : Spark.data.userId});

var playerGroup = playerGroupsCollection.findOne({"playerGroupId" : Spark.data.groupId});

var combinedPlayersStrength = player1Save.strength + player2Save.strength;

playerGroup.strength = combinedPlayersStrength;

var success = playerGroupCollection.update({"groupId" : Spark.data.groupId}, playerGroup);

 


Hope this helps! 


Shane


2 people have this question

Answer

Hello!


So to store information in a collection, you do so in an event in Cloud Code. In all cases we should use the playerId which is unique to each player and therefore should only return one document when queried. I'll run through the entire flow and add an example bit about adding from multiple documents into another document at the bottom.


On RegistrationResponse you can create a document for each player:


    

//Creates or finds a collection
var playerSavesCollection = Spark.runtimeCollection("playerSaves");

//A Javascript Object containing player information, we'll use this information to search for and update a player's save
var entry = {"playerId" : Spark.getPlayer().getPlayerId()};

//Inserts a document into a collection and returns true or false if the document insertion worked or not
var success = playerSavesCollection.insert(entry);

    


Then when we want to update the player's information we can create a custom event that accepts a JSON attribute, in this example we'll name it "JSONData" and in it's cloud code we can write:


    

//Finds our "playerSaves" collection
var playerSavesCollection = Spark.runtimeCollection("playerSaves");

//Finds the document with our player's Id
var playerSave = playerSavesCollection.findOne({"playerId" : Spark.getPlayer().getPlayerId()}); 

//This gets the JSONData attribute we are passing in
var JSONData = Spark.data.JSONData;

//Overwrite our playerSave with the data we are sending
playerSave = JSONData;

//Re-apply our user's I'd (it just got overwritten)
playerSave.playerId = Spark.getPlayer().getPlayerId();

// Update the document in our collection that contains our playerId with the current playerState
var success = playerSavesCollection.update({"playerId" : Spark.getPlayer().getPlayerId()}, playerSave);

//This will print the information in the response on the TestHarness and send it in the response in Unity.
Spark.setScriptData("playerState", playerSavesCollection.findOne({"playerId" : Spark.getPlayer().getPlayerId()}));

    

Then to update that information from Unity you need to do a few things:


    

using GameSparks.Core;
using GameSparks.Api.Requests:;

//We create a GSRequestData variable
//by using jsonDataToSend.Add() we can add in any variable we choose
//and they will be converted to JSON
			GSRequestData jsonDataToSend = new GSRequestData();
			jsonDataToSend.Add("health", playerHealth);
			jsonDataToSend.Add("strength", playerStrength);
			jsonDataToSend.AddString("name", playerName);
			jsonDataToSend.Add("playerPos", transform.position);

//We then send our LogEventRequest with the event shortcode and the event attrirbute
			new LogEventRequest().SetEventKey("setPlayerDataJSON")
			.SetEventAttribute("JSONData", jsonDataToSend)
			.Send((response) =>
			{

			}); 

    


This should send the data to GameSparks, the Cloud Code will interpret the data and save it to the document of the player stored in our collection.

To get that data back again, we need to create another custom event, we'll have this event take an attribute of "playerId":


   

//You use this to get any other player's current state

//This finds the runtimeCollection in which all the playerState documents are stored
var playerSavesCollection = Spark.runtimeCollection("playerSaves");

//This will find a particular user's state via the player Id we pass in
var playerSaves= playerSavesCollection .findOne({"playerId" : Spark.data.userId});

//This will set the information to ScriptData so it's easily readable in Unity or the Test Harness
Spark.setScriptData("playerState",  playerSaves);

   


If you run that in the test harness it should come back with the user's save.


Do retrieve it in Unity use the following:


   

//Send our logEventRequest to retrive information from the collection
			new LogEventRequest().SetEventKey("getPlayerData").SetEventAttribute("userId", userId).Send((getPlayerStateResponse) =>
			{
				if (getPlayerStateResponse.HasErrors)
				{
					Debug.Log(getPlayerStateResponse.Errors);
				}
				else
				{
					//Assign the variables from our document to our instance
					playerHealth = getPlayerStateResponse.ScriptData.GetObject("playerState").GetNumber("health").ToString();

					playerStrength = getPlayerStateResponse.ScriptData.GetObject("playerState").GetNumber("strength").ToString();

					playerName = getPlayerStateResponse.ScriptData.GetObject("playerState").GetString("name");
					playerPos = getPlayerStateResponse.ScriptData.GetObject("playerState").GetString("playerPos");
				}
			});

   

To get values from multiple collections and save them to another you could do something like:


  

var player1Save = playerSavesCollection.findOne({"player1Id" : Spark.data.userId});

var player2Save = playerSavesCollection.findOne({"player2Id" : Spark.data.userId});

var playerGroup = playerGroupsCollection.findOne({"playerGroupId" : Spark.data.groupId});

var combinedPlayersStrength = player1Save.strength + player2Save.strength;

playerGroup.strength = combinedPlayersStrength;

var success = playerGroupCollection.update({"groupId" : Spark.data.groupId}, playerGroup);

 


Hope this helps! 


Shane

How would you do ...

playerHealth = getPlayerStateResponse.ScriptData.GetObject("playerState").GetNumber("health").ToString();

 ...if you want to retrieve playerHealth from a received array of player?


Hi Gabriel,


If you are getting playerHealth from an array on the player you need to get a bit more specific and use GetDoubleList, GetIntList or GetFloatList. So if you were storing playerHealth, playerStrength, playerDefense etc in an array called "playerStats" = [100, 15, 12] respectively it would be: 


playerHealth = getPlayerStateResponse.ScriptData.GetObject("players").GetDoubleList("playerStats")[0];



If you are receiving an array of playerObjects it would be: 


playerHealth = getPlayerStateResponse.ScriptData.GetObjectList("playerState")[0].GetNumber("health").ToString();


If you have any more questions please fire away, if you have any examples of what you're trying to do, please post them as well, it helps us a lot.


Shane

Hello I follow this tutorial as best as I could and I am unable to get a working result. Was wondering what I could have done wrong.


In Unity I send a ReqistrationRequest to create a new player. In my cloud code on RegistrationResponse I included the code you provided. I check my NoSQL and I was not able to find the document "playerSaves". I even tried to move the code to ReistrationRequest since I thought it should fired that event automatically since I am sending a RegistrationRequest but unfortunately that didn't work either.

Hi Khen,


Try using 


var success = playerSavesCollection.save(entry);


and if that doesn't work can you paste your code? If it would help you could add me to your GameSparks game as a collaborator from the overview panel, this will allow me to check your code from the Portal. 


Let me know how it goes,

Shane

Hi Shane thank you for the reply. I eventually solve this on my own by simply ticking of debug mode in unity. I always get a "unkown" event key response back from gamespark even when working of the test harness. Then I tried working on the preview snap shot it works as intended. I don't know if I'm doing things correctly or not but nothing work for me on LIVE configuration.

Sorry for the dig up, but I found this topic really useful! 


I'm getting an error thought, here is the output


 

WebSocket onMessage: {"@class":".GameSparksErrorResponse","error":{"message":"TypeError: Cannot set property \"playerId\" of undefined to \"573874891474e704c7c68562\" (298828-event-GSAV#20)"},"message":"TypeError: Cannot set property \"playerId\" of undefined to \"573874891474e704c7c68562\" (298828-event-GSAV#20)","requestId":"1463317640768_2"}

 

Hello,


I have followed the tutorial but couldn't update my runtime collection. I tested it in testharness. I am just modifying playerID. Need help.


Thanks.

Login to post a comment