Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
local ReplicatedStorage = game:GetService("ReplicatedStorage") local HttpService = game:GetService("HttpService") local Players = game:GetService("Players") local UnitConfig = require(ReplicatedStorage.Databases.UnitConfig) local BadgeData = require(ReplicatedStorage.Databases.BadgeData) local GeneralData = require(ReplicatedStorage.Databases.GeneralData) local Common = require(ReplicatedStorage.Common) local Sound = require(ReplicatedStorage.Shared.Sound) local Server = require(ReplicatedStorage.Blink.Server) local TRADE_TIMEOUT = 120 local MAX_TRADE_UNITS = 8 local TRADE_COOLDOWN = 5 local TRADE_EXECUTION_DELAY = 5 local function generateTradeId() return HttpService:GenerateGUID() end local function isValidUnit(unitId, playerData) return playerData.Inventory.Units[unitId] ~= nil end local function getPlayerInventoryCount(playerData) local count = 0 for _ in pairs(playerData.Inventory.Units) do count = count + 1 end return count end local function getMaxUnitsForPlayer(playerData) local maxUnits = GeneralData.Settings.Default_MaxUnits or 100 local owned = (playerData and playerData.Gamepasses) or {} local storagePassBonus = { [1462584282] = 50, [1462564275] = 50, [1298364212] = 50, } for passId, bonus in pairs(storagePassBonus) do if table.find(owned, passId) then maxUnits += bonus end end return maxUnits end local function validateInventorySpaceAfterTrade(playerData, unitsToAdd, unitsToGive) local addCount, giveCount = 0, 0 for _ in pairs(unitsToAdd or {}) do addCount += 1 end for _ in pairs(unitsToGive or {}) do giveCount += 1 end local currentCount = getPlayerInventoryCount(playerData) local maxUnits = getMaxUnitsForPlayer(playerData) local finalCount = currentCount - giveCount + addCount return finalCount <= maxUnits end local function validateInventorySpace(playerData, unitsToAdd) local currentCount = getPlayerInventoryCount(playerData) local maxUnits = GeneralData.Settings.Default_MaxUnits if playerData and playerData.Gamepasses then if table.find(playerData.Gamepasses, 1298364212) then maxUnits = maxUnits + 50 end end local unitsToAddCount = 0 for _ in pairs(unitsToAdd) do unitsToAddCount = unitsToAddCount + 1 end return currentCount + unitsToAddCount <= maxUnits end local TradingManager = {} TradingManager.activeTrades = {} TradingManager.playerCooldowns = {} TradingManager.tradeRequests = {} function TradingManager:Init(gameModule) self.game = gameModule Server.SendTradeRequest.On(function(sender, payload) local targetUserId if typeof(payload) == "table" and payload.UserId then targetUserId = tonumber(payload.UserId) elseif typeof(payload) == "number" then local function toSignedI32(n: number): number local r = n % 4294967296 if r >= 2147483648 then r -= 4294967296 end return r end local receivedI32 = payload for _, p in ipairs(Players:GetPlayers()) do if toSignedI32(p.UserId) == receivedI32 then targetUserId = p.UserId break end end if not targetUserId then for _, p in ipairs(Players:GetPlayers()) do end Server.UI.Fire(sender, {UI = "HUD", Function = "Notify", Arguments = {"Player not found!", 3, "Error"}}) return end else Server.UI.Fire(sender, {UI = "HUD", Function = "Notify", Arguments = {"Player not found!", 3, "Error"}}) return end return self:SendTradeRequest(sender, targetUserId) end) Server.AcceptTrade.On(function(player, struct) return self:RespondToTradeRequest(player, struct) end) Server.AddUnitToTrade.On(function(player, struct) return self:AddUnitsToTrade(player, struct) end) Server.RemoveUnitFromTrade.On(function(player, struct) return self:RemoveUnitFromTrade(player, struct) end) Server.ConfirmTrade.On(function(player, struct) return self:ConfirmTrade(player, struct) end) Server.CancelTrade.On(function(player, struct) return self:CancelTrade(player, struct) end) Players.PlayerRemoving:Connect(function(player) self:HandlePlayerLeaving(player) end) local debounce = {} if workspace:FindFirstChild("TradePortal") then workspace.TradePortal.PrimaryPart.Touched:Connect(function(hit) local player = game.Players:GetPlayerFromCharacter(hit.Parent) if not player or debounce[player] then return end debounce[player] = true task.delay(1, function() debounce[player] = nil end) Server.UI.Fire(player, {UI = "HUD", Function = "Transition", Arguments = {}}) game["Teleport Service"]:Teleport(98293630968682, player) end) end if workspace:FindFirstChild("LobbyPortal") then workspace.LobbyPortal.PrimaryPart.Touched:Connect(function(hit) local player = game.Players:GetPlayerFromCharacter(hit.Parent) if not player or debounce[player] then return end debounce[player] = true Server.UI.Fire(player, {UI = "HUD", Function = "Transition", Arguments = {}}) game["Teleport Service"]:Teleport(134765553595771, player) task.delay(1, function() debounce[player] = nil end) end) end task.spawn(function() while true do task.wait(10) self:CleanupExpiredTrades() end end) end function TradingManager:HandlePlayerLeaving(player) local trade = self.activeTrades[player.UserId] if trade then if trade.executionTimer then task.cancel(trade.executionTimer) trade.executionTimer = nil end local otherPlayer = trade.player1 == player and trade.player2 or trade.player1 if otherPlayer then Server.UI.Fire(otherPlayer, { UI = "Trade", Function = "CancelTrade", Arguments = {CancelledBy = player.Name .. " (Disconnected)"} }) end self.activeTrades[trade.player1.UserId] = nil self.activeTrades[trade.player2.UserId] = nil end for dequestKey, request in pairs(self.tradeRequests) do if request.sender == player or request.receiver == player then self.tradeRequests[dequestKey] = nil end end self.playerCooldowns[player.UserId] = nil end function TradingManager:IsPlayerOnCooldown(player) local cooldownEnd = self.playerCooldowns[player.UserId] return cooldownEnd and os.time() < cooldownEnd end function TradingManager:SetPlayerCooldown(player) self.playerCooldowns[player.UserId] = os.time() + TRADE_COOLDOWN end function TradingManager:SendTradeRequest(player, playerId) local targetPlayer = Players:GetPlayerByUserId(playerId) if not targetPlayer then for _, p in ipairs(Players:GetPlayers()) do end Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"Player not found!", 3, "Error"}}) return end if targetPlayer == player then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"Cannot trade with yourself!", 3, "Error"}}) return end if self:IsPlayerOnCooldown(player) then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"You are on trade cooldown!", 3, "Error"}}) return end local senderData = self.game.dataManager:GetPlayerData(player, true) if not senderData then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"Failed to load your data!", 3, "Error"}}) return end local targetPlayerData = self.game.dataManager:GetPlayerData(targetPlayer, true) if not targetPlayerData then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"Failed to load player data!", 3, "Error"}}) return end if self.activeTrades[player.UserId] then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"You are already in a trade!", 3, "Error"}}) return end if self.activeTrades[targetPlayer.UserId] then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {targetPlayer.Name.." is already in a trade!", 3, "Error"}}) return end if targetPlayerData.Settings then end if targetPlayerData.Settings and targetPlayerData.Settings.TradeInvites == false then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"This player has trade invites disabled!", 3, "Error"}}) return end Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"Sent trade invite to "..targetPlayer.Name.."!", 3, "Success"}}) local dequestKey = player.UserId .. "_" .. targetPlayer.UserId local reverseKey = targetPlayer.UserId .. "_" .. player.UserId if self.tradeRequests[dequestKey] or self.tradeRequests[reverseKey] then return end self.tradeRequests[dequestKey] = { sender = player, receiver = targetPlayer, timestamp = os.time() } Server.UI.Fire(targetPlayer, { UI = "Trade", Function = "DisplayTradeRequest", Arguments = { SenderName = player.Name, SenderId = player.UserId, DequestKey = dequestKey } }) task.delay(15, function() self.tradeRequests[dequestKey] = nil end) end function TradingManager:RespondToTradeRequest(player, struct) local request = self.tradeRequests[struct.DequestKey] if not request or request.receiver ~= player then return end local sender = request.sender self.tradeRequests[struct.DequestKey] = nil if not struct.Accepted then Server.UI.Fire(sender, {UI = "HUD", Function = "Notify", Arguments = {player.Name.." declined your trade request!", 3, "Error"}}) return end local senderData = self.game.dataManager:GetPlayerData(sender, true) local receiverData = self.game.dataManager:GetPlayerData(player, true) if not senderData or not receiverData then return end if self.activeTrades[sender.UserId] or self.activeTrades[player.UserId] then return end local tradeId = generateTradeId() local tradeData = { id = tradeId, player1 = sender, player2 = player, player1_units = {}, player2_units = {}, player1_confirmed = false, player2_confirmed = false, timestamp = os.time(), status = "active", executionTimer = nil, executionStartTime = nil } self.activeTrades[sender.UserId] = tradeData self.activeTrades[player.UserId] = tradeData Server.UI.Fire(sender, { UI = "Trade", Function = "StartTrade", Arguments = { TradeId = tradeId, PartnerName = player.Name, PartnerId = player.UserId } }) Server.UI.Fire(player, { UI = "Trade", Function = "StartTrade", Arguments = { TradeId = tradeId, PartnerName = sender.Name, PartnerId = sender.UserId } }) end function TradingManager:AddUnitsToTrade(player, struct) local trade = self.activeTrades[player.UserId] if not trade or trade.status ~= "active" then return end local playerData = self.game.dataManager:GetPlayerData(player, true) if not playerData then return end local isPlayer1 = trade.player1 == player local currentUnits = isPlayer1 and trade.player1_units or trade.player2_units local currentUnitCount = 0 for _ in pairs(currentUnits) do currentUnitCount = currentUnitCount + 1 end if currentUnitCount + #struct.UnitIds > MAX_TRADE_UNITS then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"Cannot add more than "..MAX_TRADE_UNITS.." units to trade!", 3, "Error"}}) return end for _, unitId in ipairs(struct.UnitIds) do if not isValidUnit(unitId, playerData) then Server.UI.Fire(player, {UI = "HUD", Function = "Notify", Arguments = {"Invalid unit!", 3, "Error"}}) return end currentUnits[unitId] = playerData.Inventory.Units[unitId] end trade.player1_confirmed = false trade.player2_confirmed = false if trade.executionTimer then task.cancel(trade.executionTimer) trade.executionTimer = nil trade.executionStartTime = nil end self:UpdateTradeDisplay(trade) end function TradingManager:RemoveUnitFromTrade(player, struct) local trade = self.activeTrades[player.UserId] if not trade or trade.status ~= "active" then return end local playerData = self.game.dataManager:GetPlayerData(player, true) if not playerData then return end local isPlayer1 = trade.player1 == player local currentUnits = isPlayer1 and trade.player1_units or trade.player2_units local unitId = struct.UnitId if not unitId or not currentUnits[unitId] then return end currentUnits[unitId] = nil trade.player1_confirmed = false trade.player2_confirmed = false if trade.executionTimer then task.cancel(trade.executionTimer) trade.executionTimer = nil trade.executionStartTime = nil end self:UpdateTradeDisplay(trade) end function TradingManager:ConfirmTrade(player, struct) local trade = self.activeTrades[player.UserId] if not trade or trade.status ~= "active" then return end local player1Data = self.game.dataManager:GetPlayerData(trade.player1, true) local player2Data = self.game.dataManager:GetPlayerData(trade.player2, true) if not player1Data or not player2Data then return end if not validateInventorySpaceAfterTrade(player1Data, trade.player2_units, trade.player1_units) or not validateInventorySpaceAfterTrade(player2Data, trade.player1_units, trade.player2_units) then Server.UI.Fire(trade.player1, {UI = "HUD", Function = "Notify", Arguments = {"Not enough inventory space to complete trade!", 3, "Error"}}) Server.UI.Fire(trade.player2, {UI = "HUD", Function = "Notify", Arguments = {"Not enough inventory space to complete trade!", 3, "Error"}}) return end local isPlayer1 = trade.player1 == player if isPlayer1 then trade.player1_confirmed = not trade.player1_confirmed else trade.player2_confirmed = not trade.player2_confirmed end if trade.executionTimer and ((isPlayer1 and not trade.player1_confirmed) or (not isPlayer1 and not trade.player2_confirmed)) then task.cancel(trade.executionTimer) trade.executionTimer = nil trade.executionStartTime = nil end if trade.player1_confirmed and trade.player2_confirmed and not trade.executionTimer then return self:StartTradeExecution(trade) end self:UpdateTradeDisplay(trade) end function TradingManager:StartTradeExecution(trade) trade.executionStartTime = os.time() trade.executionTimer = task.delay(TRADE_EXECUTION_DELAY, function() if trade.player1_confirmed and trade.player2_confirmed and trade.status == "active" then self:ExecuteTrade(trade) else trade.executionTimer = nil trade.executionStartTime = nil end end) self:UpdateTradeDisplay(trade) end function TradingManager:UpdateTradeDisplay(trade) local executionTimeRemaining = nil if trade.executionStartTime then executionTimeRemaining = TRADE_EXECUTION_DELAY - (os.time() - trade.executionStartTime) end Server.UI.Fire(trade.player1, { UI = "Trade", Function = "UpdateTrade", Arguments = { Player1 = trade.player1, Player2 = trade.player2, Player1Units = trade.player1_units, Player2Units = trade.player2_units, Player1Confirmed = trade.player1_confirmed, Player2Confirmed = trade.player2_confirmed, IsExecuting = trade.executionTimer ~= nil, ExecutionTimeRemaining = executionTimeRemaining } }) Server.UI.Fire(trade.player2, { UI = "Trade", Function = "UpdateTrade", Arguments = { Player1 = trade.player1, Player2 = trade.player2, Player1Units = trade.player1_units, Player2Units = trade.player2_units, Player1Confirmed = trade.player1_confirmed, Player2Confirmed = trade.player2_confirmed, IsExecuting = trade.executionTimer ~= nil, ExecutionTimeRemaining = executionTimeRemaining } }) end function TradingManager:ExecuteTrade(trade) local player1Data = self.game.dataManager:GetPlayerData(trade.player1, true) local player2Data = self.game.dataManager:GetPlayerData(trade.player2, true) if not player1Data or not player2Data then self:CancelTrade(trade.player1, {}) return end for unitId in pairs(trade.player1_units) do if not isValidUnit(unitId, player1Data) then self:CancelTrade(trade.player1, {}) return end end for unitId in pairs(trade.player2_units) do if not isValidUnit(unitId, player2Data) then self:CancelTrade(trade.player1, {}) return end end for unitId in pairs(trade.player1_units) do player1Data.Inventory.Units[unitId] = nil end for unitId in pairs(trade.player2_units) do player2Data.Inventory.Units[unitId] = nil end for unitId in pairs(trade.player1_units) do for slot, equippedUnitId in pairs(player1Data.Equipped.Units) do if equippedUnitId == unitId then player1Data.Equipped.Units[slot] = nil end end end for unitId in pairs(trade.player2_units) do for slot, equippedUnitId in pairs(player2Data.Equipped.Units) do if equippedUnitId == unitId then player2Data.Equipped.Units[slot] = nil end end end for _, unitData in pairs(trade.player1_units) do player2Data.Inventory.Units[HttpService:GenerateGUID()] = unitData end for _, unitData in pairs(trade.player2_units) do player1Data.Inventory.Units[HttpService:GenerateGUID()] = unitData end self.game.dataManager:UpdateData(trade.player1, "Inventory.Units", player1Data.Inventory.Units) self.game.dataManager:UpdateData(trade.player2, "Inventory.Units", player2Data.Inventory.Units) self.game.dataManager:UpdateData(trade.player1, "Equipped.Units", player1Data.Equipped.Units) self.game.dataManager:UpdateData(trade.player2, "Equipped.Units", player2Data.Equipped.Units) self.game.dataManager:AddToData(trade.player1, "Trades", 1) self.game.dataManager:AddToData(trade.player2, "Trades", 1) self:SetPlayerCooldown(trade.player1) self:SetPlayerCooldown(trade.player2) Server.UI.Fire(trade.player1, {UI = "Trade", Function = "CompleteTrade", Arguments = {Success = true, PartnerName = trade.player2.Name}}) Server.UI.Fire(trade.player2, {UI = "Trade", Function = "CompleteTrade", Arguments = {Success = true, PartnerName = trade.player1.Name}}) if trade.executionTimer then task.cancel(trade.executionTimer) trade.executionTimer = nil end self.activeTrades[trade.player1.UserId] = nil self.activeTrades[trade.player2.UserId] = nil end function TradingManager:CancelTrade(player, struct) local trade = self.activeTrades[player.UserId] if not trade then return end if trade.executionTimer then task.cancel(trade.executionTimer) trade.executionTimer = nil end Server.UI.Fire(trade.player1, {UI = "Trade", Function = "CancelTrade", Arguments = {CancelledBy = player.Name}}) Server.UI.Fire(trade.player2, {UI = "Trade", Function = "CancelTrade", Arguments = {CancelledBy = player.Name}}) self.activeTrades[trade.player1.UserId] = nil self.activeTrades[trade.player2.UserId] = nil end function TradingManager:CleanupExpiredTrades() local currentTime = os.time() for playerId, trade in pairs(self.activeTrades) do if currentTime - trade.timestamp > TRADE_TIMEOUT then if trade.executionTimer then task.cancel(trade.executionTimer) trade.executionTimer = nil end Server.UI.Fire(trade.player1, {UI = "Trade", Function = "CancelTrade", Arguments = {CancelledBy = "System (Timeout)"}}) Server.UI.Fire(trade.player2, {UI = "Trade", Function = "CancelTrade", Arguments = {CancelledBy = "System (Timeout)"}}) self.activeTrades[trade.player1.UserId] = nil self.activeTrades[trade.player2.UserId] = nil end end for dequestKey, request in pairs(self.tradeRequests) do if currentTime - request.timestamp > 30 then self.tradeRequests[dequestKey] = nil end end end return TradingManager
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)