So, I had a DataStore system in my game, which was working fine. Until today, when I tested to see if the in-game currency that I made would save, it didn’t. I looked at a few posts regarding this same issue, but none of the answers worked for me. Here’s the Data Store script im using.
(P.S. yes, api services are enabled, I double checked that)
local DataStoreService = game:GetService("DataStoreService")
local PlayerCash = DataStoreService:GetDataStore("PlayerCash")
function OnPlayerAdded(player)
local stats = Instance.new("Folder", player)
stats.Name = 'leaderstats'
local Cash = Instance.new("NumberValue", stats)
Cash.Name = "Credits"
Cash.Value = 0
local data
local success, err = pcall(function()
data = PlayerCash:GetAsync(tostring(player.UserId))
end)
if success then
print("Data loaded!")
if data then
Cash.Value = data
end
else
print("There was an error while getting data of player " .. player.Name)
warn(err)
end
end
function OnPlayerRemoving(player)
local success, err = pcall(function()
PlayerCash:UpdateAsync(player.UserId, player.leaderstats:FindFirstChild("Credits").Value)
end)
if success then
print("Data saved!")
else
print("There was an error while saving data of player " .. player.Name)
warn(err)
end
end
game.Players.PlayerAdded:Connect(OnPlayerAdded)
game.Players.PlayerRemoving:Connect(OnPlayerRemoving)
Oo… I looked up UpdateAsync() and you need to provide it with a function, not a value , so you should use SetAsync() instead, or make it a function. Using UpdateAsync() is only really needed if more than one server will be changing the value at a time, which probably won’t be the case here. Here is an article explaining how to use UpdateAsync().
Although kosava solved the main problem, there are still flaws in your code.
You don’t check for already loaded players (which means there is a chance the player’s data will not load)
You don’t manage BindToClose, which is fired whenever your game shuts down.
You don’t retry any of the DataStore calls (GetAsync, UpdateAsync) whenever failed.
In onPlayerRemoving, FindFirstChild for the leaderstats folder seems redundant
5. MAJOR MAJOR PROBLEM!! Your DataStore should be saved as a table so that you can add multiple values to it, not only cash. If players have already had dataStores, then you’re going to have to migrate your current data stores.
The code below solves problems 1 and 2:
local function onPlayerAdded(player)
-- dataStore loading code
end
local function onPlayerRemoving(player)
-- dataStore saving code
end
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(onPlayerAdded)(player)
end
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
game:BindToClose(function()
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(onPlayerRemoving)(player)
end
end)
I’m not sure what you mean, but this is how roblox does their retrying code (on the wiki):
local tries = 0
local success
repeat
tries = tries + 1
success = pcall(function()
playerData:SetAsync(playerUserId, DATA_HERE)
end)
if not success then wait(1) end
until tries == 3 or success
if not success then
warn("Cannot save data for player!")
end
Alright, tried my best to implement it into my code. I ended up with:
local tries = 0
local function onPlayerRemoving(player)
repeat
tries = tries + 1
local success, err = pcall(function()
PlayerCash:SetAsync(tostring(player.UserId), player.leaderstats.Credits.Value)
end)
if success then
print("Data saved!")
else
print("There was an error while saving data of player " .. player.Name)
warn(err)
end
until tries == 3 or success
end
Late reply to this thread, but how exactly do I implement a table into a DataSave? I don’t use tables often nor do I script DataSaves often, so I’m just wondering.