When a player adds items in trade, the same items gets added to the other player's offer in my Trading system

The bug:

In my Trading system, there’s a bug that happens when a player adds items to a trade while the other player’s offer already has items then the code erroneously updates both players’ offers with the added items, though the other player didn’t add those.

After the initiating player correctly triggers the RemoteEvent to add their items, the same event is inappropriately fired for the second player, leading the system to believe they too have added the same items, even though the player who didn’t add hasn’t interacted with the trade UI at all.

I really need any help on this, i’ve been trying to fix this bug for a few days.

Trade Client code: (Showing only the part that handles adding)

local rs = game.ReplicatedStorage:WaitForChild("TradeReplicatedStorage")
local re = rs:WaitForChild("RemoteEvent")
local players = game:GetService("Players")
local player = players.LocalPlayer
local gui = script.Parent
local tradeFrame = gui.MainFrame:WaitForChild("TradeFrame")
local replicatedStorage = game:GetService("ReplicatedStorage")
local addGameButton = tradeFrame.Buttons.AddGame
local inventoryFrame = gui.Frame2.InventoryBackground
local buttonConnections = {}
local addedGames = {}
-- rest of variables...

addGameButton.MouseButton1Click:Connect(function()
	inventoryFrame.Visible = true
	local inventoryList = inventoryFrame.Handler

	-- Setup item selection and adding to trade
	for i, child in pairs(inventoryList:GetChildren()) do
		if child:IsA("TextButton") then
			-- Disconnect any existing connection on this child to avoid duplicates
			if buttonConnections[child] then
				buttonConnections[child]:Disconnect()
				buttonConnections[child] = nil -- Clear the old connection
			end

			-- Connect new MouseButton1Click event and store the connection
			buttonConnections[child] = child.MouseButton1Click:Connect(function()
				if buttonConnections[child] then
					buttonConnections[child]:Disconnect()
					buttonConnections[child] = nil -- Clear the old connection
				end
				child.Parent = replicatedStorage
				local clonedChild = child:Clone()
				clonedChild.Size = UDim2.new(0.1, 0, 0.998, 0)
				clonedChild.Parent = tradeFrame.TradingFrame.YourOfferFrame.Slots
				local playerKey = player.Name -- Assuming 'player' is the local player variable
				addedGames[playerKey] = addedGames[playerKey] or {} -- Initialize player-specific table if not exists

				-- Add clonedChild's PlaceId to the player-specific addedGames table

				table.insert(addedGames[playerKey], clonedChild.PlaceId.Value)
				print("Added items for " .. playerKey .. ":")
				print(addedGames[playerKey])

				re:FireServer("add item to trade", addedGames[playerKey])
				-- Remove item from trade on click in the trade window
				clonedChild.MouseButton1Click:Connect(function()
					-- Remove the clonedChild and its PlaceId from the table
					for index, placeId in ipairs(addedGames) do
						if placeId == clonedChild.PlaceId.Value then
							table.remove(addedGames, index)
							break
						end
					end

					if buttonConnections[child] then
						buttonConnections[child]:Disconnect()
						buttonConnections[child] = nil -- Clear the old connection
					end

					re:FireServer("remove item from trade", clonedChild.PlaceId.Value)
					clonedChild:Destroy()
					child.Parent = inventoryList
				end)
			end)
		end
	end
end)

-- rest of code...

Trade Server code: (Showing only the part that handles adding)

