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...