How to get past 9.223 quintillion limit in leaderboards?

  1. What do you want to achieve? Keep it simple and clear!
    I want to make a leaderboard that gets past the 9.223 quintillion limit since they are a lot of players that have passed it in my game
  2. What is the issue? Include screenshots / videos if possible!
    I can’t get it to work.
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I tried a solution from dev forum but i didn’t understand it and i tried getting them using the :GetAsync() function

Here is the script:

local DTS = game:GetService("DataStoreService")
local Lb = DTS:GetOrderedDataStore("Lb1")
local DataStore = DataStoreService:GetDataStore("DataStore3")
local function updateLeaderboard()
	local success, errorMessage = pcall(function()
		local Data = Lb:GetSortedAsync(false, 50,0,math.huge)
		local ClicksPage = Data:GetCurrentPage()
		for rank, data in ipairs(ClicksPage) do
			local user = game.Players:GetNameFromUserIdAsync(tonumber(data.key)) 
			local Name = user
			local PlayerUserId = "Player_"..data.key
			local LeaderboardData
			local success, errormessage = pcall(function()
				LeaderboardData = DataStore:GetAsync(PlayerUserId, data)
			end)
			local TimeWasted = math.floor(LeaderboardData.Currency)
			
			local isLeaderboard = false
			for i,v in pairs(game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame:GetChildren()) do
				if v.Player.Text == Name then
					isLeaderboard = true
					break
				end
			end
			if TimeWasted and isLeaderboard == false then
				local newLeaderboard = game.ReplicatedStorage:WaitForChild("ScrollingFrame"):Clone()
				newLeaderboard.Player.Text = Name
				newLeaderboard.Points.Text = TimeWasted
				newLeaderboard.Ranks.Text = "#"..rank
				newLeaderboard.Position = UDim2.new(0,0, newLeaderboard.Position.Y.Scale + (.02 * #game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame:GetChildren()), 0)
				newLeaderboard.Parent = game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame
				if rank == 1 then
					local Description = game.Players:GetHumanoidDescriptionFromUserId(tonumber(data.key))
					local Dummy = workspace:WaitForChild("Dummy")
					Dummy.Humanoid:ApplyDescription(Description)
					newLeaderboard.Player.TextColor3 = Color3.fromRGB(239, 184, 56)
					newLeaderboard.Points.TextColor3 = Color3.fromRGB(239, 184, 56)
					newLeaderboard.Ranks.TextColor3 = Color3.fromRGB(239, 184, 56)
				end
			end
		end
	end)
	if not success then
		warn(errorMessage)
	end
end

while true do
	for _, player in pairs(game.Players:GetPlayers()) do 
		Lb:SetAsync(player.UserId, player.leaderstats.Currency.Value)
	end
	
	for _, frame in pairs(game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame:GetChildren()) do
		frame:Destroy()
	end
	
	updateLeaderboard()
	
	wait(20)
end```
2 Likes

You can’t get past it using numbers, you need to store the value as a string or an array. Once you’ve done this you will need to find your own way to allow players to spend / gain cash.

1 Like

Leaderboards can’t store string values or an array. They can only store number values.

1 Like

OrderedDataStores are limited to 9.223 QN as a max value.

What you could do (might be inaccurate, but its a solution) is save an exclusive value that is equal to their money, but divide it by a large amount (1,000,000 for example). Then, save that in the OrderedDataStore. Once you load the leaderboard, simply multiply what the text displays by 1,000,000, and it would be over that limit.

Since you use such large numbers, 1 Million might be a bit low.

1 Like

No? Leaderstats can display any data type.

He means OrderedDataStores, not leaderstats

Is there any way to do that without having to reset the leaderboard?
Edit: It gives me an error “103: double is not allowed in data stores.” What does it mean?

You can save 2 values, their Money, and their Leaderboard Money. Everytime Money changes, you can set Leaderboard Money equal to Money divided by 1 Million (or whatever works best). Then use that Leaderboard Money for the OrderedDataStore.

It gave me an error when trying your suggestion saying “103: double is not allowed in data stores.” What does it mean?

It means there is a decimal in the number. You can do math.floor() to fix that, but it will be inaccurate.

Dividing by a value will increase your range but it will decrease the accuracy. If you need to retain accuracy you’re going to have to use multiple keys. In the ODS you can store the divided result but after you get the list of, say, the top 10 players, you will have to get their actual value from the DS and the actual value will need to be stored across multiple values so it can reach a value bigger than 9.223 quintillion.

In other words, what you want to do is not entirely trivial. If you can, a better solution might be to make sure reaching such a large number isn’t possible in the first place :smiley:.

1 Like

So what is the solution for passing the 9.223 Quintillion limit?

Better idea.

Save the Leaderboard Money divided by an amount like previously, but instead of putting the Leaderboard Money multiplied on the leaderboard, use their actual Money. The Leaderboard Money can be used to sort, and once everyone is sorted, we don’t need that Leaderboard Money anymore.

Also, I disagree with this. It will fix your issue of Leaderboards, but part of the fun of a game can be how high in numbers you can go. Take Miner’s Haven, where its possible to hit the 1.7e+308 limit. Such a game wouldn’t be possible if you only could get to billions.

The “9.223 quintillion limit” is inaccurate, if you’re storing integers you can go up to 2^53, which is 9.007 quadrillion, which is 9 thousand thousand billion, so you can get well beyond billions safely. But I get your point. Anyways I don’t see how your solution is any different than mine. To hold integers greater than 2^53 you’re going to need to split them up into multiple integers (or use a string) though so on the leaderboard you will have to use a StringValue to display the actual amount (or you can display an approximate amount ig).

There is a simple way to do it
Save your value like that:

math.log10(example.Value+1)*(2^63)/308.254

Then when u displaying stats do it like that:
(10^(example.Value/(2^63)*308.254))-1

This should help you.

So it would be like that:

local DTS = game:GetService("DataStoreService")
local Lb = DTS:GetOrderedDataStore("Lb1")
local DataStore = DataStoreService:GetDataStore("DataStore3")
local function updateLeaderboard()
	local success, errorMessage = pcall(function()
		local Data = Lb:GetSortedAsync(false, 50,0,math.huge)
		local ClicksPage = Data:GetCurrentPage()
		for rank, data in ipairs(ClicksPage) do
			local user = game.Players:GetNameFromUserIdAsync(tonumber(data.key)) 
			local Name = user
			local PlayerUserId = "Player_"..data.key
			local LeaderboardData
			local success, errormessage = pcall(function()
				LeaderboardData = DataStore:GetAsync(PlayerUserId, data)
			end)
			local TimeWasted = (10^(LeaderboardData.Currency/(2^63)*308.254))-1
			
			local isLeaderboard = false
			for i,v in pairs(game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame:GetChildren()) do
				if v.Player.Text == Name then
					isLeaderboard = true
					break
				end
			end
			if TimeWasted and isLeaderboard == false then
				local newLeaderboard = game.ReplicatedStorage:WaitForChild("ScrollingFrame"):Clone()
				newLeaderboard.Player.Text = Name
				newLeaderboard.Points.Text = TimeWasted
				newLeaderboard.Ranks.Text = "#"..rank
				newLeaderboard.Position = UDim2.new(0,0, newLeaderboard.Position.Y.Scale + (.02 * #game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame:GetChildren()), 0)
				newLeaderboard.Parent = game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame
				if rank == 1 then
					local Description = game.Players:GetHumanoidDescriptionFromUserId(tonumber(data.key))
					local Dummy = workspace:WaitForChild("Dummy")
					Dummy.Humanoid:ApplyDescription(Description)
					newLeaderboard.Player.TextColor3 = Color3.fromRGB(239, 184, 56)
					newLeaderboard.Points.TextColor3 = Color3.fromRGB(239, 184, 56)
					newLeaderboard.Ranks.TextColor3 = Color3.fromRGB(239, 184, 56)
				end
			end
		end
	end)
	if not success then
		warn(errorMessage)
	end
end

while true do
	for _, player in pairs(game.Players:GetPlayers()) do 
		Lb:SetAsync(player.UserId, math.log10(player.leaderstats.Currency.Value+1)*(2^63)/308.254
)
	end
	
	for _, frame in pairs(game.Workspace.Leaderboard.SurfaceGui.ScrollingFrame:GetChildren()) do
		frame:Destroy()
	end
	
	updateLeaderboard()
	
	wait(20)
end
5 Likes

I just meant your response of not going that high in numbers, your solution to the leaderboard is fine.

You lose accuracy if you divide the value just to multiply it back later. If you want to store integers larger than 2^53 safely, you have to use multiple values, period. You can’t fit more than 53 bits worth of data in 53 bits worth of data, it’s the classic pigeonhole principle. The ODS itself can hold these approximated scaled down values but when you read them from the ODS people who have very similar large and close values will be equal when you scale them down (for example, math.log10(2^52) == math.log10(2^52 + 1)) so you need to fetch their actual values from the original DS storing the value as a string or as multiple integers.

2 Likes

Well you are right, but that can help him a bit. Atleast for passing 9.223qn