question

Cedric Neukirchen avatar image
Cedric Neukirchen asked

Where to store what data? - UserData, CharacterData, PlayerStatistics

Good day everyone,

I'm getting a bit lost in all the different ways PlayFab saves data.
If anyone has an overview, I would very much appreciate it if they could quickly tell me where each of the following should go.

Our game has, similar to Apex Legends or Fortnite, a SeasonPass with customizations.
These can be characters, hats, emotes, skins and more.

I saw that I can have a store of sorts for our ingame-store. That is fine, however how do I realize the following concepts:

- Season Pass Data
-- Has to match a specific timeframe (e.g. 1st May to 1st June)
-- Static Data, Read-Only, set by the Developers
-- Is a complex Json Object with multiple fields in field

- Optained customizations of the player
-- Via Season Pass or Store
-- Can maybe stack in the future
-- Read-Only!

- Currently equipted items/loadout
-- Read-Only!
-- Should be adjusted via custom CloudScript to "equip" items.
This would ultimately check if the player owns the item before equipping it.
-- Other players might need to be able to retrieve the data too.

- Experience and Level
-- Of the SeasonPass
-- Of the Player
-- Read-Only!

As you can see the data has to be read-only for clients at all times. Now I saw that most of the stuff you can do in PlayFab has a Read-Only version, which is good. I also assume that the "Optained customizations" can go into the "UserInventory", however how does one stack these if wanted (Hat XY optained 3 times)?

Furthermore, what is the difference between PlayerData and PlayerStatistics?
Should I save XP and Level in the Data or Statistics? I saw both already while searching the forums.

Then I thought I could use the PlayerData (Read-Only) for the current loadout, but I struggle to see how I can retrieve these. I want to save an object of an array, something like this:

Controllers = 
[{
	"custom_drone" : "custom_drone_daze",
	"custom_hat" : "custom_hat_hatless",
	"custom_trail" : "custom_trail_fire",
	"custom_material" : "custom_material_chrome",
	"custom_color" : "custom_color_white",
	"custom_brightness" : 1.0,
},{
	"custom_drone" : "custom_drone_daze",
	"custom_hat" : "custom_hat_hatless",
	"custom_trail" : "custom_trail_fire",
	"custom_material" : "custom_material_chrome",
	"custom_color" : "custom_color_white",
	"custom_brightness" : 1.0,
},{
	"custom_drone" : "custom_drone_daze",
	"custom_hat" : "custom_hat_hatless",
	"custom_trail" : "custom_trail_fire",
	"custom_material" : "custom_material_chrome",
	"custom_color" : "custom_color_white",
	"custom_brightness" : 1.0,
},{
	"custom_drone" : "custom_drone_daze",
	"custom_hat" : "custom_hat_hatless",
	"custom_trail" : "custom_trail_fire",
	"custom_material" : "custom_material_chrome",
	"custom_color" : "custom_color_white",
	 "custom_brightness" : 1.0,
}]


This is basically an array for 4 splitscreen players and their loadout.
Set through CloudScript and Read-Only for Clients.

Looking into the API for "GetUserReadOnlyData" tells me it ultimately returns a "UserDataRecord" in a Dictionary which seems to only have one "Value" field of type "String". That doesn't really seem to support JsonObjects, or?

So yeah, I'm pretty lost at what to use here. I would love to just have one single PlayerData concept where I can save every sort of JsonObject I can come up with, which is at the same time Read-Only for clients.

Cheers,
Cedric

Player DataCloudScriptPlayer Inventory
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Seth Du avatar image
Seth Du answered
  • Season Pass Data:

Player READ ONLY data, including expiration date, Static Data (do not use Statistics)

  • Obtained customizations of the player:

Customizations (like skins) should be item instances in the player’s inventory, but the application information (check if the player has equipped the “skin”) should be maintained in the Player Data (Player read-only Data should work too). You can also maintain the expiration time at instance Custom Data via UpdateUserInventoryItemCustomData.

In addition, you can give those Season Pass offered items the same tags, so that it will be easy to manage.

  • Currently equipped items/loadout

Like the above one, the items itself should be granted to the player inventory but the equipping information should be in Player Read-only Data (Because it is important data), When you are calling GetUserData, GetUserInternalData Client APIs, you can add other player ID at PlayFabId property in the API request so that player can check other players’ equipments.

  • Experience and Level

Also in Player READ ONLY data.

Basically, most of the player related important data should be stored in the Player Read-only Data, and if there are sensitive data that should not be exposed to the player, they can be stored in the Player Internal Data. For some unimportant configurations or customizations, you can use Player Data.

About JSON object: for now the value field in player data only supports String, you cannot store JSON object directly unless you stringify it. Interesting thing is that if you input a JSON Object manually in the Game Manager, it can be saved, but when you retrieve the data via GetUserData, it is still a string with quote marks escaped. As a result, please be aware of the string format if you want to store a converted JSON object.

