BigNums and Leaderboards

The game I’m working on uses the BigNum library to store certain data as the numbers go way above the roblox number limit. However it seems like BigNums can’t be saved onto an OrderedDataStore.

Full Script
local prefixes = {
	[2] = "K", [3] = "M", [4] = "B", [5] = "T", [6] = "q", [7] = "Q", 
	[8] = "Sx", [9] = "Sp", [10] = "Oc", [11] = "N"
}

local function format(n)
	local NewNum
	local Str = tostring(n)
	local Length = string.len(Str)
	local Rounded = tonumber(string.sub(Str, 1, 4))
	local PrefixNumber = math.ceil(Length/3)
	local prefix = prefixes[PrefixNumber]
	if Length >= 4 then -- If it's in the thousands, then format it.
		if Length%3 == 1 then
			NewNum = tostring(Rounded/1000)..prefix
		end
		if Length%3 == 2 then
			NewNum = tostring(Rounded/100)..prefix
		end
		if Length%3 == 0 then
			NewNum = tostring(Rounded/10)..prefix
		end
	else
		NewNum = n
	end
	return NewNum
end 
	

local PlayerStatManager = require(game:GetService("ServerStorage").PlayerStatManager)

local Resources = require(game:GetService("ReplicatedStorage").Resources)
local BigNum = Resources:LoadLibrary("BigNum")

local DSS = game:GetService("DataStoreService")

local SkullsDS = DSS:GetOrderedDataStore("SkullDS9")

local SkullsLB = workspace.SkullsLB.LB.LB.SkullsLeaderboard.ScrollingFrame

wait(3)

while true do
-- Datastore variables:
	print("Running script")
	local smallestFirst = false
	local numberToShow = 100
	local minValue = 0
	local maxValue = 10e50
	
-- Total Skulls [All-time]
	for i,plr in pairs(game.Players:GetChildren()) do
	--	if plr.UserId>0 then
		if true then
			local PlrSkullsStr = PlayerStatManager:getStat(plr, "Total Skulls")
			local PlrSkulls = BigNum.fromString64(PlrSkullsStr)
			print(format(PlrSkulls))
			pcall(function()
				SkullsDS:UpdateAsync(plr.UserId,function(oldVal)
                  --Set new value
					return tonumber(PlrSkulls)
				end)
			end)
		end
	end
	local pages = SkullsDS:GetSortedAsync(smallestFirst, numberToShow, minValue, maxValue)
	--Get data
	local top = pages:GetCurrentPage()
	print(top)
	for i, v in pairs(top) do
		print(i, v)
	end
	print(#top)
	
	for i, v in pairs(SkullsLB:GetChildren()) do
		if v.Name ~= "UIListLayout" then
			v:Destroy()
		end
	end
	
	for rank, player in ipairs(top) do
		print(rank, player)
		local userid = player.key
		local username = "[Failed To Load]"
		local s,e = pcall(function()
			username = game.Players:GetNameFromUserIdAsync(userid)
		end)
		if not s then
			warn("Error getting name for "..userid..". Error: "..e)
		end
		local PlrCard = script.Sample:Clone()
		PlrCard.Rank.Text = rank.."."
		PlrCard.PlrName.Text = username
		PlrCard.Value.Text = tostring(format(player.value))
		PlrCard.Parent = SkullsLB
		PlrCard.LayoutOrder = rank
		PlrCard.Name = rank
	end
	
	wait(60)
end
Output

image

I had tried this same script with normal numbers and it functions perfectly. So I’m just assuming that the problem is BigNums can’t be saved in OrderedDataStores.

Any solutions would be much appreciated!

Thanks, Kipp

2 Likes

Sadly, it seems numbers in ordered data stores are capped to the same limits and int values. You can’t save strings, so there is no work around to this. You could try storing values as their value divided by x, and then display them as that number times x converted to a string. However, you may reach the same problem using decimal places.

3 Likes

OrderedDataStores only accept integer values (whole numbers), so decimal places would produce issues as well. There’s also a certain number you can go up to until you encounter an integer overflow. Thought to throw around these terms as an add-on.

2 Likes

So what is the number you’re trying to reach? 1 million, 1 billion? One thing you could try is using two slots for your big number to split it up. One slot could be for numbers in the millions range, and then another slot to store the billions number. You could probably facilitate this using some multiplication and division.

I see the IntValue limit is 2,147,483,647, so instead of having one Intvalue to handle that big number, split it up so that one IntValue named “BillionsValue” = 2, and MillionsValue = 147483647 - just an example.

To display this you could just concatenate the Billions onto a formatted (with leading zeros as needed) copy of the MillionsValue in a string… I would store and display both values unless you’re comfortable splitting up the big number into the appropriate Billions and Millions values…

Programmers have used more than one slot to store a big number, for years, due to these types of limitations.

2 Likes

Thank you all, I have found a solution now. For anyone interested I simply check if the number is above 1M, and store it as n/1000000, when displaying i just multiply it by 1000000 and format it. This increases the number limit by x1 million, in future updates once players are able to get even higher numbers, I’ll change the divider/multiply to 1 billion, then trillion, etc…

3 Likes

That should work perfectly. Nice job.

Hey, this is a long time subsequent of the post, but if you want to pass the integer or floating point limit, use EternityNum made by FoundForces which has a built-in function called lbencode(num), and lbdecode(num) which is compatible with whatever you are trying to do, but keep in mind to read the function names so you don’t get lost!