How to make a simple global leaderboard

It appears that the maxValue variable does not have an effect, I’m trying to make it really high but no matter it, it looks like its capped at 9.22e+18.

Here I’m printing the leaderstat value of coins, the maxValue in your script and the coins value being passed in your script upon being updated (same as leaderstats). Why is it only going to 9.22Qn?

image

When I print the values of coins in the loop that iterates through the data, it returns 9.22e+18 so it seems like the problem is the :GetSortedAsync()? Is there a cap to it? I’ve got it currently set at 10e65 but it doesnt matter what I put it as.

EDIT: Nvm it looks like maxValue is working, but I’m confused as to why it keep resorting to 9.22e+18 in the loop through the data?

local smallestFirst = false--false = 2 before 1, true = 1 before 2
local numberToShow = 100--Any number between 1-100, how many will be shown
local minValue = 1--Any numbers lower than this will be excluded
local maxValue = 10e65--(10^30), any numbers higher than this will be excluded
print('MaxValue: ' .. maxValue)
local pages = dataStore:GetSortedAsync(smallestFirst, numberToShow, minValue, maxValue)
--Get data
local top = pages:GetCurrentPage()--Get the first page
local data = {}--Store new data
for a,b in ipairs(top) do--Loop through data
	local userid = b.key--User id
	local coins = b.value--Coins
	print(coins)
	local username = "[Failed To Load]"--If it fails, we let them know
	local s,e = pcall(function()
		username = game.Players:GetNameFromUserIdAsync(userid)--Get username
	end)
	if not s then--Something went wrong
		warn("Error getting name for "..userid..". Error: "..e)
	end
	local image = game.Players:GetUserThumbnailAsync(userid, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size150x150)
	--Make a image of them
	table.insert(data,{username,coins,image})--Put new data in new table
end

This is the loop I’m talking about, b.value prints 9.22e+18

Forgot about something called data limits lol, what could I do to bypass :GetStoredAsync() 64 bit data limit?

If your game needs to store high value numbers, you can always store it’s power to the 10. For example, 100 would be stored as 2, 10,000 as 4. Since you can’t store decimals, you could also multiply by a precision factor such as 1000 to allow for 3 points of decimal precision. If you need an example look above or if that isn’t enough I can provide a code snippet.

Thank you for the prompt response. If you’d be so kind to provide a snippet. I’m not sure how I would apply this.

I’m trying to abbreviate the number in here:

dataStore:UpdateAsync(plr.UserId,function(oldVal)
	--Set new value
	return Format(tonumber(w), 2) -- K M T Q etc..
end)

However when I try to print coins in the loop through data it doesn’t print. Does it not like strings?

How would I treat numbers like 1e+22 or whatever

Strings cannot be ordered (at least not in the implementation), and so number values are required for OrderedDatastores. To “encode” numbers so that large ones can fit, you can use the following code:

local base = 10
local precision = 10000

local function encode(number)
	return math.floor(math.pow(number, 1 / base) * precision)
end

local function decode(encoded)
	return math.pow(encoded / precision, base)
end

local function test(number)
	local encoded = encode(number)
	local decoded = decode(encoded)
	print(string.format('Original: %f Encoded: %f Decoded: %f', number, encoded, decoded))
end

test(100) -- Original: 100.000000 Encoded: 15848.000000 Decoded: 99.941215
test(1000) --Original: 1000.000000 Encoded: 19952.000000 Decoded: 999.687729
test(10000) --Original: 10000.000000 Encoded: 25118.000000 Decoded: 9996.559632
test(100000000) --Original: 100000000.000000 Encoded: 63095.000000 Decoded: 99988360.393047
test(2846893467) --Original: 2846893467.000000 Encoded: 88193.000000 Decoded: 2846696448.133367

You have to sacrifice precision in order to save larger numbers in the same space, but that won’t be an issue if you just want to prefix the first few numbers. This is the only soultion for OrderedDatastores.

The greater the base, the larger numbers you can store. The higher the precision, the smaller numbers you can store. Find a balance that works best for your game.


As a side note, I’d recommend editing your previous replies instead of posting new ones to help reduce clutter.

3 Likes

