Leaderboard Data not showing changes for other people on my screen

I’m working on a Simulator Prototype, and for some reason while playing in-game from the website the data for other people just stay 0 on my screen even though for them it’s going up. Mine shows changes. I feel like it has something to do with the Client. I have the data changing by clicking on a tool (which has a localscript inside of it) so the point system is client sided. I had it Go from client (clicking the tool) to server (remotevent) and then it would change the data. But this causes issues. If you changed the data using a different method besides the RemoteEvents, such as just doing Data.Value = Data.Value + 1, it would change, but then clicking the coin (using the remoteevent) it would reset to the original value.

Here is the localscript (inside of my coin tool):

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local tool = script.Parent

local player = game.Players.LocalPlayer

local Debounce = false

tool.Activated:Connect(function()
	if Debounce == false then
		Debounce = true
		player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + (1 * player.leaderstats.Rebirths.Value)
		wait(.25)
		Debounce = false
	end
end)

My datastore script:

local Datastore = game:GetService("DataStoreService"):GetDataStore("pixel-DS51")

game.Players.PlayerAdded:Connect(function(player)
	
	local Key = "Player-ID:" .. player.userId
	
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	
	local Coins = Instance.new("NumberValue", leaderstats)
	Coins.Name = "Coins"
	
	local Rebirths = Instance.new("NumberValue", leaderstats)
	Rebirths.Name = "Rebirths"
	Rebirths.Value = 1
	
	-- GetAsync
	local GetSave = Datastore:GetAsync(Key)
	
	if GetSave then
		Coins.Value = GetSave[1]
		Rebirths.Value = GetSave[2]
		print("Data loaded for " .. player.Name)
	else
		local Numbers = {Coins.Value, Rebirths.Value}
		Datastore:SetAsync(Key, Numbers)
		print("Data Saved for " .. player.Name)
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	
	local Key = "Player-ID:" .. player.userId
	
	local ValuesToSave = {player.leaderstats.Coins.Value, player.leaderstats.Rebirths.Value}
	
	Datastore:SetAsync(Key, ValuesToSave)
	
	print("Data Saved for " .. player.Name)
end)

Any ideas why this might be happening?

Is FilteringEnabled turned on? Judging by your code, the client is the one setting how much Coins they have, which is extremely vulnerable to exploits. Clients cannot change what happens on the server. This is why the value isn’t updating for everyone else.

What issues does using a RemoteEvent cause? You’ll have to use it in order to make this work properly.

2 Likes

Instead of:

player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + (1 * player.leaderstats.Rebirths.Value)

I’d recommend you create a RemoteEvent inside ReplicatedStorage and change it to:

game.ReplicatedStorage.RemoteEvent:FireServer()

Then, inside of a server script, use the following code to update the player’s coins.

game.ReplicatedStorage.RemoteEvent.OnServerEvent:connect(function(player)
     player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + (1 * player.leaderstats.Rebirths.Value)
end)

You can read more about FilteringEnabled here.

Edit: Disallowed the client to change what value they increase by.

2 Likes

There’s still a lot of flaws in this, a exploiter can just fire the remote event with an insane value

3 Likes

You are correct, however, a debounce on the serverside can help assist this. Though I don’t see any other way to make this less vulnerable since it relies on the client clicking.

Edit: You can do the math that adds the value on the serverside. I’ll add this to the code I posted earlier. Thank you for pointing that out.

1 Like

Well, you could start off by making the calculation on the server instead of on the client.

local remote = game.ReplicatedStorage:WaitForChild("remoteName")

-- when needed, just do:
remote:FireServer()
-- but still check for debounce

Server Script:

local debounce = {}

game.ReplicatedStorage:WaitForChild("remoteName").OnServerEvent:Connect(function(player)
    if not debounce[player] then
        debounce[player] = true

        local coins = player.leaderstats.Coins
        coins.Value = coins.Value + player.leaderstats.Rebirths.Value

        wait(0.25)
        debounce[player] = false
    end
end)

Edit: Oh, you edited your post while I was typing. Anyways, here’s the debounce logic at least.

2 Likes

Yeah. I like this much better though. OP, this should fix your problem.

1 Like

Fundamentally speaking though, if you aren’t directly scrutinising his code example, Cherry is correct.

The point is: OP is attempting to change values from the client which is not replicating to the server, so a remote is required for the cross-environment communication. Input such as debounces and activations still need to be kept on the client for the purposes of input. The server needs to hold the validation side, meaning that the client should still debounce but the server should have a minimum threshold per player on how much the value is being incremented, taking into account their other stats (multipliers, for example).

@CherryLeaves FilteringEnabled is on by default for all places except legacy ones.

4 Likes

I found the fix, I don’t know why I thought I was wrong but I was right. I do have FilteringEnabled on, I understand the idea of using RemoteEvents. The issue I was having was that when you Rebirthed, it would set your Coins to 0, and add 1 to your rebirths. Once you rebirthed and then click it would jump back to the coins you had before you rebirthed. I just realized I wasn’t using a RemoteEvent to change the rebirth value / coin value, I just changed it using the localscript that handled the Rebirth System. Thank you all! Sometimes your biggest issue is yourself. :slight_smile:

1 Like

What do you mean? FilteringEnabled is on for all places. Experimental mode is removed.

I mean exactly what I said. FilteringEnabled is on by default for all places and legacy/non-updated ones do not have it enabled (see warnings that look like the below).

image

That is just a warning. Old games would not have FilteringEnabled since it did not exist back then, so when experimental mode was removed, in order to give an indication of that the games might need to be fixed, games have that message depending on whether the property is ticked. That is just from what I have seen. But they are still broken and still using FilteringEnabled.

You probably meant something else other than

because they do have FilteringEnabled enabled regardless of the property. It does nothing now.

1 Like

> forgot that it was relegated to a warning

In this case, just remove that sentence. Still gets the point across.

1 Like

You might want to make the debounce on server instead of client. You should also have a check to see if the player has the coin tool equipped (again, on the server).

1 Like

I understand the debounce part, but why would I need to check to see if the tool is equipped?

Exploiters can just fire your event without having the tool and will receive coins.

No. Debounce should be on both the server and the client. Keeping it on the server only is going to result in input delays which is awful for UX. The client-side debounce should merely assist with being visual, while the server-side debounce (validation) ensures that players are not gaining stats faster than what they should normally be allowed.

Yeah, my bad. It would spam the event if it doesnt have a check on the client too.
I suggest making an event cooldown too to prevent massive lag caused by exploiters.

This doesn’t matter. An exploiter can fire off the remote and “spam events”. The client-side visual is merely intended to reduce or negate client-side input lag and assist with visual effects.