Whenever I Click My Exit Button For My UI Then Come Back To Buy Something In The UI Everything Bought Doubles

So pretty much whenever I first go into my in-game shop everything is normal until I click out of it then come back then everything I buy then doubles and then again and again. I have no clue why, I will put my whole code in here. Am I missing something? Please help, much appreciated.

ReplicatedStorage.Remotes.UIRemotes.UI_BoardStart.OnClientEvent:Connect(function(TeamName)

	local Tycoon = Workspace:WaitForChild("Tycoon").Tycoons:WaitForChild(TeamName)
	local Board =  Tycoon.PurchasedObjects.Office.Whiteboard
	local BoardCam = Board.BoardCamera
	local PlayerName = LocalPlayer.Name

	local Owner = Tycoon.TycoonInfo.Owner
	
	if Owner.Value.Name == PlayerName then
		

	
	
	Camera.CameraType = Enum.CameraType.Scriptable
	
	--// Some Presets
	MainFrame.TeamName.Text = LocalPlayer.ValuesGame.TeamName.Value
	--// Labels

	
	MainFrame.Exit.MouseButton1Click:Connect(function(plr)
		ClickUI:Play()
		MainFrame.Visible = false
		Camera.CameraType = Enum.CameraType.Custom
		Camera.CameraSubject = LocalPlayer.Character.Humanoid
	end)
	
	MainFrame.PassButton.MouseButton1Click:Connect(function(plr) -- PASS PURCHASE ATTRIBUTES SCREEN
		ClickUI:Play()
		MainFrame.PassPurchase.Visible = true
	end)
	


	MainFrame.PassPurchase.Purchase.MouseButton1Click:Connect(function(plr)
		if LocalPlayer.ValuesGame.Team.PassGame.Value >= 10 then
			print("Pass Game Maxed Out")
			MainFrame.PassPurchase.PurchaseLabel.Text = "Your pass attributes are maxed out!"
			task.wait(3)
			MainFrame.PassPurchase.PurchaseLabel.Text = "Purchase 1 Pass Attribute For ".. CurrentPassCost .. " Cash?"
		else
			if LocalPlayer.leaderstats.Cash.Value <= CurrentPassCost then
				ErrorUI:Play()
				MainFrame.PassPurchase.PurchaseLabel.Text = "You cannot afford an attribute!"
				task.wait(3)
				MainFrame.PassPurchase.PurchaseLabel.Text = "Purchase 1 Pass Attribute For ".. CurrentPassCost .. " Cash?"
			else
				ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchasePassAttribute:FireServer(CurrentPassCost,TeamName)
				print("" ..LocalPlayer.Name.. " Purchased an attribute for ".. CurrentPassCost ..    "")
				MainFrame.PassPurchase.Visible = false
				SoundService.PurchaseCompleted:Play()
				--	MainFrame.PassPurchase.Visible = false
			end
		end
	end)
	
	MainFrame.PassPurchase.Decline.MouseButton1Click:Connect(function(plr)
		ClickUI:Play()
		MainFrame.PassPurchase.Visible = false
	end)
	
	
	--===
	MainFrame.RunButton.MouseButton1Click:Connect(function(plr) -- PASS PURCHASE ATTRIBUTES SCREEN
		ClickUI:Play()
		MainFrame.RunPurchase.Visible = true
	end)

	MainFrame.RunPurchase.Purchase.MouseButton1Click:Connect(function(plr)
		if LocalPlayer.ValuesGame.Team.RunGame.Value >= 10 then
			print("Pass Game Maxed Out")
			MainFrame.RunPurchase.PurchaseLabel.Text = "Your run attributes are maxed out!"
			task.wait(3)
			MainFrame.RunPurchase.PurchaseLabel.Text = "Purchase 1 Run Attribute For ".. CurrentPassCost .. " Cash?"
		else
			if LocalPlayer.leaderstats.Cash.Value <= CurrentPassCost then
				ErrorUI:Play()
				MainFrame.RunPurchase.PurchaseLabel.Text = "You cannot afford an attribute!"
				task.wait(3)
				MainFrame.RunPurchase.PurchaseLabel.Text = "Purchase 1 Run Attribute For ".. CurrentPassCost .. " Cash?"
			else
				ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchaseRunAttribute:FireServer(CurrentPassCost,TeamName)
				print("" ..LocalPlayer.Name.. " Purchased an attribute for ".. CurrentPassCost ..    "")
				MainFrame.RunPurchase.Visible = false
				SoundService.PurchaseCompleted:Play()
				--	MainFrame.PassPurchase.Visible = false
			end
		end
	end)

	MainFrame.RunPurchase.Decline.MouseButton1Click:Connect(function(plr)
		ClickUI:Play()
		MainFrame.RunPurchase.Visible = false
	end)
	
	--//
	
	local CamTweenBoard = TweenService:Create(Camera,TweenInfo.new(
		1,
		Enum.EasingStyle.Quad,
		Enum.EasingDirection.In),
		{
			CFrame = BoardCam.CFrame
		})
	
	SoundService.Chalk:Play()
	CamTweenBoard:Play()
	CamTweenBoard.Completed:Wait()
	
	MainFrame.Visible = true
	
	end
end)
2 Likes

