As what @pwx said, you shouldn't save a value whenever it is changed since you will cause stress to the server (it might break the game) and just save it whenever the player leaves instead.
Also, when using :SetAsync() and :GetAsync(), it might cause errors and eventually break the whole game. To fix this, you need to use a pcall() so that if anything errors, it will be returned by the pcall() and won't be printed in the output (which won't break the game!)
Here's a tip: You don't need to create a DataStore for each value, you can just store them in a table and save the table.
local datastore = game:GetService("DataStoreService")
local ds = datastore:GetDataStore("SaveSystem")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local function waitForRequestBudget(requestType: Enum.DataStoreRequestType)
local currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
while currentBudget < 1 do
currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
task.wait(5)
end
end
local function loadData(player)
local lb = Instance.new("Folder", player)
lb.Name = "leaderstats"
local Kills = Instance.new("IntValue", lb)
Kills.Name = "Kills"
local Cash = Instance.new("IntValue", lb)
Cash.Name = "Cash"
waitForRequestBudget(Enum.DataStoreRequestType.GetAsync)
local success, data = pcall(function()
return ds:GetAsync(player.UserId)
end)
if success and data then
Kills.Value = data.Kills
Cash.Value = data.Cash
else
print("Player " .. player.Name .. " has no data saved.")
warn(data)
end
end
local function saveData(player, dontWait)
local lb = player.leaderstats
local data = {
["Kills"] = lb.Kills.Value,
["Cash"] = lb.Cash.Value
}
local success
repeat
if not dontWait then
waitForRequestBudget(Enum.DataStoreRequestType.UpdateAsync)
end
success = pcall(function()
ds:UpdateAsync(player.UserId, function()
return data
end)
end)
until success
end
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(loadData)(player)
end
Players.PlayerAdded:Connect(loadData)
Players.PlayerRemoving:Connect(saveData)
game:BindToClose(function()
if RunService:IsStudio() then
task.wait(2)
else
local finished = Instance.new("BindableEvent")
local allPlayers = Players:GetPlayers()
local leftPlayers = #allPlayers
for _, player in ipairs(allPlayers) do
coroutine.wrap(function()
saveData(player, true)
leftPlayers -= 1
if leftPlayers == 0 then
finished:Fire()
end
end)()
end
finished.Event:Wait()
end
end)
1 comment
You shouldn't use a .Changed event with SetAsync(), you'll stress out the server and the datastore if it updates too quickly.