Sign In Register

How can we help you today?

Start a new topic
Answered

A few questions from a newbie (linking collections and how to save data)

Hello everyone, 


Just started learning GameSparks and using it today for a Unity pet project I have and I have a question regarding how to link collections together. 


I have created a realtime database and called it PlayerInventory. Also have another database in authentication called player just like everyone else. 


The scenario that pertains to the question is, if each player has 3 characters that he can create. Each of these characters can have their own inventory. How do I link between the player database, PlayerInventory and PlayerCharacters?


Another question in Database tutorials, specifically the save and load player data, they walk you through creating a meta database for items. Is this approach better that I create all my items in GameSparks? Or would it be better if I have server authority in my multiplayer game to have them as ScriptableObjects on the server (the latter was my first thought so it reduces network calls)?


My last question is if there is any complete tutorials or guide around that walks you through setting up a game in Unity for newbies or first timers? While the documentation is good and I think I can understand most of it, I am left at times wondering how certain things are implemented in a production environment and not an isolated one of tutorials.


Thanks a lot in advance :)


Best Answer

Hi Mohamed,


Welcome to GameSparks, I am sure you will find it's got an answer for every problem you have. Glad to have you onboard.


The link to everything on GameSparks is Cloud Code. Cloud Code is our cloud scripting component. It allows you to do server authoritative and player specific logic. In Cloud Code you can do collection specific tasks like update, delete or create entries. Each player has a unique player ID and a unique username. When creating a new entry for playerInventory and playerCharacters you will save the player's ID as the entry's ID. Here's an example:


Player collection:

 

{"_id":{"$oid":"5602ada7e4b02f152a8c0ee4"}, "userName":"example", "displayName":"example"}

 

You notice the $oid is a unique string used to identify the player, you can also use the username since its unique.  Knowing this piece of information, I can use that unique ID in creating a playerInventory collection using the player's ID as the entry's ID, like so:


//Load collection
var collection = Spark.runtimeCollection("playerInventory");

//Create entry using player ID
collection.insert({"_id":{"$oid":Spark.getPlayer().getPlayerId()},"inventory":{}});

//Get that entry in the future
var playerEntry = collection.findOne({"_id":{"$oid":Spark.getPlayer().getPlayerId()}});

 

As you can see, because you set the entry ID as the player ID you'll be able to get it and update in the future with ease by referencing the player's ID. The character collection will have the player ID as the entry ID then every character will have a JSON object within that entry. so:

 

{"_id":{"$oid":"5602ada7e4b02f152a8c0ee4"},"characters":{"char1":{"class":"mage","health":70},"char2":{"class":"warrior","health":180}}}

 

I hope this helps you understand the gist of how things work, if you have anymore specific questions, we'll be happy to help you.


For your second question, I advice having a meta data collection of your items. This will help you edit things on Cloud without having to update your Game Client every time there's a new item or tweak. This way you can make your changes via server end and push them, and it would seem seamless. Also, if you do things from game client you're going to have to update the backend anyway to the fact that this player has now got that item in their inventory, it makes no difference to your data usage that you update or access the database when youve made that update inventory call.


For the last question, apart from tutorials around the docs website, and the Getting started tutorials unfortunately there isnt anything else. We are planning on introducing video tutorials sometime that will help you learn the pipeline.


Hope this helps,

Omar

 




Hi Mohamed,

One way you might go about keeping reference to a players character document might be to keep a record of the id of this character document inside the player privateData, you can do this like so:

Spark.loadPlayer(playerId).setPrivateData("character", characterId);

This would then make referencing this very easy like so

Spark.loadPlayer(playerId).getPrivateData("character");


It would really depend on the individual use case here whether one has an advantage over another. Having them setup inside a runtime collection would allow you to edit these during live operations which might be something you might consider?


