Problem with global leaderboard

I made a post (I think yesterday) about my global leaderboard not working, and it got solved but just today it broke again in a different way. The leaderboard has no errors, but for some people it shows double rows
image
I seriously dont understand what is wrong, especially since there are no errors. Here is the code:

--// GENERAL VARIABLES
local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetOrderedDataStore("Wins")

--// UI VARIABLES

local UI = script.Parent.SurfaceGui
local basePlayerFrame = UI.BasePlayerFrame
local boardFrame = UI.ScrollingFrame

--// Functions
local function SaveData()
	for _, player in pairs(game:GetService("Players"):GetPlayers()) do
		if player.UserId < 1 then
			continue -- don't save this info
		end
		local plr_key = "id_"..player.UserId.."_Wins"

		local tokens = player.leaderstats:FindFirstChild("Wins")

		local success, result = pcall(function()
			DataStore:SetAsync(plr_key, tokens.Value)
		end)

		if not success then 
			warn(result)
		end
	end
end

local function getTop50Players()
	local isAscending = false
	local pageSize = 50
	local pages = DataStore:GetSortedAsync(isAscending, pageSize)
	local top50 = pages:GetCurrentPage()
	
	local top = {}
	
	for rank, data in ipairs(top50) do
		local dataName = data.key
		local userId = tonumber(dataName:split('_')[2]) -- it's easier to just have it as its own variable
		if userId < 1 then -- check for valid id
			pcall(function() -- of course in your actual code base, this would be more detailed
				DataStore:RemoveAsync(dataName) -- remove the invalid user from the data store list
			end)
			
			continue -- skip this person, it's not an actual roblox user 
		end

		local name = game:GetService("Players"):GetNameFromUserIdAsync(userId)
		local wins = data.value

		local currentPlayer =  { Player = name, Wins = wins, Rank = rank, }
		table.insert(top, rank, currentPlayer)
	end

	return top
end

local function ClearList()
	task.spawn(function()	
		for _, plrFrame in pairs(boardFrame:GetChildren()) do
			if not plrFrame:IsA("Frame") then continue end
			plrFrame:Destroy()
			task.wait(0.25)
		end
	end)
end

local function UpdateList()
	SaveData()
	ClearList()
	local top50 = getTop50Players()

	task.spawn(function()	
		for _, plr in ipairs(top50) do
			local frame = basePlayerFrame:Clone()
			frame.Parent = boardFrame

			frame.Plr.Text = plr.Player
			frame.Amount.Text = plr.Wins
			frame.Rank.Text = plr.Rank

			frame.Visible = true
			task.wait(0.25)
		end
	end)
end

task.spawn(function()
	while true do
		UpdateList()
		wait(60)
	end
end)
1 Like

I still need help with this, my only idea to solve this would be to reset everyone’s data, which I dont nessesarily think would be good

1 Like

Its just a random thought, don’t know if it would work or wether its even possible. In stead of resetting all data you could just loop over all the players data, place them in a table or something check if they are already in the table. Then afterwards save that as the new datastore.

1 Like

I dont think this would work because a lot of the players who have duplicates dont actually have their correct wins on display

1 Like
local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetOrderedDataStore("Wins")

--// UI VARIABLES
local UI = script.Parent.SurfaceGui
local basePlayerFrame = UI.BasePlayerFrame
local boardFrame = UI.ScrollingFrame

--// Functions
local function SaveData()
	for _, player in pairs(game:GetService("Players"):GetPlayers()) do
		if player.UserId < 1 then
			continue -- don't save this info
		end
		local plr_key = "id_"..player.UserId.."_Wins"

		local tokens = player.leaderstats:FindFirstChild("Wins")

		local success, result = pcall(function()
			DataStore:SetAsync(plr_key, tokens.Value)
		end)

		if not success then 
			warn(result)
		end
	end
end

local function getTop50Players()
	local isAscending = false
	local pageSize = 50
	local pages = DataStore:GetSortedAsync(isAscending, pageSize)
	local top50 = pages:GetCurrentPage()
	
	local top = {}
	
	for rank, data in ipairs(top50) do
		local dataName = data.key
		local userId = tonumber(dataName:split('_')[2]) -- it's easier to just have it as its own variable
		if userId < 1 then -- check for valid id
			pcall(function() -- of course in your actual code base, this would be more detailed
				DataStore:RemoveAsync(dataName) -- remove the invalid user from the data store list
			end)
			
			continue -- skip this person, it's not an actual roblox user 
		end

		local name = game:GetService("Players"):GetNameFromUserIdAsync(userId)
		local wins = data.value

		local currentPlayer =  { Player = name, Wins = wins, Rank = rank, }
		table.insert(top, rank, currentPlayer)
	end

	return top
end

local function ClearList()
	for _, plrFrame in pairs(boardFrame:GetChildren()) do
		if plrFrame:IsA("Frame") then 
			plrFrame:Destroy()
		end
	end
end

local function UpdateList()
	SaveData()
	ClearList()
	local top50 = getTop50Players()

	for _, plr in ipairs(top50) do
		local frame = basePlayerFrame:Clone()
		frame.Parent = boardFrame

		frame.Plr.Text = plr.Player
		frame.Amount.Text = plr.Wins
		frame.Rank.Text = plr.Rank

		frame.Visible = true
	end
end

task.spawn(function()
	while true do
		UpdateList()
		wait(60)
	end
end)
1 Like

I don’t see anything immediately noticable about why it would be duplicating, is it just a visual error? (As in: the player doesn’t have duplicate data, it’s just displaying weirdly on the board)

1 Like

I used this code, and it doesnt change anything

that’s what I’m thinking, mainly though I am just super confused

the reason the variables say tokens is bc I tried copying over the code from my other global leaderboard (which is working just fine)

alr it’s the next day and Ive remade the leaderboard completely because the old one had too many problems, and it works now. thanks for everyone’s help

task.wait(0.25)

I think it should be shorter. While the frames being destroyed, you think they were destroyed. But they still in the process

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.