Stats being given to multiple players how do I fix this?

Hello there, I have just finished making the stats and incrementers for my GUI player stats and when I open a server in studio stats are duplicated to every user for some reason I have seen threads on the forum saying to put “player” in the functions I am using and I wonder why it does not work. I also am wondering if it is how I am handling my table and where I put it I will provide the codes for it down below.
What I want my code to do is have the stats update separately and not as a group of players so each player has their own cash rebirths and whatever else I could add as a stat afterwards.

Thanks in advance!
– Scripteor

Server Sided handler (ServerScriptService)

local Players = game:GetService("Players") -- Players
local ReplicatedStorage = game:GetService("ReplicatedStorage") -- ReplicatedStorage

local CashUpdater = ReplicatedStorage:WaitForChild("CashUpdater") -- CashUpdater Event
local RebirthUpdater = ReplicatedStorage:WaitForChild("RebirthUpdater")

local PlayerList = {} -- Player list (Table)

local Stats = {
	Cash = 0,
	Increaser = 1,
	Rebirths = 0,
	RebirthPrice = 100
}

local function InitPlayerStats(Player) -- Initialize player stats
	PlayerList[Player] = Stats -- Puts the Stats inside the Players
	
	local leaderstats = Instance.new("Folder") -- Initialize the Stats
	leaderstats.Name = "leaderstats" 
	
	local Cash = Instance.new("NumberValue") 
	Cash.Name = "Cash"
	Cash.Value = 0 
	
	Cash.Parent = leaderstats 
	
	local Rebirths = Instance.new("NumberValue")
	Rebirths.Name = "Rebirths"
	Rebirths.Value = 0
	
	Rebirths.Parent = leaderstats
	
	local RebirthPrice = Instance.new("NumberValue")
	RebirthPrice.Name = "RebirthPrice"
	RebirthPrice.Value = 100
	
	RebirthPrice.Parent = leaderstats
	
	local Increaser = Instance.new("NumberValue")
	Increaser.Name = "Increaser"
	Increaser.Value = 1
	
	Increaser.Parent = leaderstats
	
	local EXP = Instance.new("NumberValue")
	EXP.Name = "EXP"
	EXP.Value = 0
	
	EXP.Parent = leaderstats
	
	leaderstats.Parent = Player -- Sets the Players as the parent of the Stats
end

local function UpdateCash(Player) -- The function that adds cash
	local Stats = PlayerList[Player] -- Sets the stats in the player list for the function
	Stats.Cash = Stats.Cash + Stats.Increaser -- Increases Stats
	
	local leaderstats = Player:FindFirstChild("leaderstats") -- Finds leaderstats of player
	local PlayerCash = leaderstats:FindFirstChild("Cash") -- Finds Cash of player
	
	PlayerCash.Value = Stats.Cash -- Sets the Cash stat in the Table for the player
end

local function UpdateRebirths(Player) -- Function that runs on event
	local Stats = PlayerList[Player]
	if Stats.Cash >= Stats.RebirthPrice then
		Stats.Cash = Stats.Cash - Stats.RebirthPrice
		Stats.Rebirths = Stats.Rebirths + 1
		Stats.Increaser = Stats.Increaser + 1
		Stats.RebirthPrice = math.floor(Stats.RebirthPrice * 2.5 / 1.2) else
	end
end

for _, Player in Players:GetPlayers() do  -- Function that goes through players to initialize
	InitPlayerStats(Player) -- function above
end

game.Players.PlayerAdded:Connect(function(Player) -- Function that adds Players on join
	InitPlayerStats(Player) -- function above
end)

game.Players.PlayerRemoving:Connect(function(Player) -- Function that removes Players on leave
	PlayerList[Player] = nil -- Reset the value in the Player table
end)

CashUpdater.OnServerEvent:Connect(function(Player) -- Starts the event
	UpdateCash(Player) -- Function launched on event
end)

RebirthUpdater.OnServerEvent:Connect(function(Player) -- Starts the event
	UpdateRebirths(Player) -- Function launched on event
end)

Client Side CashButton Handler (Under the appropriate GUI)

local ReplicatedStorage = game:GetService("ReplicatedStorage") -- Replicated Storage

local Players = game:GetService("Players") -- Players

local CashUpdater = ReplicatedStorage:WaitForChild("CashUpdater") -- CashUpdater Event

local Player = Players.LocalPlayer -- Local Player

local Button = script.Parent -- Cash Button

local TextLabel = script.Parent.Parent.CashAmount -- Cash Label

local Cash = Player:WaitForChild("leaderstats"):WaitForChild("Cash") -- Finds the Cash value for the local player

Button.MouseButton1Click:Connect(function() -- On click CashButton function

CashUpdater:FireServer() -- Fires the event to the server @ ServerScriptService.StatsHandler

end)

Cash:GetPropertyChangedSignal("Value"):Connect(function() -- Detects the value has changed

TextLabel.Text = Cash.Value .. " Cash"

print(Cash.Value)

end)

Client Sided RebirthButton Handler (Under the appropriate GUI)

local ReplicatedStorage = game:GetService("ReplicatedStorage")  -- Services and remote events
local Players = game:GetService("Players") 
local RebirthUpdater = ReplicatedStorage:WaitForChild("RebirthUpdater") 

local Player = Players.LocalPlayer  -- Variables
local RebirthPriceLabel = script.Parent
local CashIncreaserLabel = script.Parent.Parent.CashButton
local RebirthAmountLabel = script.Parent.Parent.RebirthAmount
local CashLabel = script.Parent.Parent.CashAmount

