Player Data Being Updated Incorrectly

I am making a tycoon game. When a player presses one of their buttons (and has enough money to buy it) the game builds the part and updates the player’s data. My buttons in this tycoon are separated into three categories: Structure, Security, and Laptop Upgrades. Naturally. My player data is structured in a table and one of the values is BuildButtons, which is the number of structure buttons the player has pressed. When a player successfully pushes a button and builds the part, it is supposed to add one to the BuildButtons data value. However, it seems to add one to each active player’s BuildButtons data instead.

I would test the game on a local server with two players. Both players would load in and they would be given the default data (which is basically 0 of everything) When Player1 would get a tycoon and build some parts, Player2 would get the other tycoon and all the parts that Player 1 had built would load in for him. The data is being updated for both player 1 and player 2 for some reason that I can’t figure out. My guess is it has something to do with the for loops I use to spread the code across all available tycoons.

What happens in the scripts is this:
It is a tycoon and there will be multiple tycoons so I do have my Structure Script wrapped in a for loop that loops through all the banks in the Banks folder. The Structure Script has a list of buttons. When a button is pressed it uses the BuildScript module script to see if the player has enough money to buy it and if he does the BuildScript builds the instance and returns true to the Structure Script. The structure script then gets the player’s data from the PlayerData module script and adds one to the build buttons value.

Originally I had my BuildScript update the player’s data but I switched it around a bunch of times to try out different ways of doing it and here we are.

Here is my first Structure Script that handles the buttons.

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

local playerData = require(ServerScriptService.PlayerData)
local buildScript = require(ServerScriptService.BuildScripts.BuildScript)
local levelUpEvent = ReplicatedStorage.LevelUp
local cashTableBoughtEvent = ReplicatedStorage.CashTableBought

local banks = workspace.Banks:GetChildren()
for _, bank in banks do
	local securityFolder = bank.Lvl1Security:GetChildren()
	local structureFolder = bank.Structure
	local vaultHousingFolder = bank.VaultHousing
	local vaultFolder = bank.Vault
	local deskFolder = bank.Desks
	local loanOfficeFolder = bank.LoanOffices

	local buttons = {structureFolder.Wall1.Button, structureFolder.Wall2.Button, structureFolder.Wall3.Button, structureFolder.Wall4.Button,
		structureFolder.DoorLeft.Button, structureFolder.DoorRight.Button, vaultHousingFolder.Wall1.Button, vaultHousingFolder.Wall2.Button,
		vaultHousingFolder.Wall3.Button, vaultHousingFolder.Door.Button, vaultFolder.Wall1.Button, vaultFolder.Wall2.Button, vaultFolder.Wall3.Button,
		vaultFolder.Wall4.Button, vaultFolder.Floor.Button, vaultFolder.Ceiling.Button, vaultFolder.VaultDoor.Button, vaultFolder.Locker1.Button,
		vaultFolder.Locker2.Button, vaultFolder.Locker3.Button, vaultFolder.Table.Button, deskFolder.Desk1.Button, deskFolder.Computer1.Button,
		deskFolder.Desk2.Button, deskFolder.NpcComputer.Button, deskFolder.Desk3.Button, deskFolder.NpcComputer1.Button
	}

	--Add the touched function to all of the buttons in the laptop upgrades folder
	for index, button in buttons do
		button.Touched:Connect(function(hit)
			local COST = button.Cost.Value
			local bank = button.Parent.Parent.Parent
			local owner = bank.Owner
			playerData.returnPlayerData(Players:FindFirstChild(hit.Parent.Name).UserId).BuildButtons += 1
			
			
			if not button:GetAttribute("Touched") then
				button:SetAttribute("Touched", true)

				if buildScript.instanceTouched(COST, hit, owner.Value, button.Parent, bank, "Structure") then
					local character = Players:GetPlayerFromCharacter(hit.Parent)

					buildScript.hideButton(button)

					--Activate the next button if there is one
					if #buttons > index then
						buildScript.activateButton(buttons[index+1])
					else
						local addedMoney = math.floor(500 * character.Backpack.Multiplier.Value)
						character.leaderstats.Money.Value += addedMoney
						print("Bank Level 1 Completed. Awarded $" .. addedMoney)

						levelUpEvent:Fire(bank, 1, 1, "Bank", addedMoney)
					end
				end

				task.wait(0.1)
				button:SetAttribute("Touched", false)
			end
		end)
	end
