Hello. I have the following script in ServerScriptService, that adds and manages leaderstat for a player joining the game, and saves data for players leaving the game or when a server shuts down.
-- Assigning variables
local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetOrderedDataStore("RatedPoints")
-- Function to save data
local function saveData(player)
local pointsValue = player.leaderstats and player.leaderstats:FindFirstChild("Points") and player.leaderstats.Points.Value
if pointsValue == nil then
warn("Points value is nil for player " .. player.Name)
return
end
local success, err = pcall(function()
dataStore:UpdateAsync(player.UserId, function(oldData)
-- Update points
return pointsValue
end)
end)
if success then
print("Data has been saved for player " .. player.Name)
else
print("Data not saved for player " .. player.Name)
warn(err)
end
end
game.Players.PlayerAdded:Connect(function(player)
-- Assigning player stats
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Points = Instance.new("IntValue")
Points.Name = "Points"
Points.Parent = leaderstats
-- Load data
local success, data = pcall(function()
return dataStore:GetAsync(player.UserId)
end)
if success and data then
Points.Value = data
else
print("The player " .. player.Name .. " has no data or there was an error loading data!")
if not success then
warn(data)
end
end
end)
-- Player removing event
game.Players.PlayerRemoving:Connect(function(player)
saveData(player)
end)
--Game close
game:BindToClose(function()
for _, player in pairs(game.Players:GetPlayers()) do
saveData(player)
end
task.wait(4)
end)
--For studio testing
if game:GetService("RunService"):IsStudio() then
game:BindToClose(function()
task.wait(4)
end)
end
However, every once in a while some players will come to me and goes “what did you do to my data im reporting this crap game” because their leaderstats didn’t load in and resulted in points showing 0 in leaderstat when the datastore stored a different amount of point (e.g. 45). This meant that if the player leaves the session where they get 0 on the leaderstat, they are going to live on with all the points wiped out, because the script saves whatever is on the leaderstat at the time of leaving.
expected behaviour:
described problem:
Currently, I have tried to use WaitForChild() on the leaderstat folder as suggested on this post, however it still happens every now and then (just less frequently) so I didn’t opt to use it.
How should I modify my script/datastore/saving method so that it eliminates the chances of loading failure on the leaderstat?
Although I didn’t see the output at the time of data losses from the players in question, but data are said to be correctly loaded and saved as per my observation from the past 15 minutes or so in a live server
From what I know saving is mostly okay, but the problem occured during loading
I’m not so sure about elimination, since DataStores are dependent on network, so there’s always a chance of failure.
The best solution would be to kick your Player here, instead of just warning in the console. You can create any sort of Value object (BooleanValue, etc,) and parent it to the character to indicate whether the variable success is true or false, and skip saving data if it’s false.
It takes some time to observe the data loss problem, so while that is in progress, I tried another approach which I think could work equally well, is to not modify the player’s data if their leaderstat value is 0 at the time of saving due to whatever reasons. This is the script I got to work for this approach, derived from the original script:
local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetOrderedDataStore("RatedPoints")
-- Function to save data
local function saveData(player)
local pointsValue = player.leaderstats and player.leaderstats:FindFirstChild("Points") and player.leaderstats.Points.Value
if pointsValue == nil or pointsValue == 0 then
print("Points value is zero or nil for player " .. player.Name .. ", data not saved.")
return
end
local success, err = pcall(function()
dataStore:UpdateAsync(player.UserId, function(oldData)
-- Update points only if they are greater than zero
if pointsValue > 0 then
return pointsValue
else
return oldData -- Return the old data to avoid overwriting with zero
end
end)
end)
if success then
print("Data has been saved for player " .. player.Name)
else
print("Data not saved for player " .. player.Name)
warn(err)
end
end
game.Players.PlayerAdded:Connect(function(player)
-- Assigning player stats
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Points = Instance.new("IntValue")
Points.Name = "Points"
Points.Parent = leaderstats
local success, data = pcall(function()
return dataStore:GetAsync(player.UserId)
end)
if success and data then
Points.Value = data
else
print("The player " .. player.Name .. " has no data or error")
if not success then
warn(data)
end
end
end)
-- Player removing event
game.Players.PlayerRemoving:Connect(function(player)
saveData(player)
end)
-- Game close
game:BindToClose(function()
for _, player in pairs(game.Players:GetPlayers()) do
saveData(player)
end
task.wait(4)
end)
-- For studio testing
if game:GetService("RunService"):IsStudio() then
game:BindToClose(function()
task.wait(4)
end)
end
However, it seems that although the data is ignored when the leaderstat.Points is 0 and the print stated that the saving did not proceed, the value in the datastore still updated to 0 and the next time I join the game, the data is lost. what seem to be the problem here?
Just realised that you’re using OrderedDatastores, which makes :UpdateAsync() useless as you can’t even compare values with OrderedDatastores. You can just try to use :SetAsync() to simplify things.
You seem to be referring to multiple instances in a single variable? That return statement only seems to break from the if statement, not the function.
There”s also kind of a major flaw with your theory. If your DataStore fails to load and your Player tries to increase their Points value when their original stat doesn’t load, wouldn’t that also result in data loss at the end of the day?
Yeah you are right, I was working overtime at that point and I do not know what was on my mind
But thank you for your kind assistance anyways, I have stopped using point system in my game, as maintaining datastores is severely holding back some other more major gameplay fixes and updates.