local Rebirths = Player:WaitForChild("leaderstats"):WaitForChild("Rebirths") -- Data for the player
local RebirthPrice = Player:WaitForChild("leaderstats"):WaitForChild("RebirthPrice")
local Increaser = Player:WaitForChild("leaderstats"):WaitForChild("Increaser")
local Cash = Player:WaitForChild("leaderstats"):WaitForChild("Cash")

-- Single use functions for UI
local function CashUiUpdater()
	CashLabel.Text = Cash.Value .. " Cash"
end

local function RebirthUiUpdater()
	RebirthAmountLabel.Text = Rebirths.Value .. " Rebirths"
end

local function RebirthPriceUiUpdater()
	RebirthPriceLabel.Text = RebirthPrice.Value .. " Cash to rebirth"
end

local function IncreaserUiUpdater()
	CashIncreaserLabel.Text = "+" .. Increaser.Value .. " Cash"
end
-- Single use functions for UI

RebirthPriceLabel.MouseButton1Click:Connect(function()  -- Mouse Clicked the rebirth button
	if Cash.Value >= RebirthPrice.Value then
		
		RebirthUpdater:FireServer()

		Cash.Value = Cash.Value - RebirthPrice.Value
		CashUiUpdater()
		
		Rebirths.Value = Rebirths.Value + 1
		RebirthUiUpdater()
		
		Increaser.Value = Increaser.Value + 1
		IncreaserUiUpdater()
		
		RebirthPrice.Value = math.floor(RebirthPrice.value * 2.5 / 1.2)
		RebirthPriceUiUpdater()
		
		print(Cash.Value .. " " .. Rebirths.Value .. " " .. RebirthPrice.Value .. " " .. Increaser.Value) else
		print("Not enough money, missing :" .. RebirthPrice.Value - Cash.Value .. " Cash")
	end
end)

Cash:GetPropertyChangedSignal("Value"):Connect(function()  -- Remote event
end)

Sorry about the last script I did not comment it yet :confused:

InitPlayerStats does not do what you think it does. The way you have it theres only one “Stats” table which you give to all your players, so anything that effects one player’s stats will effect them all. You probably meant to do:

local function InitPlayerStats(Player) -- Initialize player stats
	local Stats = {
		Cash = 0,
		Increaser = 1,
		Rebirths = 0,
		RebirthPrice = 100
	}

	PlayerList[Player] = Stats -- Puts the Stats inside the Players
	
	--rest of function
end
1 Like

So instead of my long function for InitPlayerStats I would put the table of data and PlayerList[Player] = Stats?

I don’t understand what you’re asking by this.

Do I remove what is inside InitPlayerStats or do I move the Stats table inside of InitPlayerStats? Sorry if I am not that clear I’m not too experienced with Lua and coding in general :slight_smile: .

No you can keep everything else in InitPlayerStats, just move the Stats table inside the function. This will create a new Stats table for each player instead of sharing one. I didn’t look at what the rest of InitPlayerStats does and I assume you need that code for something else.

the rest of the code is a leaderstats instance with the base value for cash and everything else like so :

local leaderstats = Instance.new("Folder") -- Initialize the Stats
	leaderstats.Name = "leaderstats" 
	
	local Cash = Instance.new("NumberValue") 
	Cash.Name = "Cash"
	Cash.Value = 0 
	
	Cash.Parent = leaderstats

Duplicate this for every stat as well!

Would I still need that or would I be fine with just the Stats table?

I can’t answer that because I don’t know what you’re using the NumberValues for. The purpose of Value objects are to have a value stored in the game hierarchy (in the workspace or replicated storage for example), which can be shared between scripts and is replicated to clients when set from the server. They are kind of old school and there is generally always a way to write your code so you don’t need them, but I need to know more about what they are used for to say.

It is only a gui that has numbers going up like cash on every cash click and rebirths when you reach a certain amount of cash some people told me to make it but I do not know if I really need it for what I am trying to do :stuck_out_tongue:
for example my rebirth updater thingie looks like this

local function UpdateRebirths(Player) -- Function that runs on event
	local Stats = PlayerList[Player]
	if Stats.Cash >= Stats.RebirthPrice then
		Stats.Cash = Stats.Cash - Stats.RebirthPrice
		Stats.Rebirths = Stats.Rebirths + 1
		Stats.Increaser = Stats.Increaser + 1
		Stats.RebirthPrice = math.floor(Stats.RebirthPrice * 2.5 / 1.2) else
	end
end

I never use leaderstats hence why I am wondering if I need it in the first place
Well actually the only place I use it is in my client sided scripts like so :

local Rebirths = Player:WaitForChild("leaderstats"):WaitForChild("Rebirths") -- Data for the player

local RebirthPrice = Player:WaitForChild("leaderstats"):WaitForChild("RebirthPrice")

local Increaser = Player:WaitForChild("leaderstats"):WaitForChild("Increaser")

local Cash = Player:WaitForChild("leaderstats"):WaitForChild("Cash")

Ideally you should keep one or the other, either the stats table in the script or the values. I would recommend keeping the table and using remote functions to update the table. That would be a whole different question though as there are a some timing, reliability, and security considerations to talk about first.

1 Like

Yea this was my main preoccupation making this I could of made this ui half botched and finish it in 10 mins but I want to try to not have players have access to everything on the client side of things

I will look what I can do with remote functions but I feel like that would work. My last question is what type of functions should be set as remote functions? Only the ones who handle data or there’s more to it?

Most of your stuff already uses remotes, to replace the leaderstats all you’d have to do is send each player their Stats table periodically (like once a second) and read the stats values from there the same way you’d read them from a Value.

1 Like

Could I not send it on every button click instead? For optimization purposes of course.

If pressing the button is the only thing that can cause the stats to change, then yes. Dont forget to send the initial values when the player first joins.

1 Like

Alright thank you! This answers my question pretty well thank you for taking the time I appreciate it!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.