You are binding all your UI events every time UI_BoardStart.OnClientEvent is triggered. Every time this event is triggered, you will have another set duplicate of UI events.

1 Like

Okay understandable, opposing I would have to unbind it somehow, what would be the best way to?

You would have to assign all the event connections (RBXScriptConnection) into accessible variables or some shared table and disconnect them when you no longer need them to trigger.

However, it is likely a better approach to simply connect your UI events once and instead use some shared state to allow/disallow the events to have any effect.

What is the purpose of the UI_BoardStart RemoteEvent? When and why is it triggered by the server?

When the player uses a proximity prompt in the workspace when they walk up to the board fires the client event to then allow them to see the UI.

By that I would have to pretty much rework the variable (team name) I’m taking from the server?

Oh, I see. So TeamName has an impact on what the player sees in the shop? What is TeamName and is it information known by the client (LocalPlayer)?

When the player buys something from the client side using the shop, it then sends a remote event to the server to take their cash (leaderstats) using this code in serverscript service (teamname is the name of the players tycoon which is also the name of the players folder where the money is stored in the server)

ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchasePassAttribute.OnServerEvent:Connect(function(plr, CurrentPassCost, TeamName)
	if plr.leaderstats.Cash.Value <= CurrentPassCost then	
		-- Player Doesn't Have Enough Cash
		print("player doesn't have enough cash")
		ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchaseNo:FireClient(plr)
	else
		local tcnInfo = Workspace:WaitForChild("Tycoon").Tycoons:FindFirstChild(TeamName):WaitForChild("TycoonInfo")
		local cash = game.ServerStorage:WaitForChild("PlayerCash"):FindFirstChild(tcnInfo.Owner.Value.Name)
		cash.Value -= CurrentPassCost
		plr.ValuesGame.Team.PassGame.Value += 1
		ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchasePassAttribute:FireClient(plr)
		
		--print("" ..plr.Name.. " Purchased an attribute for ".. CurrentPassCost ..    "")
		
	end
end)
ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchaseRunAttribute.OnServerEvent:Connect(function(plr, CurrentPassCost, TeamName)
	if plr.leaderstats.Cash.Value <= CurrentPassCost then	
		-- Player Doesn't Have Enough Cash
		print("player doesn't have enough cash")
		ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchaseNo1:FireClient(plr)
	else
		local tcnInfo = Workspace:WaitForChild("Tycoon").Tycoons:FindFirstChild(TeamName):WaitForChild("TycoonInfo")
		local cash = game.ServerStorage:WaitForChild("PlayerCash"):FindFirstChild(tcnInfo.Owner.Value.Name)
		cash.Value -= CurrentPassCost
		plr.ValuesGame.Team.RunGame.Value += 1
		ReplicatedStorage.Remotes.Tycoon_Function_Remotes.White_Board.PurchaseRunAttribute:FireClient(plr)

		--print("" ..plr.Name.. " Purchased an attribute for ".. CurrentPassCost ..    "")

	end
end)

this is to determine the players tycoon which the players cash is set up in serverstorage and then subtracts that amount from their leaderstats which is how I set up the tycoon aspect of the game.

I use teamname from the proximity prompt to bring it over to the client for the most simple way under my knowledge of coding so far, must be an easier way, im trying to figure out how to make it so these don’t double which with what you said before is pretty self explanatory. But currently I don’t know how to fix it.

(edit)
teamname has no significant changes to the shop other than bringing the value of the purchase to the server to take the players cash.

When you connect to an event (RBXScriptSignal), using the :Connect() method, it returns a RBXScriptConnection. This instance has the method :Disconnect() which can be used to remove the function bound to the event.

local part = Instance.new("Part", workspace)
local partTouchedSignal = part.Touched:Connect(function()
   print("Part touched")
end)
task.wait(30)
partTouchedSignal:Disconnect() --After 30 seconds, "Part touched" will no longer print even when the Part is touched.

Although this is a bit unorthodox, this approach could technically be used to connect your UI events (after the RemoteEvent is triggered) and disconnect them (after the shop is closed).

this would go in the prox prompt script correct?

The code block was simply an example of how to connect to an event and later disconnect it. It has nothing to do with your UI system.

I tried messing around with it, I still don’t quite understand.