How to fix this multiple players issue?

Hi Developers! :wave:

So, I have a weapon system that manages all weapon transactions and etc. Everything works fine but the player variable, for some reason when some functions are being fired they apply to every single player in the server!

The client side runs without any issues, not a single error shows up in console, everything works as intended in singleplayer session. All the functions like GetWeapon(), AddToEquipped and etc. mess up with the players and fire to all clients, even if there’s no :FireAllClients() in the entire game…

I’d appreciate any help provided :hidere:! If you need more info, please let know!

Here's the server script in ServerScriptService named 'Data'
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local DatastoreService = game:GetService("DataStoreService")
local MarketPlaceService = game:GetService("MarketplaceService")
local rs = game:GetService("ReplicatedStorage")

local Data = DatastoreService:GetDataStore("1")
local sessionData = {}

--weapons data
local WeaponData = DatastoreService:GetDataStore("WeaponData")
local WeaponSessionData = {}


function PlayerAdded(player)

	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Kills = Instance.new("NumberValue")
	Kills.Name = "Kills" 
	--Kills.Parent = player
	Kills.Parent = leaderstats

	local CC = Instance.new("IntValue")
	CC.Name = "CC"
	CC.Parent = player

	local success, playerData = pcall(function()
		return Data:GetAsync(player.UserId) 
	end)

	if success then

		if not playerData then


			playerData = {
				["Kills"] = 0,
				["CC"] = 0,
			}
		end

		sessionData[player.UserId] = playerData
	else
		warn("Couldn't load data: " .. player.Name)
		player:Kick("Couldn't load your data, rejoin please!")
	end

	if CC.Value == nil then CC.Value = 0 end

	Kills.Value = sessionData[player.UserId].Kills

	Kills:GetPropertyChangedSignal("Value"):Connect(function()
		sessionData[player.UserId].Kills = Kills.Value
	end)


	CC.Value = sessionData[player.UserId].CC

	CC:GetPropertyChangedSignal("Value"):Connect(function()
		sessionData[player.UserId].CC = CC.Value
	end)




	--=================================================================================================================================================
	--============================================================WEAPON DATA AND PROCESSES============================================================
	--=================================================================================================================================================


	--unlocked weapons  (the data table structure for weapons)
	local weaponTable = {
		OwnedWeapons = {
			["G36"] = true,
			["Five-Seven"] = true
		},
		EquippedWeapons = {
			Primary = "G36",
			Secondary = "Five-Seven",
			Melee = nil
		},
	}
	
	local InitialweaponTable = {
		OwnedWeapons = {
			["G36"] = true,
			["Five-Seven"] = true
		},
		EquippedWeapons = {
			Primary = "G36",
			Secondary = "Five-Seven",
			Melee = nil
		},
	}
	
	
	

	local success, playerWpnsData = pcall(function()
		return WeaponData:GetAsync(player.UserId)
	end)

	if success then
		if not playerWpnsData then playerWpnsData = weaponTable end
		WeaponSessionData[player.UserId] = playerWpnsData
	else
		warn("Couldn't load data: " .. player.Name)
		player:Kick("Couldn't load your weapon data, rejoin please!")
	end

	-- Ensure weaponTable is initialized as a table
	if not WeaponSessionData[player.UserId] then
		WeaponSessionData[player.UserId] = weaponTable
	else
		weaponTable = WeaponSessionData[player.UserId]
	end
	

	if weaponTable ~= InitialweaponTable then
		weaponTable = InitialweaponTable
		print("yes", weaponTable, InitialweaponTable)
		WeaponSessionData[player.UserId] = InitialweaponTable
	end
	
	CC.Value = 1000000

	print("That's the data of", player, weaponTable)


	------prices------
	local weaponPrices = {

		--historical
		["G36"] = {
			name = "G36",
			price = 0,
			class = "Primary",
		},
		["Five-Seven"] = {
			name = "Five-Seven",
			price = 0,
			class = "Secondary",
		},
		["Glock 17"] = {
			name = "Glock 17",
			price = 9000,
			class = "Secondary",
		},
		["SKS"] = {
			name = "SKS",
			price = 3300,
			class = "Primary",
		},
		["Remington 870"] = {
			name = "Remington 870",
			price = 7200,
			class = "Primary",
		},
		["M61 Vulcan"] = {
			name = "M61 Vulcan",
			price = 0,
			class = "Primary"
		},
		["Handship"] = {
			name = "Handship",
			price = 0,
			class = "Primary"
		},

		--unnatural
		["Fire"] = {
			name = "Fire",
			price = 1800,
			class = "Secondary",
		},
		["Magic Stick"] = {
			name = "Magic Stick",
			price = 3000,
			class = "Primary",
		},

	}
	------------------
	
	local function GetWeapon(weapon)
		
		warn(weaponTable)
		warn(weapon)
		warn(weaponTable.OwnedWeapons)
		
		for i, v in pairs(weaponTable.OwnedWeapons) do
			if i == weapon then
				print("Already have that weapon", weapon)
				return true
			else
				local unlockedStatus = true
				
				weaponTable.OwnedWeapons[weapon] = unlockedStatus
				WeaponSessionData[player.UserId] = weaponTable
				print("check this, inserted ", weapon, " to ", player, ". Status:", unlockedStatus)
				
			end
		end
	end

	local function AddWeapon(player, WeaponName: string, WeaponFolder: string)
		if WeaponName == nil then return end 
		
		local Weapon = nil
		
		for i, folder in pairs(rs.WeaponStorage:GetChildren()) do
			local find = folder[WeaponFolder]:FindFirstChild(WeaponName)
			
			if find ~= nil then
				Weapon = find
				print("Found weapon", Weapon, WeaponName, "in", WeaponFolder)
			else
				print("Didn't find any weapon in", WeaponFolder,"!")
			end
			
		end
		
		if Weapon then

			local existingWeapon = player.Backpack:FindFirstChild(WeaponName)

			if existingWeapon then
				existingWeapon:Destroy()	
			else
				--rs.WeaponNotification:FireClient(player, WeaponName)
			end
			local NewWeapon = Weapon:Clone()
			NewWeapon.Parent = player.Backpack
			
			print("added", Weapon, "to", player,"'s backpack!")
		end
	end
	
	local function AddToEquipped(weaponName: string, weaponClass: string)
		if weaponClass then
			weaponTable["EquippedWeapons"][weaponClass] = weaponName
			print("saved to equipped:", weaponName, weaponClass)

			WeaponSessionData[player.UserId] = weaponTable
		end
	end
	
	local function EquipWeapons(player, primary, secondary, melee)
		AddWeapon(player, primary, "Primary")
		task.wait(0.1)
		AddWeapon(player, secondary, "Secondary")
		task.wait(0.1)
		AddWeapon(player, melee, "Melee")
	end
	
	
	local updateEvent = rs.WeaponSystemEvents:WaitForChild("UpdateWeapon")
	local warning = rs.WeaponSystemEvents:WaitForChild("NotEnough")
	
	local function OnBuyEvent(wpn)
		warn(wpn, weaponPrices, weaponPrices[wpn]["price"])
		local price = weaponPrices[wpn]["price"]
		
		print("the price is", price, "weapon:", wpn, wpn.ClassName)
		
		if price and price ~= nil then
			if CC.Value >= price then
				CC.Value -= price
				GetWeapon(wpn)
				updateEvent:FireClient(player, wpn)
				
			else
				local needed = price - CC.Value
				
				warning:FireClient(player, needed)
			end
		end
	end
	

	--[[for _, weaponName in pairs(weaponTable) do
		local weaponInfo = weaponPrices[weaponName]
		if weaponInfo then
			AddWeapon(weaponInfo.name, weaponInfo.class, weaponInfo.price)
		end
	end]]



	--=====================Equipping and deploying==========================
	
	local equipEvent = rs.WeaponSystemEvents:WaitForChild("Equip")
	
	equipEvent.OnServerEvent:Connect(function(player, wpn)
		warn("fired!", wpn)
		for key, info in pairs(weaponPrices) do
			if wpn == info.name then
				AddToEquipped(wpn, info.class)
				print("equipped", wpn, "and inserted to", weaponTable.EquippedWeapons)
			else
				warn("no such a weapon!")
			end
		end
	end)
	
	
	
	local deployEvent = rs.WeaponSystemEvents:WaitForChild("PlayPressed")
	
	deployEvent.OnServerEvent:Connect(function(player)
		
		local primary = weaponTable.EquippedWeapons.Primary
		local secondary = weaponTable.EquippedWeapons.Secondary
		local melee = weaponTable.EquippedWeapons.Melee
		
		warn("WEAPONS:", primary, secondary, melee)
		
		
		EquipWeapons(player, primary, secondary, melee)
		print("deployed!", player, primary, secondary, melee)
	end)
	
	
	

	--===========buying new weapons=======================
	local buyevent = rs.WeaponSystemEvents.Buy

	buyevent.OnServerEvent:Connect(function(plr, weapon) print(weapon, plr) OnBuyEvent(weapon) end)


	--=======Alert about a new weapon when round has ended=================
	
	
	--=========Firing an event to show already equipped weapons============
	
	rs.WeaponSystemEvents.GetEquipped:FireClient(player, weaponTable.EquippedWeapons)
	print("fired equipped thing on join, you understand what I mean", weaponTable.EquippedWeapons)
	


	--=========Give "Unlocked" status and price to client==================

	local giveunlockedEvent = rs.WeaponSystemEvents:WaitForChild("GetUnlockStatus")
	local givepriceEvent = rs.WeaponSystemEvents:WaitForChild("GetPrice")
	

	--"unlocked"
	giveunlockedEvent.OnServerInvoke = function(player, weaponName)
		
		for key, wpnData in pairs(weaponTable.OwnedWeapons) do
			warn(key)
			if weaponName == key then
				if wpnData then
					print("success, sent", key, wpnData, "to", player)
					return wpnData
				end
			end
		end
	end
	
	--price
	givepriceEvent.OnServerInvoke = function(player, weaponName)
		for i, priceData in pairs(weaponPrices) do
			if weaponName == priceData.name then
				print("success, sent prices(", priceData.price, ") to", player)
				return priceData.price
			end
		end
	end
	
	
	
	local VulcanGamepassID = 169225577
	local HandshipGamepassID = 1004204303
	
	if MarketPlaceService:UserOwnsGamePassAsync(player.UserId, VulcanGamepassID) then
		GetWeapon("M61 Vulcan")
	end
	
	if MarketPlaceService:UserOwnsGamePassAsync(player.UserId, HandshipGamepassID) then
		GetWeapon("Handship")
	end