So for somewhat reason every time a player joins the game his money is not zero and the leaderboard is monthly.

How did you modify the source code? This is likely due to something you did, as the leaderboard by itself still works completely as expected. Also, money is not something set by the global leaderboard.

I just wrote down the code everything works fine, but it wont be monthly like the leaderboard. It is showing my coins I have, but the thing is I want it to be at zero

Do you want it to be monthly or to not be monthly? I’m confused as to what you want here. The leaderboard, by default, is not monthly. For it to be monthly, see the FAQ.

To make it work as a monthly leaderboard u will have to reset the datastore every month, not manually though. u can add a script in it to make it work.
you can maintain multiple datastore to do so, so that you also have a global leaderboard in case u need both.

I did a all time leaderboard on my game

I tried to make copies of a main leaderboard and then copy it to the secondary ones, but when the place is loaded, the secondary boards seem to receive the content very slowly.

This is the single part where I changed the script:

for number,d in pairs(data) do--Loop through our new data
		local name = d[1]
		local val = d[2]
		local image = d[3]
		local color = Color3.new(1, 1, 1)--Default color
		if number == 1 then
			color = Color3.new(1, 0, 0)--1st place color
		elseif number == 2 then
			color = Color3.new(1, 0.854902, 0.109804)--2nd place color
		elseif number == 3 then
			color = Color3.fromRGB(255, 158, 21)--3rd place color
		end
		local new = sample:Clone()--Make a clone of the sample frame
		new.Name = name--Set name for better recognition and debugging
		new.LayoutOrder = number--UIListLayout uses this to sort in the correct order
		new.Image.Image = image--Set the image
		new.Image.Place.Text = number--Set the place
		new.Image.Place.TextColor3 = color--Set the place color (Gold = 1st)
		new.PName.Text = name--Set the username
		val = MoneyLib.HandleMoney(val)
		new.Value.Text = val--Set the amount of points
		new.Value.TextColor3 = color--Set the place color (Gold = 1st)
		new.PName.TextColor3 = color--Set the place color (Gold = 1st)
		new.Parent = sf--Parent to scrolling frame

		--Trying to copy the main leaderboard to the secondary ones
		for i, list in pairs(workspace.LeaderBoards.SecondaryLeaderboards:GetChildren()) do
			list.CashBoard.Leader.SurfaceGui.ScrollingFrame:Destroy()
			local clone = sf:Clone()
			clone.Parent = list.CashBoard.Leader.SurfaceGui
		end
	end

Any ideas on how to make this work? I feel like the lines where I implemented the copying is not the right place, but I couldn’t find where else to make it.

It’s hard to tell when you’ve removed a chunk of the original code and I don’t know how your object hierarchy looks. My best bet would be testing and seeing if it gets created and where.

I didn’t include the rest of the code because it is exactly the same as the original one with the single change made being the addition of the four lines that are copying it. I thought it was reductant to include it.

However, this is the full code of the cash board:

local sg = script.Parent
local sample = script:WaitForChild("Sample") --Our Sample frame
local sf = sg:WaitForChild("ScrollingFrame") --The scrolling frame
local ui = sf:WaitForChild("UI") --The UI list layout

local MoneyLib = require(game:GetService("ReplicatedStorage").MoneyLib)
local dataStoreService = game:GetService("DataStoreService")
--The data store service
local dataStore = dataStoreService:GetOrderedDataStore("CashBoard")
--Get the data store with key "Leaderboard"

