Data.key returns negative

I know this question has been asked before but the ones I found didn’t have an answer in them that I could use but basically well I think its better to put the code first:

local rs = game:GetService("ReplicatedStorage")
local st = rs:WaitForChild("SaveTime")
local dss = game:GetService("DataStoreService")
local leaderboardstore = dss:GetOrderedDataStore("leaderboardstore")

st.OnServerEvent:Connect(function(player, runtime) 
	local playertime = tonumber(runtime) 
	local function update()
		local success, errormessage = pcall(function()
			local Data = leaderboardstore:GetSortedAsync(false,10)
			local timepage = Data:GetCurrentPage()
			for rank, data in ipairs(timepage) do
				print(""..tonumber(data.key)) 
				local username = game.Players:GetNameFromUserIdAsync(tonumber(data.key))
				local name = username
				local timing = data.value
				local onboard = false
				for i, v in pairs(game.Workspace.Leaderboard.LeaderboardGui.LeaderboardHolder:GetChildren()) do
					if v.Player.Text == name then
						onboard = true
						break
					end
				end
				if timing and onboard == false then
					local newframe = rs:WaitForChild("Template"):Clone()
					newframe.Player.Text = name
					newframe.Time.Text = timing
					newframe.Rank.Text = "#"..rank
					newframe.Position = UDim2.new(0,0,newframe.Position.Y.Scale + (.1 * #game.Workspace.Leaderboard.LeaderboardGui.LeaderboardHolder:GetChildren()), 0)
					newframe.Parent = game.Workspace.Leaderboard.LeaderboardGui.LeaderboardHolder
				end
			end
		end)
		if not success then
			print(errormessage)
			warn(errormessage)
		end
	end
	while true do
		for _, player in pairs(game.Players:GetPlayers()) do
			leaderboardstore:SetAsync(player.UserId,playertime*100)
		end
		
		for _, frame in pairs(game.Workspace.Leaderboard.LeaderboardGui.LeaderboardHolder:GetChildren()) do
			frame:Destroy()
		end
		update()
		print("update")
		wait(10)
	end
end)


while looping through the page, data.key returns a negative value and then getnamefromuseridasync says unknown user. I tried printing data.key and published it but even if i play the actual game and go into the server console it shows its a negative number and getnamefromuseridasync has the same error.

2 Likes

Is that negative value “-1” by any chance? If so then I’m assuming you opened the game in test server mode in studio. When you do this you’ll notice that for each player their “Name” property is set to “Player” followed by a number indicating their position in the test server, i.e; “Player1” would represent the first player that was loaded into the test server. Taking a further inspection of any test player’s “UserId” property you’ll notice the following.

image

Therein likely lies your answer.

1 Like

The issue is definitely what @Forummer mentioned, most leaderboard scripts counter this issue by placing an if condition for the userIds:

if data.key < 1 then continue end --if a user has an id below 1, skip the current loop iteration
print(""..tonumber(data.key))
--etc.

and on your saving loop:

for _, player in pairs(game.Players:GetPlayers()) do
	if player.UserId < 1 then continue end --same check
	leaderboardstore:SetAsync(player.UserId,playertime*100)
end

This will restrict the dummy accounts from appearing on the leaderboards, which is what the majority of games does.

PS: You may also want to use pcalls to handle API request errors:

--example
local username
local Success, Error = pcall(function()
	username = game.Players:GetNameFromUserIdAsync(tonumber(data.key))
end)

if Error then 
	warn(Error) --what's the error?
	continue  ​--ignore the current loop iteration, user doesn't exist or Roblox services are down
end

All the API requests that are able to error and can break the script should be wrapped inside a pcall( GetSortedAsync , GetNameFromUserIdAsync , SetAsync) so the script wont break if certain APIs are down.

2 Likes

This error appears in game too though like if I go to the roblox website and my profile and play this game the issue is still there

1 Like

The value appears negative even for alts that go inside the actual game not studio, also the whole thing is already in a pcall, do you mean make another one inside it?

1 Like

The reason the values are negative is because the datastore data contains the dummy accounts userIds, you have to either erase their leaderboard data or add the if statements I mentioned.

That worked thanks, but you also said to use a pcall, does that mean Im using it incorrectly?

How did you erase the leaderboard data may I ask?

I actually have that same issue, at least in studio… Haven’t tested in game.

for rank, data in ipairs(page) do
			
			local playerName = game.Players:GetNameFromUserIdAsync(tonumber(data.key))
			local value = data.value
			
			local isOnLeaderboard = false
			
			for i,v in pairs(parent:GetChildren()) do
				if v:IsA("Frame") and v.PlayerName.Text == playerName then
					isOnLeaderboard = true
					break
				end
			end
			
			if value and isOnLeaderboard == false then
				local GLTemplate = game.ReplicatedStorage.ASSETS.GLTemplate:Clone()
				GLTemplate.Rank.Text = "#"..rank
				GLTemplate.Kills.Text = value
				GLTemplate.PlrName.Text = playerName
				GLTemplate.Parent = parent
			end
			
		end

Im not too advanced with datastores but I think Ive seen that modifying the name of the actual datastore name resets the data, by name I mean the name that you call it when getting the ordered data store.

1 Like

You don’t need to erase the entire datastore data, you can just use a plugin such as Datastore Editor, search for all the keys with a number less than 1(assuming they represent userIds), and manually remove them one by one.

1 Like