So I’m currently brainstorming a design for my data system, and I found a way to back up player data, giving players the ability to restore their data from a “restore your data” menu if they needed to.
Essentially, the system would work roughly like this :
A player has left the game. Save their data to their regular datastore key, such as Player_183000342 as an example. Write to a second key in the backup datastore, with the key name being <PlayerID>@<Timestamp>, where <PlayerID> is the ID of the player and <TimeStamp> is the exact time stamp that the key is being written (used as a unique identifier).
If a player joins the game and clicks on the “Recover your data” menu, the game queries the backup datastore for all keys that the player owns. The data “files” are now displayed on a list UI, showing the timestamp of the “file” (not literally a file, semmantics for demonstration purposes). When the player clicks on one, and confirms via an OK dialog or something, the backup key they chose is written to their normal key in the regular datastore, essentially restoring their backed up data.
I personally love this design, but I ran into a problem - how would I find all backup keys (or a certain number of the most recent ones) that the player owns in the backup datastore (with a scope too maybe)?
I know datastore iteration was talked about at last year’s developer conference/RDC17 along with a lot of other new datastore features such as automatic retries, but there is no way to iterate through datastores at the moment.
Is there any way I could do this?
If not, what’s another way I could back up user data via unique timestamp, and let the user choose which one they want?
Could I just have 3 backup keys, named <PlayerID>Backup_1,<PlayerID>Backup_2,<PlayerID>Backup_3, and query those 3 keys?
Yeah I’m aware, I’m not exactly concerned with the efficiency of the system right now. When I start designing the actual system I’ll obviously find an efficient way of implementing it.
EDIT : I think I just found a more elegant / efficient way.
Instead of querying 3 keys, I can just query 1 backup key which has 3 tables in it, each containing the 3 backups of the players data. There’s also a number value containing the last backup number that was written to (useful for deciding when to overwrite the 1st backup).
This is how I store infinite backups and can access them easily and chronologically too. Best part is I don’t hit any throttling limits (also there’s probably some people on the web team who hate me for this)
So how I understand it is instead of doing “player_1234” or whatever you’d put in the os.time? But if multiple people save at the same os.time wouldn’t that overwrite their data?
local DataStoreService = game:GetService("DataStoreService")
local playerExperienceStore = DataStoreService:GetDataStore("PlayerExperience")
local playerExperience = 0
pcall(function()
playerExperience = playerExperienceStore:GetAsync("player_1234")
end)
“player_1234” is the key, if I were to replace it with os.time as the key, wouldn’t it overwrite the datastore if two players tried to save at the same os.time?
How well does this prevent users from losing their data and how could I make data restores? I was thinking if I allowed players to revert their data to an older version, they could exploit it by trading some items, rejoining and reverting to before they traded their items, or something like that.
It looks like I won’t be allowing users to manually restore their data, but a backup system is still useful to have. I simply won’t add in the “restore your data” menu.