Leaderstat values not loaded in, resulting in points folder showing zero

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:
image

described problem:
image

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?

Have you viewed the output to check if the player’s data successfully saved/loaded?

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.

appears to be good way to deal with the problem. I will try this and observe how it goes.

1 Like

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.

1 Like