One datastore for multiple leaderboards?

Im making a level-based game in which u can speedrun those levels and save them to a global leaderboard. However, the script I’m using right now works only for 1 level’s leaderboard and I don’t want to create 30 different scripts for 30 levels but im not sure how I can modify this one script to handle every leaderboard. Here is the code:

local datastoreservice = game:GetService("DataStoreService")
local Players = game:GetService("Players")

local savetime = game.ReplicatedStorage.SaveTime
local gltimes = {}

local SpeedrunTimes = datastoreservice:GetOrderedDataStore("speedruntimes")


savetime.OnServerEvent:Connect(function(player, save, level)
	if save == true then
		gltimes[player.UserId] = player.playertimevalue.Value
		player.playertimevalue:Destroy()
	else
		player.playertimevalue:Destroy()
	end
end)

local function update()
	local success, err = pcall(function()
		local Data = SpeedrunTimes:GetSortedAsync(true, 10)
		local TimesPage = Data:GetCurrentPage()
		
		for rank, data in ipairs(TimesPage) do
			local username = Players:GetNameFromUserIdAsync(tonumber(data.key))
			local name = username
			local Time = data.value
			local onLB = false
			for i, v in pairs(game.Workspace.Leaderboards.Leaderboard1.SurfaceGui.ScrollingFrame:GetChildren()) do
				if v.ClassName == "Frame"  then
					if v.Player.Text == name  then
						onLB = true
						break
					end
				end

			end
			if Time and onLB == false then
				local newLB = game.ReplicatedStorage:WaitForChild("Sample"):Clone()
				newLB.Player.Text = name
				newLB.Time.Text = Time/1000
				newLB.Position = UDim2.new(0,0,.5,0)
				newLB.Parent = game.Workspace.Leaderboards.Leaderboard1.SurfaceGui.ScrollingFrame
			end
			
		end
	end)
	if success then
		print("success")
	else
		error(err)
	end

end

while true do
	for _, player in pairs(game.Players:GetPlayers()) do
		if gltimes[player.UserId] ~= nil then
			SpeedrunTimes:SetAsync(player.UserId, gltimes[player.UserId]*1000)
		end
	end
	
	for _, frame in pairs(game.Workspace.Leaderboards.Leaderboard1.SurfaceGui.ScrollingFrame:GetChildren()) do
		if frame.ClassName == "Frame" and frame.Player.Text ~= "Player" then
			frame:Destroy()
		end
	end

	update()
	
	wait(20)
end

So assuming I have the level in which the player speedran and the time they got is there any way to modify this script to handle every leaderboard?

You can’t save tables on OrderedDatastores so there’s no other way to do it. If Roblox added a method to get ordered lists from normal datastores it would be possible but simply is not at the moment.

Well, I could save it all as one string value then split it up inside but from inside would it be possible to handle all the leaderboards?

{5.06-1,6.98-2,3.47-3,4.24-4} and so on

A OrderedDataStore is essentially a GlobalDataStore with the exception that stored values must be positive integers. It exposes a method OrderedDataStore:GetSortedAsync() which allows inspection of the entries in sorted order using a DataStorePages object.

OrderedDataStore

Best thing I could think of would be having a function return an ordered datastore based on key.
make a table of keys and put it on a for loop and based on the loop create the leaderboard.

local keys = {"Key1", "Key2", "Key3", "Key4"}

function getDataStore(key)
    return datastoreservice:GetOrderedDataStore(key)
end

for index, key in pairs(keys) do
    local leaderboard  = getDataStore(key)

    
    -- do leaderboard stuff
end

Of course it’s gonna be much more complicated that than. But yeah you can’t store strings or table in OrderedDataStore you can only store Positive Integers.

1 Like

Sorry I meant as one string so it would be “4.56-1,3.56-1,7.65-3” and so on not as a table. Also I’m receiving that data In the same script so I don’t have to send it through the data store I can just access it either way.