local function saveData(plr)
local tableToSave = {
plr.leaderstats.Wins.Value,
plr.leaderstats.Streaks.Value,
plr.Values.Coins.Value
}
local success, err
local n = 0
while not success do
if n > 0 then
print("Retrying")
wait(1)
end
success, err = pcall(function()
dataStore:SetAsync(plr.UserId, tableToSave)
end)
n += 1
end
if success then
print("Data has been saved!")
end
end
The function is consistently called when the player leaves or when the server shuts down, but sometimes the data is failing to save and does not print any outputs compared to when it succeeds, which will print âData has been saved!â. Interestingly whenever it fails, it does not show the disconnecting message that usually prints when I stop testing in Studio.
If you test it in studio, most likely these events wouldnât call, or data store cannot respond.
If you test it in a game, itâs more accurate. I got this issue when I first try using data store, and the time it worked when I test it in a real game.
Iâve never had issues with Studio on a case where I wasnât doing something wrong. The only big difference between studio and client is that on the actual game, requests to datastores should error less commonly and that requests are way quicker. I believe thatâs because Roblox servers have more direct access to datastores.
With that said, I believe this is an issue on this personâs BindToClose, so showing it would be useful.
The BindToClose and PlayerRemoving event fires as normal in studio, and the function is called without erroring, whilst the issue occurs at the loop/pcall, seemingly yielding. However after I have tested in game, the data does save for some reason.
game.Players.PlayerRemoving:Connect(function(plr)
local success, err = pcall(function()
wait() -- delay for value changes
saveData(plr)
end)
end)
game:BindToClose(function()
print("Server Closing!")
for _, plr in pairs(game.Players:GetPlayers()) do
local success, err = pcall(function()
coroutine.wrap(saveData)(plr)
end)
end
end)
Yep, like I said, BindToClose isnât set up properly.
Something like this instead should work. Btw task.spawn is just a better coroutine.wrap.
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
game:BindToClose(function()
local leftToSave = 0
for _, player in ipairs(Players:GetPlayers()) do
task.spawn(function()
leftToSave += 1
saveData(player)
leftToSave -= 1
end)
end
while leftToSave > 0 do
RunService.Heartbeat:Wait() -- you can also use task.wait(), but don't use wait() đĄđĄ
end
end)
BindToClose handlers should yield until whatever theyâre doing is finished, thatâs why they exist, to prepare for a server being shutdown and end everything properly. The server only actually shuts down once all :BindToClose calls are finished, or after 30 seconds.
Another tip I have for you, keep a table with all the players that have data loaded, and only save the data from the players inside that table.
When you begin to save their data, remove that player from that table.
This would help with not saving empty data in case a player ends up not loading properly, or fast enough.
About that, this post should help with that in specific.