I’m working on a DataStore. I have two games and I coded their DataStores in the same way. But the problem is here; I always get data loss reports in one game (about 10-15 people per month). The only difference is that there is more data in that game.
I leave the necessary parts of the code down below. I would be very happy if you could tell me where I made a mistake, or what I need to optimize. Thank you! (Please do not recommend the DataStore2 method, because the DataStore I’ve already written works good in my other game)
(“PlayerSave” is a folder with all the values)
local Data = game:GetService("DataStoreService"):GetDataStore("Data")
--PUBLISH PROJECT TO ACCESS DATASTORE!
function loadSave(plr)
local XP = game.ReplicatedStorage[plr.Name].XP
local Number = game.ReplicatedStorage[plr.Name].Number
local Inventory = game.ReplicatedStorage[plr.Name].Inventory
--Stats
local Goals = game.ReplicatedStorage[plr.Name].Goals
local Assists = game.ReplicatedStorage[plr.Name].Assists
local AccuratePasses = game.ReplicatedStorage[plr.Name].AccuratePasses
local SavedItems = Data:GetAsync(plr.UserId)
if SavedItems then
XP.Value = SavedItems.XP
Number.Value = SavedItems.Number
Inventory.Value = SavedItems.Inventory
--Stats
Goals.Value = SavedItems.Goals
Assists.Value = SavedItems.Assists
AccuratePasses.Value = SavedItems.AccuratePasses
end
end
game.Players.PlayerAdded:Connect(function(plr)
local success, message = pcall(function()
game:WaitForChild("ReplicatedStorage")
game.ReplicatedStorage:WaitForChild("PlayerSave")
if game.ReplicatedStorage:FindFirstChild(plr.Name) ~= nil then
game.ReplicatedStorage:FindFirstChild(plr.Name):Destroy()
end
local Folder = game.ReplicatedStorage.PlayerSave:Clone()
Folder.Parent = game.ReplicatedStorage
Folder.Name = plr.Name
game.ReplicatedStorage:WaitForChild(plr.Name)
loadSave(plr)
end)
if success then
warn("DataStore Loaded!")
else
warn("DataStore Error While Loading!")
wait(7)
warn("DataStore: Retrying...")
local success, message = pcall(function()
loadSave(plr)
end)
if not success then
warn("DataStore Error While Loading!")
wait(7)
warn("DataStore: Retrying...")
loadSave(plr)
end
end
end)
game.Players.PlayerRemoving:Connect(function(plr)
game:BindToClose(function()
if game:GetService("RunService"):IsStudio() then
return
end
local Saving
local PGoals
local NewData = false
local success, message = pcall(function()
Saving = {
["XP"] = game.ReplicatedStorage:FindFirstChild(plr.Name).XP.Value;
["Number"] = game.ReplicatedStorage:FindFirstChild(plr.Name).Number.Value;
["Inventory"] = game.ReplicatedStorage:FindFirstChild(plr.Name).Inventory.Value;
--Stats
["Goals"] = game.ReplicatedStorage:FindFirstChild(plr.Name).Goals.Value;
["Assists"] = game.ReplicatedStorage:FindFirstChild(plr.Name).Assists.Value;
["AccuratePasses"] = game.ReplicatedStorage:FindFirstChild(plr.Name).AccuratePasses.Value;
}
local SavedItems = Data:GetAsync(plr.UserId)
if SavedItems == nil then
NewData = true
end
if SavedItems then
if SavedItems.Goals ~= nil then
PGoals = SavedItems.Goals
else
NewData = true
end
end
end)
if success then
if game.ReplicatedStorage:FindFirstChild(plr.Name) ~= nil then
if NewData == true then
Data:SetAsync(plr.UserId,Saving)
warn("DataStore Saved!")
else
if PGoals ~= nil then
if PGoals ~= "" then
if game.ReplicatedStorage:FindFirstChild(plr.Name).Goals.Value >= PGoals then
Data:SetAsync(plr.UserId,Saving)
warn("DataStore Saved!")
end
end
end
end
end
else
warn("DataStore Error While Saving!")
end
end)
end)
This is by far one of the best resources for this kind of thing. Read up on it, it’s super useful. Just get the existing data and convert it to DataStore2. Check if a save doesn’t exist in order to convert, so you don’t get caught in an endless loop of updating to your old data. (You can just do :DeleteAsync() also.)
Thanks but please do not recommend the DataStore2 method, because the DataStore I’ve already written works actively, and working good on my other game. (As written above)
It would probably be helpful if you knew what error the pcall is giving. You could either have the pcall displayed on the clients screen when the data is auto saved or you can send the error to a discord webhook with the player name and the data if you want. Just be sure not to spam the discord webhook.
Why are you using GetAysnc when the player is leaving? i think it would be better to call that once, when the player joins. if you needed a way to check if a player has new data you should use UpdateASync() as it returns the previously stored data and allows you to update it at the same, furthermore adding a BindtoClose (as kind of mentioned above) and placing a wait inside should make the server wait (given amount, max is 30secs ) before fulling closing, thus allowing time for all players data to save( in theory) , here’s what i mean:
game:BindToClose(function()---Fired when the server is about to close
wait(10) -----wait
print("ServerClosing")
end)
I added BindtoClose() to the code but data loss problem persists. And UpdateASync() is not working on this situation. So I have to use SetASync() for now. (PlayerRemoving function)
I’m using GetAysnc to check data, it’s like; if one of player data is less than saved data, don’t save.
What do you mean UpdateAsync() is not working in this situation? From past experience, that would suggest an issue with values, not the actual saving/loading.
What if there is all of that values are strings, which is you can’t use UpdateAsync()? I want that solution actually. There must be a solution about that.
You can use UpdateAsync for anything that set Async can save as well, so you can save strings using it For example: (using your set-up)
(this is just some quick pseudo code, you probably should modify it)
local success, message = pcall(function()
DataStore:UpdateAsync(PlayerKey, function(oldData)
if oldData == nil then
return Saving ----returns saving, (table)
else
--Save other data using return
end
end)
end
end
If the game shuts down unexpectedly the data will not save. The reason is because the BindToClose function will not work if it is in the PlayerRemoving Function. PlayerRemoving does not fire if the server unexpectedly shuts down. If I were you I would create a save function(Be sure to put pcalls and if you could DataStore the pcall errors and check them that would probably give you the answer to Data Loss). Like so
function saveData(plr)
--Code to save
end
Then you call this function to Save Data when player is leaving.