In terms of Statistics, they are associated with leaderboards. A Leaderboard will be generated as soon as an statistics is created (be aware of the amount limits , check in [Game Manager]->[Settings]->[Limits]). In the normal circumstance, client should disable players to upload statistics (check in [Game Manager] ->[Settings]->[API Features]), and yes, you can use statistics for XP or Level, but be careful that if the leaderboard is reset, the statistics in the player will be clear too(But you can still retrieve the previous version, please see GetPlayerStatistics).

4 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Cedric Neukirchen avatar image Cedric Neukirchen commented ·

Hey there, thanks for your answer. A few questions though:

The Season Pass Data, so the Data that defines how many levels the current pass has, what each level of the pass offers in terms of items etc. should go into PlayerData?

This is basically one-time static data, wouldn't putting it into PlayerReadOnlyData multiply the data by the amount of players, as every player would have it?

Isn't there something similar to PlayerReadOnlyData that only exists once? I found TitleData, would that suite this approach better?

----

Alright, so owned customizations into the Inventory.
Equipted customizations into the PlayerReadOnlyData.

They wouldn't expire though.

----

Avoid statistics for Level and XP, roger.

----

About JSON Object: I would def need to save JSON Objects in the PlayerData. Stringifying them and turning them back into JSON Objects in UE4 is fine, as long as storing a JSON Object like this in the PlayerReadOnlyData is a valid thing to do(?). I don't know if the value has any bigger limit for the size of the string (big JSON Object).

0 Likes 0 ·
Seth Du avatar image Seth Du ♦ Cedric Neukirchen commented ·

I think there could be something missed when I was writing the last reply, I will clarify it.

I am not aware that some parts of Season Pass Data is pre-defined data (each level of the pass offers in terms of items etc.). Hence, you may store it in the Title Data, as it will be shared by all players within the title. Title Data is a cached and sharded resources and is designed for storing infrequent changing data.

please see the below paragraphs if you are talking about level of pass that a player owns.

---

I mentioned that you can add tags to those customizations, for example, "Season201905". After a season ends, you can check those items according to tag then revoke them. (make use of Cloud Script and segments feature)

---

0 Likes 0 ·
Seth Du avatar image Seth Du ♦ Cedric Neukirchen commented ·

In fact, you can use statistics for Level and XP, it is a choice rather than a designate solution. You may notice that statistics can be reset, hence if this Level and XP will last for a lifetime of a player, you may store in Player Data. If it goes with Season Pass, you may want to rest it every season. In this case, it is better to store them in statistics. (In addition, you may check if statistics keys "Level" and "XP" exist. If no, you can assume the season has ended, then revoke Season-Pass-Available items.)

---

PlayFab offers PlayFab JSON object construction in UE4 SDK and I think you can make use of it.

You can check all the limits information at [Game Manager]->[Settings]->[Limits]. Feel free to create a title in you studio and check it.

0 Likes 0 ·
Cedric Neukirchen avatar image Cedric Neukirchen Seth Du ♦ commented ·

Thanks again for your answer!

Season Pass Items will in fact stay with the player once the Season Ends.
The only thing that won't be possible is aquiring items from a Season Pass that ended.
So I don't need to revoke access to these items after they are in the Inventory of the Player.

For the XP I'm actually not sure yet. I think we would save XP per SeasonPass.
Means that if during Season1 you reached Level 13 with 13.000XP, this would reset to 0, but would also be stored just in case we need the data for later.
So for the Player it's a reset to Level 1 and 0 XP, but we would keep whatever they reached during Season1. I assume I can save this as a simple Json Object Array, where each entry is a Season. That way I could write a custom CloudScript to retrieve the current Season and SeasonData of the Player based on a simple integer passed along with the call.

Now saving it as a Statistic, just because I can call "reset" on it, seems wrong(?).
Because I think I can very much call a custom function to just set the data, saved in the PlayerData, back to 0, or just remove it all together.

Thanks so far for all your time. This is really helpful to get started! (:

0 Likes 0 ·
info-31 avatar image
info-31 answered

@Cedric Neukirchen @SethDuHi, so i'm reading this section

  • Currently equipped items/loadout
    i'm actuallly using this method in unreal engine blueprint and currently it does produce a json with the value. But i'm not sure how do I get just the "value" from the produced json so i can reference it with an item in unreal engine.

    I manage to get this as a result to the node "Encode Json" being sent to a "Print String" node

{"eyes":{"Value":"eyes_001","LastUpdated":"2022-08-11T08:41:37.87Z","Permission":"Public"}}

But what is the setup of nodes I should use to get just the "Value", in this case eyes_001

,

Hi @SethDu @Cedric Neukirchen, so i'm reading this section

  • Currently equipped items/loadout
    i'm actuallly using this method in unreal engine blueprint and currently it does produce a json with the value. But i'm not sure how do I get just the "value" from the produced json so i can reference it with an item in unreal engine.

    I manage to get this as a result to the node "Encode Json" being sent to a "Print String" node

{"eyes":{"Value":"eyes_001","LastUpdated":"2022-08-11T08:41:37.87Z","Permission":"Public"}}

But what is the setup of nodes I should use to get just the "Value", in this case eyes_001

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.