Hello, I need help. Please tell me if this is not the right category for this thread so I can change asap. So basically, I want to ask if there is a way to identify if someone really lost his data stats? Before, I received some reports on my group from my close friends that they lost stats on my game which I already did something to change the way I save data, restored their stats and it never happens to them anymore. But recently, some players are reporting issues with data loss but I am not sure if they are really telling the truth. Here is the piece of code of my leaderstats. Thankyou
local players = game:GetService(“Players”)
local dataStoreService = game:GetService(“DataStoreService”)
local saveDataStore = dataStoreService:GetDataStore(“SaveDataTest”)
local function savePlrData(userID, leaderstats)
local success,err = pcall(function()
local saveData = {}
for _,stat in pairs(leaderstats:GetChildren())do
saveData[stat.Name] = stat.Value
end
saveDataStore:SetAsync(userID,saveData)
end)
if not success then return err end
end
game.Players.PlayerAdded:Connect(function(Player)
local Leaderstats2 = Instance.new(“Folder”)
Leaderstats2.Name = “leaderstats2”
Leaderstats2.Parent = Player
local Currency = Instance.new("IntValue")
Currency.Parent = Leaderstats2
Currency.Name = "Cash"
Currency.Value = 0
local wins = Instance.new("IntValue")
wins.Parent = Leaderstats2
wins.Name = "Wins"
wins.Value = 0
local data = saveDataStore:GetAsync(Player.UserId)
if data then
for _,stat in pairs(Leaderstats2:GetChildren()) do
stat.Value = data[stat.Name]
end
else
print(Player.Name .. "has no data")
end
end)
players.PlayerRemoving:connect(function(plr)
local userId = plr.UserId
local leaderstats = plr.leaderstats2
local err = savePlrData(userId,leaderstats)
if err then print(err) end
end)
game:BindToClose(function()
for _,plr in pairs(players:GetPlayers())do
local userId = plr.UserId
local leaderstats = plr.leaderstats2
local err = savePlrData(userId,leaderstats)
if err then print(err) end
end
wait(2)
end)
AFAIK without external logging it would either be extremely difficult or impossible to tell if any data loss occurred. If you do your data management completely in-house then any data could be valid or invalid so external logging could help you track down if an error occurred while saving a player’s data. I say external because that way you can actually see the log irrespective of when the issue occurred.
One thing I would hazard is to use UpdateAsync to save data, not SetAsync. I’m not sure how many developers would agree with me on this but I personally believe that SetAsync has little to no place in production-level data code that works with critical data. Its use cases are very esoteric and should ideally only be used if you need to force something in.
UpdateAsync itself does not save you from encountering data loss but it removes one vector for it which is race conditions between multiple instances attempting to write data to a key. I’m not sure if you have that same scenario but if you have multiple places in an experience then that’s worth thinking about in case they’re modifying outdated data and forcing that through.
Other than a missing pcall for GetAsync, your DataStore implementation looks good enough, though. You may have to a deeper dive to figure out where the data loss is rooted from. Consider being present in live servers or setting up error logging so you can investigate as in when you get a data loss report with an error message on hand to work with.
I will try your suggestion to replace saveDataStore:SetAsync(userID,saveData) to saveDataStore:UpdateAsync(userID,saveData) and see what happens next. I also want to add that based on my game stats, it has devices (mostly mobile phones) in filtered devices which has some percentages of crash rate but I am not sure if this crash causes data loss. I have been playing and testing my game on live servers for several times and to this date, I have never lost a stat so it is hard for me to figure out right now. I am waiting for other suggestions that may help, Thankyou!
Can’t switch functions like that. UpdateAsync takes a function call as its second argument and its called with the data already written to the key as a parameter. UpdateAsync is not a drop-in replacement for SetAsync, you will have to change a bit of your structuring there.
Ideally device crashes shouldn’t cause data loss unless they’re preventing PlayerRemoving from getting fired which in that case you may want to look into creating an autosave implementation. It’s not a surefire resolution to data loss but it can mitigate a good number of cases if indeed device crashes are the source of data loss. I’d wager it’s something different but I don’t have analytics or insight on your experience to know that for sure so I can only make assumptions.
Yeah, my bad on the part of UpdateAsync. I will read it to understand how it works. I also have an assumption but not sure, it could be the stats are not properly loaded yet their device has crashed and it fires the PlayerRemoving and saved 0 value to each stat. If this may happens, I am thinking of adding an event to fire to the client that their stats are now loaded and the client will also fire an event on the server and under the on server event will be the player removing. I am not sure if this idea is possible.