--VARIABLES
local HttpService = game:GetService("HttpService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local rs = game.ReplicatedStorage:WaitForChild("TradeReplicatedStorage")
local re = rs:WaitForChild("RemoteEvent")
local config = require(rs:WaitForChild("CONFIGURATION"))

local tradeRequestsFolder = Instance.new("Folder")
tradeRequestsFolder.Name = "TRADE REQUESTS"
tradeRequestsFolder.Parent = rs

local ongoingTradesFolder = Instance.new("Folder")
ongoingTradesFolder.Name = "ONGOING TRADES"	
ongoingTradesFolder.Parent = rs

local getGameDataForTradeEvent = replicatedStorage:WaitForChild("GetGameDataForTrade")
local sendGameDataForTrade = replicatedStorage:WaitForChild("SendGameDataForTrade")
local getInventoryOfPlayer = replicatedStorage:WaitForChild("GetInventoryOfPlayer")
local sendPlayerInventory = replicatedStorage:WaitForChild("SendPlayerInventory")
local getGamesDataForTradeEvent = replicatedStorage:WaitForChild("GetGamesDataForTrade")
local sendGamesDataForTrade = replicatedStorage:WaitForChild("SendGamesDataForTrade")

--REMOVE TRADES FOR THIS PLAYER
function removeTrades(plr)
	for i, trade in pairs(ongoingTradesFolder:GetChildren()) do
		if trade.Sender.Value == plr.Name or trade.Receiver.Value == plr.Name then
			trade:Destroy()
		end
	end

	for i, request in pairs(tradeRequestsFolder:GetChildren()) do
		if request.Name == plr.Name or request.Value == plr.Name then
			request:Destroy()
		end
	end
end

-- trunacted code...

--RECEIVE CLIENT INFORMATION
re.OnServerEvent:Connect(function(plr, instruction, data)
	local tradeFolder = nil
	-- trunacted code...
	if instruction == "accept trade request" then

		local requestValue = nil
		for i, request in pairs(tradeRequestsFolder:GetChildren()) do
			if request.Name == plr.Name or request.Value == plr.Name then
				requestValue = request
				break
			end
		end

		if requestValue.Parent == tradeRequestsFolder and requestValue.Value == plr.Name then

			local senderPlr = game.Players[requestValue.Name]
			local receiverPlr = game.Players[requestValue.Value]


			requestValue:Destroy()

			tradeFolder = Instance.new("Folder")

			local senderValue = Instance.new("StringValue")
			senderValue.Name = "Sender"
			senderValue.Value = senderPlr.Name
			senderValue.Parent = tradeFolder

			local receiverValue = Instance.new("StringValue")
			receiverValue.Name = "Receiver"
			receiverValue.Value = receiverPlr.Name
			receiverValue.Parent = tradeFolder

			local senderOffer = Instance.new("Folder")
			senderOffer.Name = senderPlr.Name .. "'s offer"
			senderOffer.Parent = tradeFolder

			local receiverOffer = Instance.new("Folder")
			receiverOffer.Name = receiverPlr.Name .. "'s offer"
			receiverOffer.Parent = tradeFolder

			tradeFolder.Parent = ongoingTradesFolder
		end


		--Add an item to the trade
	elseif instruction == "add item to trade" then
		local clientData = data
		local gameIds = {}

		local senderGamesData = nil

		getGamesDataForTradeEvent:Fire(data)

		sendGamesDataForTrade.Event:Connect(function(encodedGameData)
			senderGamesData = HttpService:JSONDecode(encodedGameData)
			print("Receieved encoded data:")
			print(senderGamesData)
			local currentTrade = nil

			for i, trade in pairs(ongoingTradesFolder:GetChildren()) do
				if trade.Sender.Value == plr.Name or trade.Receiver.Value == plr.Name then
					currentTrade = trade
					break
				end
			end

			if currentTrade then

				local plrSlots = currentTrade[plr.Name .. "'s offer"]
				print(plr.Name .. ", did you add? If did that good. If not, NOOOOOO!")

				-- culprit 1
				for i, slot in pairs(plrSlots:GetChildren()) do
					slot:Destroy()
				end

				local numItems = #senderGamesData

				if numItems < config.MaxSlots then
					for i, senderGameData in pairs(senderGamesData) do
						local itemInTrade = false
						for i, plrItem in pairs(plrSlots:GetChildren()) do
							print("Trading id: " .. plrItem.placeId.Value)
							if plrItem.placeId.Value == senderGameData.placeId then
								itemInTrade = true
								print("DONT DUPLICATE PLSSSSS")
								break
							end
						end

						if not itemInTrade then

							if currentTrade.Receiver:FindFirstChild("ACCEPTED") then
								currentTrade.Receiver.ACCEPTED:Destroy()
							end
							if currentTrade.Sender:FindFirstChild("ACCEPTED") then
								currentTrade.Sender.ACCEPTED:Destroy()
							end
						end

						-- Create a folder to hold all data as StringValues, named after the placeId if it exists
						local dataFolder = Instance.new("Folder")
						dataFolder.Name = tostring(senderGameData.placeId or "UnknownPlaceId")

						-- Function to convert and add data to the folder
						local function addDataToFolder(dataTable, parentFolder) -- IMPOSTER CAUGHT
							for key, value in pairs(dataTable) do
								-- Check if the value is another table; if so, create a subfolder and recurse
								if typeof(value) == "table" then
									local subFolder = Instance.new("Folder")
									subFolder.Name = key
									subFolder.Parent = parentFolder
									addDataToFolder(value, subFolder)  -- Recursive call for nested tables
								else
									local stringValue = Instance.new("StringValue")
									stringValue.Name = key
									stringValue.Value = tostring(value)  -- Convert the value to a string to ensure consistency
									stringValue.Parent = parentFolder
								end
							end
						end

						-- Populate the data folder with data from senderGameData
						addDataToFolder(senderGameData, dataFolder)

						dataFolder.Parent = plrSlots
					end
				end
			end
		end)	
	end
	-- trunacted code...
end)

-- rest of code...

The server side adjustment

-- Inside "add item to trade" event
if instruction == "add item to trade" then
    local currentTrade = findTradeForPlayer(plr)
    if currentTrade then
        updatePlayerOffer(plr, currentTrade, data) -- Implement this function
    end
end

It seems like the issue lies in how the server handles the “add item to trade” instruction from the client. Specifically, when the server receives this instruction, it iterates over the slots in the player’s offer and destroys them, which is likely unintended behavior. This action wipes out any existing items in the trade, leading to the problem where items from one player’s offer are erroneously added to the other player’s offer.

To fix this issue, you need to modify the server code to correctly handle the addition of items to the trade without destroying existing items. Here’s a suggested modification to address this problem:

--VARIABLES
local HttpService = game:GetService("HttpService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local rs = game.ReplicatedStorage:WaitForChild("TradeReplicatedStorage")
local re = rs:WaitForChild("RemoteEvent")
local config = require(rs:WaitForChild("CONFIGURATION"))

local tradeRequestsFolder = Instance.new("Folder")
tradeRequestsFolder.Name = "TRADE REQUESTS"
tradeRequestsFolder.Parent = rs

local ongoingTradesFolder = Instance.new("Folder")
ongoingTradesFolder.Name = "ONGOING TRADES"	
ongoingTradesFolder.Parent = rs

local getGameDataForTradeEvent = replicatedStorage:WaitForChild("GetGameDataForTrade")
local sendGameDataForTrade = replicatedStorage:WaitForChild("SendGameDataForTrade")
local getInventoryOfPlayer = replicatedStorage:WaitForChild("GetInventoryOfPlayer")
local sendPlayerInventory = replicatedStorage:WaitForChild("SendPlayerInventory")
local getGamesDataForTradeEvent = replicatedStorage:WaitForChild("GetGamesDataForTrade")
local sendGamesDataForTrade = replicatedStorage:WaitForChild("SendGamesDataForTrade")

--REMOVE TRADES FOR THIS PLAYER
function removeTrades(plr)
	for i, trade in pairs(ongoingTradesFolder:GetChildren()) do
		if trade.Sender.Value == plr.Name or trade.Receiver.Value == plr.Name then
			trade:Destroy()
		end
	end

	for i, request in pairs(tradeRequestsFolder:GetChildren()) do
		if request.Name == plr.Name or request.Value == plr.Name then
			request:Destroy()
		end
	end
end

-- trunacted code...

--RECEIVE CLIENT INFORMATION
re.OnServerEvent:Connect(function(plr, instruction, data)
    -- truncated code...
    if instruction == "add item to trade" then
        local clientData = data
        local gameIds = {}

        local senderGamesData = nil

        getGamesDataForTradeEvent:Fire(data)

        sendGamesDataForTrade.Event:Connect(function(encodedGameData)
            senderGamesData = HttpService:JSONDecode(encodedGameData)
            print("Received encoded data:")
            print(senderGamesData)
            local currentTrade = nil

            for i, trade in pairs(ongoingTradesFolder:GetChildren()) do
                if trade.Sender.Value == plr.Name or trade.Receiver.Value == plr.Name then
                    currentTrade = trade
                    break
                end
            end

            if currentTrade then
                local plrSlots = currentTrade[plr.Name .. "'s offer"]

                local numItems = #senderGamesData

                if numItems < config.MaxSlots then
                    for i, senderGameData in pairs(senderGamesData) do
                        local itemInTrade = false
                        for i, plrItem in pairs(plrSlots:GetChildren()) do
                            print("Trading id: " .. plrItem.placeId.Value)
                            if plrItem.placeId.Value == senderGameData.placeId then
                                itemInTrade = true
                                print("DON'T DUPLICATE PLEASE")
                                break
                            end
                        end

                        if not itemInTrade then
                            if currentTrade.Receiver:FindFirstChild("ACCEPTED") then
                                currentTrade.Receiver.ACCEPTED:Destroy()
                            end
                            if currentTrade.Sender:FindFirstChild("ACCEPTED") then
                                currentTrade.Sender.ACCEPTED:Destroy()
                            end
                        end

                        -- Create a folder to hold all data as StringValues, named after the placeId if it exists
                        local dataFolder = Instance.new("Folder")
                        dataFolder.Name = tostring(senderGameData.placeId or "UnknownPlaceId")

                        -- Function to convert and add data to the folder
                        local function addDataToFolder(dataTable, parentFolder)
                            for key, value in pairs(dataTable) do
                                -- Check if the value is another table; if so, create a subfolder and recurse
                                if typeof(value) == "table" then
                                    local subFolder = Instance.new("Folder")
                                    subFolder.Name = key
                                    subFolder.Parent = parentFolder
                                    addDataToFolder(value, subFolder)  -- Recursive call for nested tables
                                else
                                    local stringValue = Instance.new("StringValue")
                                    stringValue.Name = key
                                    stringValue.Value = tostring(value)  -- Convert the value to a string to ensure consistency
                                    stringValue.Parent = parentFolder
                                end
                            end
                        end

                        -- Populate the data folder with data from senderGameData
                        addDataToFolder(senderGameData, dataFolder)

                        dataFolder.Parent = plrSlots
                    end
                end
            end
        end)
    end
    -- truncated code...
end)

This modification ensures that the server does not destroy existing items in the player’s offer when new items are added to the trade. It maintains the integrity of each player’s offer and should resolve the issue you’re experiencing with items erroneously being added to both players’ offers.

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