We have a few tutorials that will explain various topics, as each use case can be very different we try to isolate our tutorials into covering select individual topics, however we do have some more general beginner tutorials like the following here (https://docs.gamesparks.com/getting-started/creating-a-game/unity-setup.html) Basic Setup, here (https://docs.gamesparks.com/getting-started/using-cloud-code/unity-cloud-code.html) Cloud Code Integration and here (https://docs.gamesparks.com/getting-started/creating-an-achievement/unity-achievements.html) Achievements integration. I hope this helps and of course if you have any issues please get in touch.


Kind regards,

 - Steve




Hey Steve, 


Thanks for your reply. 


Just to confirm I understood what you meant correctly, let's say I have Player (which is in the System part), PlayerCharacters, PlayerInventory and PlayerStats. If I include Player's id in PlayerCharacters as part of the attributes and include the PlayerCharacters id in PlayerInventory and PlayerStats I could then reference them. That or perhaps vice versa where PlayerCharacters has a reference id to both the PlayerInventory and PlayerStats associated with it?


Is it possible to avoid CloudCode? I am not good with JS and would like to handle everything in Unity, is that possible? Basically just send data and get it written into the collections? 


My use case is an online multiplayer similar to Realm of the Mad God but a smaller scale. UNet handles the entire multiplayer aspects and I would like to use GameSparks for authentication (creating player accounts) and database only. So basically storing player data and that is about it. Which approach would be better ScriptableObjects or Meta collection? Also would I be able in this case to avoid Cloud Code and just do everything from within Unity?


Thanks for your help :)

Answer

Hi Mohamed,


Welcome to GameSparks, I am sure you will find it's got an answer for every problem you have. Glad to have you onboard.


The link to everything on GameSparks is Cloud Code. Cloud Code is our cloud scripting component. It allows you to do server authoritative and player specific logic. In Cloud Code you can do collection specific tasks like update, delete or create entries. Each player has a unique player ID and a unique username. When creating a new entry for playerInventory and playerCharacters you will save the player's ID as the entry's ID. Here's an example:


Player collection:

 

{"_id":{"$oid":"5602ada7e4b02f152a8c0ee4"}, "userName":"example", "displayName":"example"}

 

You notice the $oid is a unique string used to identify the player, you can also use the username since its unique.  Knowing this piece of information, I can use that unique ID in creating a playerInventory collection using the player's ID as the entry's ID, like so:


//Load collection
var collection = Spark.runtimeCollection("playerInventory");

//Create entry using player ID
collection.insert({"_id":{"$oid":Spark.getPlayer().getPlayerId()},"inventory":{}});

//Get that entry in the future
var playerEntry = collection.findOne({"_id":{"$oid":Spark.getPlayer().getPlayerId()}});

 

As you can see, because you set the entry ID as the player ID you'll be able to get it and update in the future with ease by referencing the player's ID. The character collection will have the player ID as the entry ID then every character will have a JSON object within that entry. so:

 

{"_id":{"$oid":"5602ada7e4b02f152a8c0ee4"},"characters":{"char1":{"class":"mage","health":70},"char2":{"class":"warrior","health":180}}}

 

I hope this helps you understand the gist of how things work, if you have anymore specific questions, we'll be happy to help you.


For your second question, I advice having a meta data collection of your items. This will help you edit things on Cloud without having to update your Game Client every time there's a new item or tweak. This way you can make your changes via server end and push them, and it would seem seamless. Also, if you do things from game client you're going to have to update the backend anyway to the fact that this player has now got that item in their inventory, it makes no difference to your data usage that you update or access the database when youve made that update inventory call.


For the last question, apart from tutorials around the docs website, and the Getting started tutorials unfortunately there isnt anything else. We are planning on introducing video tutorials sometime that will help you learn the pipeline.


Hope this helps,

Omar

 



Hello Omar,

 

Thanks a lot for your detailed reply. I'll reply below to the points you addressed:

 

"Cloud Code is our cloud scripting component. It allows you to do server authoritative and player specific logic."

 

I understand and while I do understand the concepts behind the code and what needs to be done, I find the syntax quite difficult to follow and understand. That is why I was trying to evade using Cloud Code at all. Seems no going around it so I'll try to get by somehow. However, if there is an opportunity for feedback, it is quite confusing.

 

 

"collection.insert({"_id":{"$oid":Spark.getPlayer().getPlayerId()},"inventory":{}});"


Does this line of code then mean:

