Problems with a block of code in my script, arithmetic issues for a leaderboard

Hey everyone! I was creating a stopwatch which records your time from touching one part to another part, so I made a leaderboard which uses your best time to put up on the leaderboard.

The issue here is that when I run the game with API enabled I see in the output an arithmetic error. This error occurs as soon as I join the game which causes the script to stop working. I put these calculations in so it can actually be able to get formatted to be put up on the leaderboard.

I’ve tried removing the line of code and it did not work I also changed up the values of the equation but still nothing had changed, anyone know?
The error comes from the line, “local time = data.Value/1000”, which can be found in the “local function updateleaderboard()” block of code.

local dataStoreService = game:GetService("DataStoreService")
local leaderboardStore = dataStoreService:GetOrderedDataStore("MainLeaderboard")

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:UpdateAsync(player.UserId, function(oldTime)
		if not oldTime then
			oldTime = math.huge
		end
		if time < oldTime then
			return time
		else
			return
		end
	end)
end)

local LeaderboardPart = workspace:WaitForChild("LeaderBoard")
local surfacegui = LeaderboardPart.LeaderboardGui
local positionLabels = {
	surfacegui:WaitForChild(1),
	surfacegui:WaitForChild(2),
	surfacegui:WaitForChild(3),
	surfacegui:WaitForChild(4),
	surfacegui:WaitForChild(5),
	surfacegui:WaitForChild(6),
	surfacegui:WaitForChild(7),
	surfacegui:WaitForChild(8),
	surfacegui:WaitForChild(9),
	surfacegui:WaitForChild(10),
}

local function updateLeaderboard()
	local leaderboardData = leaderboardStore:GetSortedAsync(false, 10)
	local currentPage = leaderboardData:GetCurrentPage()
	for i, data in ipairs(currentPage) do
		local time = data.Value/1000
		local positionLabel = positionLabels[i]
		if positionLabel then
			local player = game:GetService("Players"):GetNameFromUserIdAsync(data.key)
			if player then
				positionLabel.Text = string.format("%d. %s - %.3f", i, player, time)
			else
				positionLabel.Text = ""
			end
		end
	end
end

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:SetAsync(player.UserId, time)
	updateLeaderboard()
end)

updateLeaderboard()
5 Likes

You can do

local time = (data.Value or 0)/1000

That will make sure that if data does not have an assigned value yet, it is set to 0 as default.
Another thing I would suggest is just doing print(data) and print(data.Value) instead of the division to see if they even exist

5 Likes

Okay so, I’ve just tried it and added a print(time) under it to print data and the data it had printed was 0, here is a video of me trying it, it is just sending out 0 after setting a new high score,

6 Likes

That indicates that data probably does not have anything inside it. Can you confirm if print(data) returns anything? If not, Make sure that data is a thing before you try to get a value out of it

5 Likes

Yeah here, I was setting a new high score every try and the output showed a print from the line right under the arithmetic issue, Take a look.
image

4 Likes

Remove the OR 0 and do it again. Also, Don’t use time as a variable, change it to something else even Time works as time is a predefined variable so you might run into conflicts

3 Likes

number one: read the error

:38: Attempt to perform artihmetic (div) on nil and number
which means you are doing: nil/number on line 38

number two: find line 38

local time = data.Value/1000

as i said earlier, you are doing nil/number, which is exactly what we found here. you are dividing a value of something that no one knows, with the number 1000.

number three: investigate data.Value

from this line:

for i, data in ipairs(currentPage) do

i know that data is a member of currentPage, which seems like a datastore object. so it must be an issue related to the datastore.

number four: investigate what’s causing the datastore issue

look,

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:UpdateAsync(player.UserId, function(oldTime)
		if not oldTime then
			oldTime = math.huge
		end
		if time < oldTime then
			return time
		else
			return
		end
	end)
end)

you are using UpdateAsync, and i see two returns, one is return time and one is return with no value or nil. like i mentioned earlier, you are doing nil/number, which looks extremely familiar to this.

number five: solution

now that we figured out the issue behind the nil value, we’ll make the script to return the smallest time between time and oldTime

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:UpdateAsync(player.UserId, function(oldTime)
		if not oldTime then
			oldTime = math.huge
		end
		return math.min(oldTime, time)
	end)
end)

from my prespective, i think you are trying to make a leaderboard for players who spent time the most, not the shortest time spent. so here’s my revision:

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:UpdateAsync(player.UserId, function(oldTime)
		oldTime = oldTime or 0
		return math.max(oldTime, time) -- put the bigger time to the leaderboard.
	end)
end

if you encounter any errors, feel free to reply.

5 Likes

Ok! so, it works well but another issue is raised, there is a problem on line 37 with the line where it formats the number to an actual string so it can get put onto the leaderboard, here is the line of code with the issue
positionLabel.Text = string.format("%d. %s - %.3f", i, player, time)


Here is the issue that is shown in the output, now I tried removing the formatter but the leaderboard will just show “1”. This is part of the same script in the original issue line 37 in the updateleaderboard() function.

4 Likes

i’m not a format pattern masters degree, but since i is a number, player is a string, and time is a number i suppose you can use "%d. %s - %d"