wait(10)
while true do
	for i,plr in pairs(game.Players:GetChildren()) do--Loop through players
		if plr.UserId>0 then--Prevent errors
			local w = math.floor(--[[Value that I count for the cash]])
			if w then
				pcall(function()
					--Wrap in a pcall so if Roblox is down, it won't error and break.
					dataStore:UpdateAsync(plr.UserId,function(oldVal)
						--Set new value
						return tonumber(w)
					end)
				end)
			end
		end
	end    
	local smallestFirst = false--false = 2 before 1, true = 1 before 2
	local numberToShow = 100--Any number between 1-100, how many will be shown
	local minValue = 1--Any numbers lower than this will be excluded
	local maxValue = 10e30--(10^30), any numbers higher than this will be excluded
	local pages = dataStore:GetSortedAsync(smallestFirst, numberToShow, minValue, maxValue)
	--Get data
	local top = pages:GetCurrentPage()--Get the first page
	local data = {}--Store new data
	for a,b in ipairs(top) do--Loop through data
		local userid = b.key--User id
		local points = b.value--Points
		local username = "[Failed To Load]"--If it fails, we let them know
		local s,e = pcall(function()
			username = game.Players:GetNameFromUserIdAsync(userid)--Get username
		end)
		if not s then--Something went wrong
			warn("Error getting name for "..userid..". Error: "..e)
		end
		local image = game.Players:GetUserThumbnailAsync(userid, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size150x150)
		--Make a image of them
		table.insert(data,{username,points,image})--Put new data in new table
	end
	ui.Parent = script
	sf:ClearAllChildren()--Remove old frames
	ui.Parent = sf
	for number,d in pairs(data) do--Loop through our new data
		local name = d[1]
		local val = d[2]
		local image = d[3]
		local color = Color3.new(1, 1, 1)--Default color
		if number == 1 then
			color = Color3.new(1, 0, 0)--1st place color
		elseif number == 2 then
			color = Color3.new(1, 0.854902, 0.109804)--2nd place color
		elseif number == 3 then
			color = Color3.fromRGB(255, 158, 21)--3rd place color
		end
		local new = sample:Clone()--Make a clone of the sample frame
		new.Name = name--Set name for better recognition and debugging
		new.LayoutOrder = number--UIListLayout uses this to sort in the correct order
		new.Image.Image = image--Set the image
		new.Image.Place.Text = number--Set the place
		new.Image.Place.TextColor3 = color--Set the place color (Gold = 1st)
		new.PName.Text = name--Set the username
		val = MoneyLib.HandleMoney(val)
		new.Value.Text = val--Set the amount of points
		new.Value.TextColor3 = color--Set the place color (Gold = 1st)
		new.PName.TextColor3 = color--Set the place color (Gold = 1st)
		new.Parent = sf--Parent to scrolling frame
		
		for i, list in pairs(workspace.LeaderBoards.SecondaryLeaderboards:GetChildren()) do
			list.CashBoard.Leader.SurfaceGui.ScrollingFrame:Destroy()
			local clone = sf:Clone()
			clone.Parent = list.CashBoard.Leader.SurfaceGui
		end
		
	end
	wait()
	sf.CanvasSize = UDim2.new(0,0,0,ui.AbsoluteContentSize.Y)
	--Give enough room for the frames to sit in
	wait(120)
end

The frames of every player get created, and they parrent correctly to the scrolling frames of the secondary boards. The problem occurs when the server/map is loading. The main 4 boards receive their content instantly, but the secondary ones receive every frame (of every player on the board) very slowly (I think it is one frame for every 10 seconds).

This is the hierarchy:
image

You’re getting the children of a non-existent (or not shown) TycoonLeaderboards. Assuming it does exist, and follow the same pattern as the rest of them, you seem to index each child directly with CashBoard when you’d need to index with Set1 first.

What exactly is your use case? Is there really no errors? If possible, a place file would help.

Also, it is possible that you might be cloning large copies of instances unintentionally, which would explain the loading issues.

Sorry for the confusion, I corrected the name of the model that their children are indexed.
Set1, Set2, Set3 etc are all identical (they contain the same children). So in

for i, list in pairs(workspace.LeaderBoards.SecondaryLeaderboards:GetChildren()) do
	list.CashBoard.Leader.SurfaceGui.ScrollingFrame:Destroy()
	local clone = sf:Clone()
	clone.Parent = list.CashBoard.Leader.SurfaceGui
end

list is every Set and list.CashBoard refers to every CashBoard in the set.

My use is that I want to have the main 4 leaderboards copied around the map. So every “Set” is a set of copies of the main leaderboards.

I don’t think I can provide a place file atm, but I can edit a new place to resemble my implementation if it helps.

If you’re cloning it after the layout is finished, you should be fine. If not (like you are now), then you will have issues. Check what is actually cloned to see.

1 Like

Oops, I should’ve put it after the for. Now it works, thanks!