How Should I Handle Player Data Saving/Loading Between Servers?

I’m currently working on a round-based game where players will constantly be teleported between servers (player joins lobby server, gets teleported to a reserved server that plays a round, then teleports all players to another lobby and shuts down), and data management is proving to be a giant headache (as per usual).

Essentially, my original plan was to use some DS2-style system where the data is loaded when the player joins and saved when the player leaves/server shuts down, but it has occurred to me that my game is especially prone to a classic scenario: the player leaves the game and the data fails to save (or just takes forever), but before it gets a chance to retry, the player joins a new server and their old data is loaded back in, overwriting their save.

One solution I can think of is to just use MessagingService to send a copy of the player’s data to all servers, so the next server can grab the messaged data and use it as a higher-priority source than the DataStores, but MessagingService is still not very reliable despite recent improvements.

Another solution is to just not let the player leave until the data has saved successfully, but the player could always just exit the game and rejoin to bypass those restrictions (though I could at least say to them, “Well, the game told you so…”). This has other issues, such as the player straight-up not being able to play the game in the event of an outage.

A third solution would be to detect DataStore changes mid-play and prompt the player to reconcile the issue by choosing between the save files. Upon first glance this seems like a good idea, but the more I think about it the more it falls apart. If the player loads a different dataset in the middle of their playthrough, they’ve just overwritten some amount of progress, and in a PvP game they could also use this to their advantage: use some really powerful consumable, and then after dealing a ton of damage, overwrite their save data and use the consumable again. It also interrupts the flow of the game. The more I write the more I realize this idea sucks, but I’m going to keep it in anyways just so people know I have thought of it.

Which of these three would work the best, and why? Should I use some combination of the three? Do you have a better way to do it? I’ve dealt with players losing data before and I really don’t want to deal with it again.

Edit: This isn’t a complete solution but could help with mitigating the issue, but what if I just didn’t load the player’s data until it was actually required (i.e. they open the shop or something)? It wouldn’t work for all games but in a round-based game it could actually provide some cushion.

4 Likes

This is one way, don’t tp the players back until the data has saved.

If you’re making minor changes to stats you could pass Teleportation Data when you teleport the players back to the game, I’m not sure if this could be manipulated on the users end at all, and I’m not sure how reliable it is as I haven’t tried it my self.

Essentially when the player joins back to the main server it would then save it, while data loss could be possible if the player decides to exit the game during the teleport, you could use datastores/messaging service as a backup.

As for Match Making I would try the Messaging Service personally. A few dropped messages here and there I think is okay so long as you can take that into account with that system.

Another option would be to store the data to an external service such as through Amazon or something else.

the third solution might work, but I’m not sure it’s a good idea as the player might not know which one to choose from. However, this could add an interesting aspect to gameplay, reversible round data; didn’t like the game you just had, don’t save it!

As for the Edit, I think that could be an option, the player would have to wait for a few seconds when the server went to retrieve that data, after which just make sure you save it to a table in the script so it’s not having to constantly pull from datastores when you can pull once and use that data over and over making changes as needed before saving it. (Edit: Just note it’s always possible for the pull to fail.)

Yeah, I’m pretty sure this can be spoofed by players.

I’ve already got matchmaking covered.

That’s still a bit out of my wheelhouse, unfortunately. Maybe someday.

I personally don’t code but finding another way like @helperobc said about platforms like amazon, though it may seem a bit out of your wheelhouse, I certainly believe there is multiple other ways out there. Sorry if this didn’t help, I was just giving feedback.

1 Like

Salve, I made a rough draft solution, this is a hypothetical algorithm and I have not tested it yet

Summary

The general idea is as follows; There are two data stores, One called Data to load, and another called PlayerData. The method of which data loads is that it goes from each key within the data table of “Data to load,” and if a key is missing, it will then wait for the key to not be missing.
If it takes too long, it will then patch it with data from the real store and give a player a choice.
It will allow him to stay in the server and bring data loss responsibility on himself, or he can leave and a prevent data save will be toggled to false; I think it should default to false to prevent data saving in a time of crash whilst loading and should be toggled true when data is finished loading

and for saving
-If cansave == false then return end
-make a short term data table
-go through each key of that data table
-and save it to the two respective data stores
-If there are any errors; retry to save x times

Why dose this work

Answer

It works for 1 reason, it takes time for it to save, and time to load.
For instance, each key is saved at a time instead of a whole table.
This enables portions of data to go through at a time, and not only that
while data is loading, it will wait for each key to occur or patch with
data from the real main data store. And if a player leaves while it’s loading,
a null data will not save as a toggle var will prevent it, and then once a player rejoins
it will load data from the fully patched “Data to load.”
and if a portion fails to save; it will patch it with the real data
The Player will be warned and he can choose to rejoin to wait for fully patched data, or
he can also choose to stay; however, a invalid data state will be set and the data
in his current play session will be counted as a backup in which he can choose to load when he rejoins. (do not save in “data to load”; this is to prevent the data from other servers to finish init. Possibly make a third data store for "data to load_backup)

Glaring Flaws

Sound Counter Arguments

There are multiple issues I have though about this.
First of all, if a player’s data is truly corrupted, it will constantly warn the player
that data is missing. Another issue is that of when going through each key,
and if the key is missing, it will force the data store to be required constantly
until the key is found. Although this is countered with the feature of which
it patches a key. And to sum it up, it takes time. This may take a few seconds or
even more lengthy time. There are other issues I have not thought about.

1 Like

It’s an interesting idea but I don’t really think it would help with fixing the issue. This all still depends on a DataStore bit being saved by the time the player has joined another server, which isn’t guaranteed. On top of that, separating the data into multiple keys will make managing rate limits much harder.

1 Like

I did some analysis on some data saving and loading and thought about a save and load failure. This puzzles me a little about how to handle this. Maybe if you could find any endpoint to check if the player is actually in the game but not in the server and use MessagingService to inform the user that their session is invalid.

On this scenario:

  1. Player leaves the game
  2. Cached data is not properly saved, attempting until success
  3. Player joins again, loading data
  4. Use MessagingService to intercept any possible save failure
  5. The target server would return the response
  6. Mark invalid data and warn player

Thinking about this is a difficult problem to tackle. Cross-server management with data is very hard to do so. Mitigating it requires some warning when the server detects saving failures. Also it you could do a global announcement using MessagingService if the amount of flags lit up on saving failures is over X.

Possibly, you could attempt load the data while saving to see if the timestamp of saving is much later than the current one. Then do some specific recalculation of the data to compensate the mismatched data. However, this solution is unpredictable. One issue is one saving ahead of the other. Thus you have to do the loading again on both sides to check timestamp of latest save.

2 Likes

Those are some interesting ideas, I’ll have to look into that. One note, though:

Unfortunately cross-server timestamps seem to be unreliable.

1 Like