im not sure how the fourth argument (variable time) is detected as a function, perhaps you changed the script? because i see in the script that variable time is defined as data.Value/1000 and there is no way a dividing operation is going to give a function.

3 Likes

Okay so, I just tried it and it still gives out the exact same error on the exact same line, I think this isn’t related to the original issue but more related to formatting issues because it is expecting a number instead of a function as it says in the output.

2 Likes

can you give me the current script? perhaps you changed something and it made a different result

2 Likes

Sure thing, here

local dataStoreService = game:GetService("DataStoreService")
local leaderboardStore = dataStoreService:GetOrderedDataStore("MainLeaderboard4")

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:UpdateAsync(player.UserId, function(oldTime)
		oldTime = oldTime or 0
		return math.max(oldTime, time) -- put the bigger time to the leaderboard.
	end)
end)

local LeaderboardPart = workspace:WaitForChild("LeaderBoard")
local surfacegui = LeaderboardPart.LeaderboardGui
local positionLabels = {
	surfacegui:WaitForChild(1),
	surfacegui:WaitForChild(2),
	surfacegui:WaitForChild(3),
	surfacegui:WaitForChild(4),
	surfacegui:WaitForChild(5),
	surfacegui:WaitForChild(6),
	surfacegui:WaitForChild(7),
	surfacegui:WaitForChild(8),
	surfacegui:WaitForChild(9),
	surfacegui:WaitForChild(10),
}

local function updateLeaderboard()
	local leaderboardData = leaderboardStore:GetSortedAsync(true, 10)
	local currentPage = leaderboardData:GetCurrentPage()
	for i, data in ipairs(currentPage) do
		print(time)
		local positionLabel = positionLabels[i]
		if positionLabel then
			local player = game:GetService("Players"):GetNameFromUserIdAsync(data.key)
			if player then
				positionLabel.Text = string.format("%d. %s - %d", i, player, time)
			else
				positionLabel.Text = ""
			end
		end
	end
end

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:SetAsync(player.UserId, time)
	updateLeaderboard()
end)

updateLeaderboard()```
2 Likes

as i expected, you removed the time variable.
looking at your old script:

and your current script

i noticed that the time variable disappeared.

(im suspecting that roblox added a built in function named time)

try to define the variable time above the line local positionLabel = positionLabels[i] in your current script. (to overwrite the time built in function)
i meant:

local time = data.Value/1000

and if you encounter any errors with the format pattern, just use "%d. %s - %d"

2 Likes

I just updated it and added the missing part, here is the updated code block, the original issue is yet again brought back up with the arithmetic issue and now when I stop play testing there is a huge amount of lag.

   local leaderboardData = leaderboardStore:GetSortedAsync(true, 10)
   local currentPage = leaderboardData:GetCurrentPage()
   for i, data in ipairs(currentPage) do
   	print(time)
   	local time = data.Value/1000
   	local positionLabel = positionLabels[i]
   	if positionLabel then
   		local player = game:GetService("Players"):GetNameFromUserIdAsync(data.key)
   		if player then
   			positionLabel.Text = string.format("%d. %s - %d", i, player, time)
   		else
   			positionLabel.Text = ""
   		end
   	end
   end
end
2 Likes

can i see the error for the arithmetic part?

2 Likes

Yeah here it is,

2 Likes

sorry for asking again but can you give me your current script

2 Likes

It’s fine lol I’m just doing anything to get this sorted, Here you go,

local dataStoreService = game:GetService("DataStoreService")
local leaderboardStore = dataStoreService:GetOrderedDataStore("MainLeaderboard4")

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:UpdateAsync(player.UserId, function(oldTime)
		oldTime = oldTime or 0
		return math.max(oldTime, time) -- put the bigger time to the leaderboard.
	end)
end)

local LeaderboardPart = workspace:WaitForChild("LeaderBoard")
local surfacegui = LeaderboardPart.LeaderboardGui
local positionLabels = {
	surfacegui:WaitForChild(1),
	surfacegui:WaitForChild(2),
	surfacegui:WaitForChild(3),
	surfacegui:WaitForChild(4),
	surfacegui:WaitForChild(5),
	surfacegui:WaitForChild(6),
	surfacegui:WaitForChild(7),
	surfacegui:WaitForChild(8),
	surfacegui:WaitForChild(9),
	surfacegui:WaitForChild(10),
}

local function updateLeaderboard()
	local leaderboardData = leaderboardStore:GetSortedAsync(true, 10)
	local currentPage = leaderboardData:GetCurrentPage()
	for i, data in ipairs(currentPage) do
		print(time)
		local time = data.Value/1000
		local positionLabel = positionLabels[i]
		if positionLabel then
			local player = game:GetService("Players"):GetNameFromUserIdAsync(data.key)
			if player then
				positionLabel.Text = string.format("%d. %s - %d", i, player, time)
			else
				positionLabel.Text = ""
			end
		end
	end
end

replicatedStorage.BestTime.OnServerEvent:Connect(function(player, time)
	time = math.floor(time * 1000)
	leaderboardStore:SetAsync(player.UserId, time)
	updateLeaderboard()
end)

updateLeaderboard()
3 Likes

can u put print(data) below for i, data in ipairs(currentPage) do? just curious what data’s insides are

1 Like


So we have the data, 2548 is the actual time that should be up on the leaderboard but it isn’t.