end

Here is my BuildScript module script that checks to see if a player has enough money and then builds the instance.

local BuildScript = {}

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

local playerData = require(ServerScriptService.PlayerData)

local prestigeEvent = ReplicatedStorage.PrestigeActivated
local resetBankEvent = ReplicatedStorage.ResetBank

local function CheckPrice(COST, partTouched, ownerName, instance)
		
	local player = partTouched.Parent

	if player:FindFirstChildWhichIsA("Humanoid") then
		if player.Name == ownerName then
			local character = Players:GetPlayerFromCharacter(player)
			local money = character.leaderstats.Money
			
			if money.Value < COST then
				print("Need $" .. COST - money.Value .. " more")
			else
				money.Value -= COST
				print("Bought " .. instance.Name .. " for $" .. COST)
					
				return true
			end
		else
			print(player.Name .. " is not the owner!")
		end
	end
		
	return false
end

local function modifyPart(part, transparency, canCollide)
	if transparency ~= "_" then
		part.Transparency = transparency
	end
	if canCollide ~= "_" then
		part.CanCollide = canCollide
	end
end

local function BuildInstance(instance, bank)
	if instance:HasTag("Default") then
		if instance.ClassName == "Part" or instance.ClassName == "UnionOperation" or instance.ClassName == "MeshPart" then
			modifyPart(instance, 0, true)
		end
		
		local parts = instance:GetDescendants()
		
		local directParts = instance:GetChildren()
		
		for _, part in directParts do
			if part.Name == "EventFireScript" then
				part.Enabled = true
			end
		end

		for _, part in parts do
			if part:HasTag("Ignore") then
				
			elseif part.ClassName == "Script" or part.ClassName == "SurfaceGui" or part.ClassName == "SpotLight" or part.ClassName == "SurfaceLight" then
				part.Enabled = true
			elseif part.ClassName == "ClickDetector" then
				part.MaxActivationDistance = 20
			elseif part.ClassName == "Part" or part.ClassName == "UnionOperation" then
				if part.Name ~= "Button" then
					modifyPart(part, 0, true)
				end
			elseif part.ClassName == "Decal" then
				part.Transparency = 0
			elseif part.ClassName == "MeshPart" then
				modifyPart(part, 0, true)
			elseif part.ClassName == "Seat" then
				part.CanTouch = true
				part.CanCollide = true
			elseif part.ClassName == "BoolValue" then
				if part:HasTag("True") then
					part.Value = true
				end
			elseif part.ClassName == "Sound" then
				if part:HasTag("Start") then
					part:Play()
				end
			elseif part.ClassName == "BindableEvent" then
				part:Fire(bank)
			end
			
			if part:GetAttribute("Glass") then
				modifyPart(part, part:GetAttribute("Glass"), "_")
			end
			
			if part:HasTag("CantCollide") then
				modifyPart(part, "_", false)
			end
		end
		
	elseif instance:HasTag("CantCollide") then
		modifyPart(instance, 0, false)
        end
end

function BuildScript.instanceTouched(COST, partTouched, ownerName, instance, bank, buttonType)
	if not partTouched.Parent:FindFirstChild("MaxMoney") then
		if CheckPrice(COST, partTouched, ownerName, instance) then
			local successSound = instance.Button.Successful
			successSound:Play()
			
			BuildInstance(instance, bank)
				
			return true
		else
			local failSound = instance.Button.Failure
			failSound:Play()
		end
	end

	return false
end

function BuildScript.hideButton(button)
	if button:FindFirstChild("Highlight") then
		button.Highlight:Destroy()
	end
	button.CanCollide = false
	button.Transparency = 1
	button.BillboardGui.Enabled = false
	button.CanTouch = false
end

function BuildScript.activateButton(button)
	local highLight = Instance.new("Highlight")
	highLight.Parent = button
	highLight.FillColor = button.Color
	highLight.FillTransparency = 0.9
	highLight.OutlineTransparency = 0.8
	
	button.CanCollide = true
	button.Transparency = 0
	button.BillboardGui.AlwaysOnTop = true
	button.BillboardGui.Enabled = true
	button.CanTouch = true
end