end

Players.PlayerAdded:Connect(PlayerAdded)

function PlayerLeaving(player)

	if sessionData[player.UserId] then

		local success, errorMsg = pcall(function()
			Data:SetAsync(player.UserId, sessionData[player.UserId])

		end)

		if success then
		else
			-- If data saving fails, print a warning
			warn("Can't save: " .. player.Name, "|", errorMsg)
		end
	end

	if WeaponSessionData[player.UserId] then
		local success, errorMsg = pcall(function()
			WeaponData:SetAsync(player.UserId, WeaponSessionData[player.UserId])
		end)

		if success then
		else
			-- If data saving fails, print a warning
			warn("Can't save weapons: " .. player.Name, "|", errorMsg, WeaponSessionData[player.UserId])
		end
	end
end

Players.PlayerRemoving:Connect(PlayerLeaving)

function ServerShutdown()
	if RunService:IsStudio() then
		return
	end


	for _, player in ipairs(Players:GetPlayers()) do
		task.spawn(function()
			PlayerLeaving(player)
		end)
	end
end

game:BindToClose(ServerShutdown)

You aren’t really checking if the player argument in the functions of connections to the events like deployEvent or equipEvent is the player that was added in the PlayerAdded function. You should add a check to see if the player is actually the player that was added.

2 Likes

How am I gonna do this? Like the print thing or what? Or comparing player from client to player from server?

Since these are server events (.OnServerEvent), it is received by all connections to those events in the server. You could check if it was sent to the specific player like this:

	local deployEvent = rs.WeaponSystemEvents:WaitForChild("PlayPressed")

	-- Since there is already an argument named "player" in the PlayerAdded function,
	-- the name "playerReceived" should be used to prevent overriding.
	deployEvent.OnServerEvent:Connect(function(playerReceived)

		if playerReceived ~= player then return end

		local primary = weaponTable.EquippedWeapons.Primary
		local secondary = weaponTable.EquippedWeapons.Secondary
		local melee = weaponTable.EquippedWeapons.Melee

		warn("WEAPONS:", primary, secondary, melee)


		EquipWeapons(playerReceived, primary, secondary, melee)
		print("deployed!", playerReceived, primary, secondary, melee)
	end)
2 Likes

Thank you a lot man! I placed that if playerReceived ~= player then return end line in the start of all events, and it works pretty much fine!

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