In the collection we created previously, insert an attribute called "inventory" in the entry which has an "_id" equal to "$oid"? 


Consequently then, the below line:

 

var playerEntry = collection.findOne({"_id":{"$oid":Spark.getPlayer().getPlayerId()}});


That line means; in the above collection defined, find an entry using the playerID which is stored in the attribute "_id" and assign it to playerEntry? Does that mean that to use .findOne() I need to find assign the collection I am referencing in a variable same you did with the variable collection? 


Another question raises itself is when I want to update a part of a collection's entry rather than the entire entry. What if I have an item as follows:

 

{ "shortCode" : "HomeBeacon", "name" : "Home Beacon", "description" : "This item allows you to teleport back to the last activated beacon", "unique" : "true", "Tradeable" : " false", "type" : "General" }

 And let's say I want to change the name from "Home Beacon" to "Home Teleporter". I tried doing an Update (on the dashboard and not code) by just querying { "name" : "Home Beacon" } and added the update as { "name" : "Home Teleporter" } and that overwrote the entire entry with the { "name" : "Home Teleporter" }. Does that mean if I want to change a name, I need to literally send the entire format? 


One more thing, is there noway to use emails as the username rather than ask the player to choose his own?


"I hope this helps you understand the gist of how things work, if you have anymore specific questions, we'll be happy to help you. "

Thanks a lot. At the current moment if my understanding of the above is correct, I think I could just give this whole thing a whirl and see if I can manage to get it to work. 


"For the last question, apart from tutorials around the docs website, and the Getting started tutorials unfortunately there isnt anything else. We are planning on introducing video tutorials sometime that will help you learn the pipeline."

Well I would love to see those when they come out. Specially if they take you a step by step through creating a full working game (if even a very simple and basic one) that includes how to use the different features of GameSpaks!


Thank you so much for the detailed responses, will try what you've mentioned so far and will see how it goes.

Hey Mohamed,


Cloud Code is a great tool, if you learn it, it will allow you to combine every component in the backend and customise them to your heart's desire to achieve anything that comes to your mind. I do realise Javascript and MongoDB might be new to you, but this is as straight forward as network programming is gonna be, it's quiet fun when you start to understand, and I will do what I can to help you with it!

 

collection.insert({"_id":{"$oid":Spark.getPlayer().getPlayerId()},"inventory":{}});

 

Here we are inserting a new object named inventory. a Javascript object '{}' is variable type that is used as a container or other variables. Like a struct for example. JS objects can save functions, variables and other objects inside them. You notice that all of our requests, responses and messages are just big objects. _id is also an object. Within the object _id we have the string variable $oid which is equal to this players ID. Just an easy way to reference that database entry without having to do any reference logic which would cost us some computing power and resources.


https://www.w3schools.com/js/js_objects.asp


Yes you need to reference the collection you're trying to update, query or remove. Runtime collections are perfect for this.


Mongos update function does overwrite the whole entry, to update a partial part of the entry, use the $set function, like so:


 

//First part is the query
collection.update({"_id":{"$oid":Spark.getPlayer().getPlayerId()}},{ "$set":{"quantity": 500 }})

 

 

 Here, only the variable 'quantity' will be updated in this entry. The whole entry will NOT be rewritten. More on this here:


https://docs.mongodb.com/manual/reference/operator/update/set/


I think it is possible to use a string of the email as the username. Or you can set the email as scriptData(Custom data) on the player.


Hope this answers all these questions, do ask more!


Cheers,

Omar








Hi Omar, 


OK, I think I am starting to get it. Sorry for the loads of questions and complaints. You did help me quite a lot and I think that is enough for now or we'll turn this thread more into a course than anything else :P


I'll give what you've taught me so far a run and see how far I can get with this. If I hit another wall I'll post again. 


Again, thank you very much and I really do appreciate it. 


Side Note: Considering the fact that I deal with a lot of support as of late, GameSparks' support is excellent thanks to you guys. It definitely got me to want to continue trying to get GameSparks working rather than try something else :). You all should ask for a raise :P

Haha glad you find it useful, here to help!


Let us know if you need anything else,

Have a great day!

Omar

Login to post a comment