function BuildScript.loadProgress(buttonFolder, bank, buttonsPressed, playerData, Datatype)
	if buttonsPressed >= #buttonFolder then
		buttonsPressed = #buttonFolder
	else
		if buttonFolder.Name ~= "StructureButtons" and buttonsPressed ~= 27 then
			if buttonFolder.Name ~= "SecurityButtons" and buttonsPressed ~= 8 then
				if buttonFolder.Name ~= "StructureButtons" and buttonsPressed ~= 57 then
					if buttonFolder.Name ~= "SecurityButtons" and buttonsPressed ~= 26 then
						if buttonFolder.Name ~= "StructureButtons" and buttonsPressed ~= 77 then
							if buttonFolder.Name ~= "SecurityButtons" and buttonsPressed ~= 36 then
								BuildScript.activateButton(buttonFolder[buttonsPressed + 1])
							elseif playerData == 139 then
								BuildScript.activateButton(buttonFolder[buttonsPressed + 1])
							end
						elseif playerData == 36 then
							BuildScript.activateButton(buttonFolder[buttonsPressed + 1])
						end
					elseif playerData == 77 then
						BuildScript.activateButton(buttonFolder[buttonsPressed + 1])
					end
				elseif playerData == 26 then
					BuildScript.activateButton(buttonFolder[buttonsPressed + 1])
				end
			elseif playerData == 57 then
				BuildScript.activateButton(buttonFolder[buttonsPressed + 1])
			end
		elseif playerData == 8 then
			BuildScript.activateButton(buttonFolder[buttonsPressed + 1])
		end
	end
	
	for i = 1, buttonsPressed do
		BuildInstance(buttonFolder[i].Parent, bank)
		BuildScript.hideButton(buttonFolder[i])
	end
end

resetBankEvent.Event:Connect(resetBank)

return BuildScript

Here is my PlayerData module script

local Players = game:GetService("Players")
local playerData = {}

local default = {
	["Money"] = 0,
	["BuildButtons"] = 0, --Max 139 Level 1: 27 Level 2: 57 Level 3: 77 Level 4: 107, 
	["SecurityButtons"] = 0, --Max 45 Level 1: 8 Level 2: 26 Level 3: 36
	["LaptopButtons"] = 0, --Max 5
	["CustomerAccountSystem"] = {},
	["Employees"] = {},
	["Multiplier"] = 1.0,
	["Ads"] = 0, -- Max 5
	["PlayerLevel"] = 1 -- Max 5

}

local dataBase = {}

function playerDataModules.getPlayerData(playerId)
	for key, data in dataBase do
		if key == playerId then
			print(playerId .. "'s data is loading...")
			local player = Players:GetPlayerByUserId(playerId)
			player.leaderstats.Money.Value = data.Money
			print(playerId .. "'s data set!")
			return
		end
	end
	
	print("Could not find player data! Setting default data...")
	dataBase[playerId] = default
	print("Data set!")
end

function playerDataModules.savePlayerData(playerId, player)
	for key, data in dataBase do
		if key == playerId then
			print("Found", playerId .. "'s data. Saving...")
			print(data)
			
			data.Money = player.leaderstats.Money.Value
			return
		end
	end
	
	warn("ERROR: Could not get player's data!")
	playerDataModules.getPlayerData(playerId)
end

function playerDataModules.returnPlayerData(playerId)
	local data = dataBase[playerId]
	if data then
		return data
	end
	
	warn("ERROR: Could not find player's data to return!\nAttempting to set default data...")
	playerDataModules.getPlayerData(playerId)
end

The scripts are modified a little bit. I just cut out the fat that didn’t contribute to this part.

Nobodys helping me which is super cool. So been working at it and doing some thinking. I’ve deduced that it can’t be the Structure Scripts fault because the same issue was happening while the Build Script was handling the player data. I’ve also just done a test where I had preset data for Player 1 but not the other. When Player 1 buys a part it does not get added on to Player 2’s data. Very interesting… :thinking:

I found it! So when a player does not have any data I set the default data that I keep in a variable. I suppose that this variable was linking the two data types together. Maybe they inherited the name or the data was being set weirdly, but I just replaced that variable with the actual data values and it all works perfectly now. Almost done with this tycoon game and can’t wait to release it! I’m literally him.

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