local ds = game:GetService("DataStoreService")
local cash = ds:GetDataStore("") -- left blank for security reasons
game.Players.PlayerAdded:Connect(function(plr)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = plr
local coins = Instance.new("IntValue")
coins.Parent = leaderstats
coins.Name = "Coins"
if cash:GetAsync(plr.UserId) == nil then
coins.Value = 0
cash:SetAsync(plr.UserId, coins.Value)
else
coins.Value = cash:GetAsync(plr.UserId)
end
end)
game.Players.PlayerRemoving:Connect(function(plr)
local success, err = pcall(function()
cash:SetAsync(plr.UserId, plr.leaderstats.Coins.Value)
end)
if success then
print(success)
else
warn(err)
end
end)
This is my DataStore which I made. I spent half an hour writing and learning the code, but suddenly it does not work. When it fails to save the coins, I get no error. I really need some help.
Hey there. I threw your code into a place and found it to be working perfectly as intended. I’ve heard that sometimes PlayerRemoving will fail to fire if a player crashes, or you may have issues saving when a game shuts down if you don’t account for it. So here’s how I would modify your code to be more resilient.
local ds = game:GetService("DataStoreService")
local cash = ds:GetDataStore("MyDataStore")
local AUTOSAVE_INTERVAL = 120
local function savePlayerData(plr)
local success, err = pcall(function()
cash:SetAsync(plr.UserId, plr.leaderstats.Coins.Value)
end)
if success then
print(success)
else
warn(err)
end
end
local function playerAdded(plr)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = plr
local coins = Instance.new("IntValue")
coins.Name = "Coins"
if cash:GetAsync(plr.UserId) == nil then
coins.Value = 0
cash:SetAsync(plr.UserId, coins.Value)
else
coins.Value = cash:GetAsync(plr.UserId)
end
coins.Parent = leaderstats
-- autosave
delay(AUTOSAVE_INTERVAL, function()
while plr and plr.Parent do
savePlayerData(plr)
wait(AUTOSAVE_INTERVAL)
end
end)
end
game.Players.PlayerAdded:Connect(playerAdded)
game.Players.PlayerRemoving:Connect(savePlayerData)
-- make sure all players save before the server shuts down
game:BindToClose(function()
for _, plr in pairs(game.Players:GetPlayers()) do
savePlayerData(plr)
end
end)
BTW- there’s no reason for you to block out your DataStore name. We can’t do anything with it
There are a lot of issues here that I can see from just taking a glance. Most importantly your GetAsync() should be wrapped using a pcall. You face the risk of data wipes if GetAsync() fails which is a serious concern your current implementation does not take into consideration. Also, do not spam :GetAsync() and :SetAsync() functions. You are going to throttle DataStore limits very quickly that way.
if cash:GetAsync(plr.UserId) == nil then
coins.Value = 0
cash:SetAsync(plr.UserId, coins.Value)
else
coins.Value = cash:GetAsync(plr.UserId)
end
This is a great point as well that I missed. An easy fix to prevent data corruption is to not parent the coins value to leaderstats until after you’ve confirmed GetAsync ran without error. This might cause issues for that player, but it’ll prevent data loss. Ideally you want to continuously re-try GetAsync if it fails. I’ve edited my code example above with the easier fix
Thanks! I got one last question though. Is there a way to retrieve wiped datastore information, if not, should I save all my data to a database in case of an attack or function fail?
No, unless you have a backup copy stored somewhere else. Wipe the data once and it’s gone.
There are other avenues you can take such as using DataStore2, but, honestly, they aren’t necessary as long as you write your code properly with security in mind.
That’s because studio closes so quickly that it doesn’t have time to save. Though, I have tried holding down the stop button and it will sometimes work.