So occasionally people seem to lose all their data in my game. I made a previous post but it was about the different methods…
Right now this is what I have for my code.
player joins:
game.Players.PlayerAdded:Connect(function(player)
local success,data = pcall(function()
return Data:GetAsync(prefix .. tostring(player.UserId))
end)
if success then
if data then
local plrData = Data:GetAsync(prefix .. tostring(player.UserId))
print("loading in data")
Coin.Value = plrData[1] or 0
xp.Value = plrData[2] or 0
Level.Value = plrData[3] or 1
-- weapons
weapons.Axe.Owns.Value = plrData[4] or 0
weapons.Sabre.Owns.Value = plrData[5] or 0
weapons.Rifle.Owns.Value = plrData[6] or 0
weapons.Musket.Owns.Value = plrData[7] or 1
weapons.Horse.Owns.Value = plrData[8] or 0
weapons.Flintlock.Owns.Value = plrData[9] or 0
weapons.Carbine.Owns.Value = plrData[10] or 0
weapons.Lance.Owns.Value = plrData[11] or 0
weapons.Bandage.Owns.Value = plrData[12] or 0
else
print("no data")
Level.Value = 1
weapons.Musket.Owns.Value = 1
Data:SetAsync(prefix .. tostring(player.UserId), {
Coin.Value,
xp.Value,
Level.Value,
weapons.Axe.Owns.Value,
weapons.Sabre.Owns.Value,
weapons.Rifle.Owns.Value,
weapons.Musket.Owns.Value,
weapons.Horse.Owns.Value,
weapons.Flintlock.Owns.Value,
weapons.Carbine.Owns.Value,
weapons.Lance.Owns.Value,
weapons.Bandage.Owns.Value
})
end
else
print("Data store working, but no data ever made for this player")
end
end)
function saveData(player)
local playerStats = game.ServerStorage.PlayerStats[player.UserId]
local pfolder = game.ServerStorage.PlayerStats:FindFirstChild(player.UserId)
local spfolder = game.ReplicatedStorage.PlayerStats:FindFirstChild(player.UserId)
local weapons = playerStats:WaitForChild("Owned")
local tries = 0
local success
repeat
tries = tries + 1
success = pcall(function()
--print("saved")
Data:SetAsync(prefix .. tostring(player.UserId), {
playerStats.Coin.Value,
playerStats.xp.Value,
playerStats.Level.Value,
weapons.Axe.Owns.Value,
weapons.Sabre.Owns.Value,
weapons.Rifle.Owns.Value,
weapons.Musket.Owns.Value,
weapons.Horse.Owns.Value,
weapons.Flintlock.Owns.Value,
weapons.Carbine.Owns.Value,
weapons.Lance.Owns.Value,
weapons.Bandage.Owns.Value
})
wait(2)
if spfolder ~= nil then
spfolder:Destroy()
end
if pfolder ~= nil then
pfolder:Destroy()
end
end)
if not success then wait(1) end
until tries == 3 or success
if not success then
warn("Cannot save data for player!")
end
end
game:BindToClose(function()
for _, client in ipairs(game:GetService("Players"):GetPlayers()) do
spawn(function()
saveData(client)
end)
end
end)
game.Players.PlayerRemoving:Connect(function(player)
saveData(player)
end)
I also have an autosave every 2 minutes, but I’m disabling that for now.
Your problem is that your datastore is maxing out the allowed save requests. I would recommend only saving when the players data changes. Also change your data to be in tables as right now each line is saving as a different datastore.
I always have 240 available requests but dataloss still happens.
I feel like datastores are generally unreliable. Sometimes they just don’t work, othertimes they take over a minute to process.
Kick a player if he fails to load (or atleast retry to load).
Don’t allow a player who’s failed to load inventory join because when he leaves he’ll override his actual saved inventory and loose stuff.
Use serverchat to see if a player is currently being saved on another server.
If so, do not allow him to load until it’s saved. To be safe just kick him when he tries to load.
Using too many requests where not necessary. You fetch player data twice; once in the pcall and another time right below it. You use SetAsync when a player has no data, through an auto save loop, on BindToClose and PlayerRemoving. Most code is shoved into pcalls when you should only be having DataStore requests in the pcalls. In the first pcall, you treat a success false as “DataStore working” when that is actually the opposite of what is happening. You have a retry function despite DataStores supporting this natively.
I’d say you have quite a bit of refactoring to do.
game:BindToClose(function()
for _, client in ipairs(game:GetService("Players"):GetPlayers()) do
spawn(function()
saveData(client)
end)
end
end)
The way you wrote this BindToClose, it will return immediately. And once the BindToClose returns, the game will shut down. That means those saveData calls in it probably aren’t happening at all. You need to wait until all of those spawned saveData calls complete before returning from the BindToClose hander.
Here is some example code on how to do that: BindToClose & Data Loss Risk - #2 by Tiffblocks, I would follow that because it’s not particularly easy to write that code correctly in a way that handles errors.
Alright, well I had some help from sircfenner and I wanted to break this down step by step.
First apparently, when the data would be found it would be successful, but then I looked for their data again. If there was no data, then I also saved data even if a player’s data never even loaded.
local success,data = pcall(function()
return Data:GetAsync(prefix .. tostring(player.UserId))
end)
if success then
if data then
print("loading in data")
Coin.Value = data[1] or 0
xp.Value = data[2] or 0
Level.Value = data[3] or 1
-- weapons
weapons.Axe.Owns.Value = data[4] or 0
weapons.Sabre.Owns.Value = data[5] or 0
weapons.Rifle.Owns.Value = data[6] or 0
weapons.Musket.Owns.Value = data[7] or 1
weapons.Horse.Owns.Value = data[8] or 0
weapons.Flintlock.Owns.Value = data[9] or 0
weapons.Carbine.Owns.Value = data[10] or 0
weapons.Lance.Owns.Value = data[11] or 0
weapons.Bandage.Owns.Value = data[12] or 0
else
print("no data")
Level.Value = 1
weapons.Musket.Owns.Value = 1
end
else
print("Data store fail!")
end