Иконка ресурса

FREE Trade : 1.2.45 1.2.45

Нет прав для скачивания
C#:
using System;
using System.Text;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Plugins;
using Newtonsoft.Json;
using System.Linq;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
namespace Oxide.Plugins {
    [Info ("Trade", "Calytic", "1.2.45")]
    class Trade : RustPlugin {
        // Константы для меню выбора игрока
        private const string PlayerSelectMenu = "TradePlayerSelect";
        private const string PlayerSelectBackground = "TradePlayerSelectBackground";
        private const string PlayerSelectTitle = "TradePlayerSelectTitle";
        private const string PlayerSelectCloseButton = "TradePlayerSelectCloseButton";
        private const string PlayerSelectScrollView = "TradePlayerSelectScrollView";
        private const string PlayerSelectContent = "TradePlayerSelectContent";
#region Configuration
        string box;
        int slots;
        float cooldownMinutes;
        float maxRadius;
        float pendingSeconds;
        float radiationMax;
        bool allowSafeZone;
        [PluginReference]
        Plugin Ignore, Clans, Friends;
        Dictionary<string, DateTime> tradeCooldowns = new Dictionary<string, DateTime> ();
        // Переменные для постраничной навигации меню выбора игроков
        private const int PlayersPerPage = 8;
        // Количество игроков на странице
        private Dictionary<string, int> playerMenuPages = new Dictionary<string, int>();
        // Текущая страница для каждого игрока
#endregion
#region Trade State
        class OnlinePlayer {
            public BasePlayer Player;
            public StorageContainer View;
            public OpenTrade Trade;
            public PlayerInventory inventory {
                get {
                    return Player.inventory;
                }
            }
            public ItemContainer containerMain {
                get {
                    return Player.inventory.containerMain;
                }
            }
            public OnlinePlayer (BasePlayer player) {
            }
            public void Clear () {
                View = null;
                Trade = null;
            }
        }
        [OnlinePlayers]
        Hash<BasePlayer, OnlinePlayer> onlinePlayers = new Hash<BasePlayer, OnlinePlayer> ();
        class OpenTrade {
            public OnlinePlayer source;
            public OnlinePlayer target;
            public BasePlayer sourcePlayer {
                get {
                    return source.Player;
                }
            }
            public BasePlayer targetPlayer {
                get {
                    return target.Player;
                }
            }
            public bool complete = false;
            public bool closing = false;
            public bool sourceAccept = false;
            public bool targetAccept = false;
            public OpenTrade (OnlinePlayer source, OnlinePlayer target) {
                this.source = source;
                this.target = target;
            }
            public OnlinePlayer GetOther (OnlinePlayer onlinePlayer) {
                if (source == onlinePlayer) {
                    return target;
                }
                return source;
            }
            public BasePlayer GetOther (BasePlayer player) {
                if (sourcePlayer == player) {
                    return targetPlayer;
                }
                return sourcePlayer;
            }
            public void ResetAcceptance () {
                sourceAccept = false;
                targetAccept = false;
            }
            public bool IsInventorySufficient () {
                if (target == null || source == null) {
                    return false;
                }
                if (target.containerMain == null || source.containerMain == null) {
                    return false;
                }
                if ((target.containerMain.capacity - target.containerMain.itemList.Count) < source.View.inventory.itemList.Count || (source.containerMain.capacity - source.containerMain.itemList.Count) < target.View.inventory.itemList.Count) {
                    return true;
                }
                return false;
            }
            public bool IsValid () {
                if (IsSourceValid () && IsTargetValid ()) return true;
                return false;
            }
            public bool IsSourceValid () {
                if (sourcePlayer != null && sourcePlayer.IsConnected) return true;
                return false;
            }
            public bool IsTargetValid () {
                if (targetPlayer != null && targetPlayer.IsConnected) return true;
                return false;
            }
        }
        class PendingTrade {
            public BasePlayer Target;
            public Timer Timer;
            public PendingTrade (BasePlayer target) {
                Target = target;
            }
            public void Destroy () {
                if (Timer != null && !Timer.Destroyed) {
                    Timer.Destroy ();
                }
            }
        }
        List<OpenTrade> openTrades = new List<OpenTrade> ();
        Dictionary<BasePlayer, PendingTrade> pendingTrades = new Dictionary<BasePlayer, PendingTrade> ();
#endregion
#region Initialization
        void Init () {
            UnsubscribeAll ();
        }
        void UnsubscribeAll () {
            //Unsubscribe(nameof(CanNetworkTo));
            Unsubscribe (nameof (OnItemAction));
            Unsubscribe (nameof (OnItemAddedToContainer));
            Unsubscribe (nameof (CanMoveItem));
            Unsubscribe (nameof (OnItemRemovedFromContainer));
        }
        void SubscribeAll () {
            //Subscribe(nameof(CanNetworkTo));
            Subscribe (nameof (OnItemAction));
            Subscribe (nameof (OnItemAddedToContainer));
            Subscribe (nameof (CanMoveItem));
            Subscribe (nameof (OnItemRemovedFromContainer));
        }
        void Loaded () {
            permission.RegisterPermission ("trade.use", this);
            permission.RegisterPermission ("trade.confirm", this);
            LoadMessages ();
            CheckConfig ();
            box = GetConfig ("Settings", "box", "assets/prefabs/deployable/woodenbox/woodbox_deployed.prefab");
            slots = GetConfig ("Settings", "slots", 30);
            cooldownMinutes = GetConfig ("Settings", "cooldownMinutes", 5f);
            maxRadius = GetConfig ("Settings", "maxRadius", 5000f);
            pendingSeconds = GetConfig ("Settings", "pendingSeconds", 25f);
            radiationMax = GetConfig ("Settings", "radiationMax", 1f);
            allowSafeZone = GetConfig ("Settings", "allowSafeZone", true);
        }
        void Unloaded () {
            foreach (var player in BasePlayer.activePlayerList) {
                OnlinePlayer onlinePlayer;
                if (onlinePlayers.TryGetValue (player, out onlinePlayer)) {
                    if (onlinePlayer.Trade != null) {
                        TradeCloseBoxes (onlinePlayer.Trade);
                    }
                    else if (onlinePlayer.View != null) {
                        CloseBoxView (player, onlinePlayer.View);
                    }
                }
                // Очищаем UI от IQSorter при выгрузке плагина
                try {
                    CuiHelper.DestroyUi(player, "IQ_HEADER_PLAYER");
                    CuiHelper.DestroyUi(player, "IQ_HEADER_CONTAINER");
                }
                catch (Exception ex) {
                    Puts(string.Format("Error clearing IQSorter UI in Unloaded: {0}", ex.Message));
                }
                // Скрываем кнопку принятия торговли при выгрузке плагина
                HideTradeAcceptButton(player);
                // Дополнительная очистка лута при выгрузке плагина
                try {
                    if (player.inventory.loot.entitySource != null) {
                        // Проверяем, не является ли это активной торговлей
                        bool isActiveTrade = false;
                        if (onlinePlayers.ContainsKey(player)) {
                            var playerData = onlinePlayers[player];
                            if (playerData.Trade != null && !playerData.Trade.complete) {
                                isActiveTrade = true;
                            }
                        }
                        // Очищаем лут только если это не активная торговля
                        if (!isActiveTrade) {
                            player.EndLooting();
                            player.inventory.loot.entitySource = null;
                            player.inventory.loot.itemSource = null;
                            player.inventory.loot.containers.Clear();
                        }
                    }
                }
                catch (Exception ex) {
                    Puts(string.Format("Error clearing loot in Unloaded: {0}", ex.Message));
                }
            }
        }
        protected new void LoadDefaultConfig () {
            Config ["Settings", "box"] = "assets/prefabs/deployable/woodenbox/woodbox_deployed.prefab";
            Config ["Settings", "slots"] = 30;
            Config ["Settings", "cooldownMinutes"] = 5;
            Config ["Settings", "maxRadius"] = 5000f;
            Config ["Settings", "pendingSeconds"] = 25f;
            Config ["Settings", "radiationMax"] = 1;
            Config ["Settings", "allowSafeZone"] = true;
            Config ["VERSION"] = Version.ToString ();
        }
        void CheckConfig () {
            if (Config ["VERSION"] == null) {
                // FOR COMPATIBILITY WITH INITIAL VERSIONS WITHOUT VERSIONED CONFIG
                ReloadConfig ();
            }
            else if (GetConfig<string> ("VERSION", "") != Version.ToString ()) {
                // ADDS NEW, IF ANY, CONFIGURATION OPTIONS
                ReloadConfig ();
            }
        }
        protected void ReloadConfig () {
            Config ["VERSION"] = Version.ToString ();
            // NEW CONFIGURATION OPTIONS HERE
            Config ["Settings", "radiationMax"] = GetConfig ("Settings", "radiationMax", 1f);
            // END NEW CONFIGURATION OPTIONS
            PrintToConsole ("Upgrading configuration file");
            SaveConfig ();
        }
        void LoadMessages () {
            lang.RegisterMessages (new Dictionary<string, string> {
                {
                    "Inventory: You", "You do not have enough room in your inventory"
                }
                , {
                    "Inventory: Them", "Their inventory does not have enough room"
                }
                , {
                    "Inventory: Generic", "Insufficient inventory space"
                }
                , {
                    "Player: Not Found", "No player found by that name"
                }
                , {
                    "Player: Unknown", "Unknown"
                }
                , {
                    "Player: Yourself", "You cannot trade with yourself"
                }
                , {
                    "Status: Completing", "Completing trade.."
                }
                , {
                    "Status: No Pending", "You have no pending trade requests"
                }
                , {
                    "Status: Pending", "They already have a pending trade request"
                }
                , {
                    "Status: Received", "You have received a trade request from {0}.Type <color=#00FF00>/trade accept</color> to begin trading"
                }
                , {
                    "Status: They Interrupted", "They moved or closed the trade"
                }
                , {
                    "Status: You Interrupted", "You moved or closed the trade"
                }
                , {
                    "Trade: Sent", "Trade request sent"
                }
                , {
                    "Trade: They Declined", "They declined your trade request"
                }
                , {
                    "Trade: You Declined", "You declined their trade request"
                }
                , {
                    "Trade: They Accepted", "{0} accepted."
                }
                , {
                    "Trade: You Accepted", "You accepted."
                }
                , {
                    "Trade: Pending", "Trade pending."
                }
                , {
                    "Denied: Permission", "You lack permission to do that"
                }
                , {
                    "Denied: Privilege", "You do no have building privilege"
                }
                , {
                    "Denied: Swimming", "You cannot do that while swimming"
                }
                , {
                    "Denied: Falling", "You cannot do that while falling"
                }
                , {
                    "Denied: Mounted", "You cannot do that while mounted"
                }
                , {
                    "Denied: Wounded", "You cannot do that while wounded"
                }
                , {
                    "Denied: Irradiated", "You cannot do that while irradiated"
                }
                , {
                    "Denied: Generic", "You cannot do that right now"
                }
                , {
                    "Denied: They Busy", "That player is busy"
                }
                , {
                    "Denied: They Ignored You", "They ignored you"
                }
                , {
                    "Denied: Distance", "Too far away"
                }
                , {
                    "Denied: Ship", "You cannot do that while on a ship"
                }
                , {
                    "Denied: Lift", "You cannot do that while on a lift"
                }
                , {
                    "Denied: Balloon", "You cannot do that while on a balloon"
                }
                , {
                    "Denied: Safe Zone", "You cannot do that while in a safe zone"
                }
                , {
                    "Item: BP", "BP"
                }
                , {
                    "Syntax: Trade Accept", "Invalid syntax./trade accept"
                }
                , {
                    "Syntax: Trade", "Invalid syntax./trade \"Player Name\""
                }
                , {
                    "Cooldown: Seconds", "You are doing that too often, try again in a {0} seconds(s)."
                }
                , {
                    "Cooldown: Minutes", "You are doing that too often, try again in a {0} minute(s)."
                }
                ,
            }
            , this);
        }
#endregion
#region Oxide Hooks
        //object CanNetworkTo(BaseNetworkable entity, BasePlayer target)
        //{
        //    if (entity == null || target == null || entity == target) return null;
        //    if (target.IsAdmin) return null;
        //    OnlinePlayer onlinePlayer;
        //    bool IsMyBox = false;
        //    if (onlinePlayers.TryGetValue(target, out onlinePlayer))
        //    {
        //        if (onlinePlayer.View != null && onlinePlayer.View.net.ID == entity.net.ID)
        //        {
        //            IsMyBox = true;
        //        }
        //    }
        //    if (IsTradeBox(entity) && !IsMyBox) return false;
        //    return null;
        //}
        void OnPlayerConnected (BasePlayer player) {
            onlinePlayers [player].View = null;
            onlinePlayers [player].Trade = null;
        }
        void OnPlayerDisconnected (BasePlayer player) {
            OnlinePlayer onlinePlayer;
            if (onlinePlayers.TryGetValue (player, out onlinePlayer)) {
                if (onlinePlayer.Trade != null) {
                    TradeCloseBoxes (onlinePlayer.Trade);
                }
                else if (onlinePlayer.View != null) {
                    CloseBoxView (player, onlinePlayer.View);
                }
            }
            // Очищаем UI от IQSorter при отключении игрока
            try {
                CuiHelper.DestroyUi(player, "IQ_HEADER_PLAYER");
                CuiHelper.DestroyUi(player, "IQ_HEADER_CONTAINER");
            }
            catch (Exception ex) {
                Puts(string.Format("Error clearing IQSorter UI in OnPlayerDisconnected: {0}", ex.Message));
            }
            // Скрываем кнопку принятия торговли при отключении игрока
            HideTradeAcceptButton(player);
            // Дополнительная очистка лута при отключении игрока
            try {
                if (player.inventory.loot.entitySource != null) {
                    // Проверяем, не является ли это активной торговлей
                    bool isActiveTrade = false;
                    if (onlinePlayers.ContainsKey(player)) {
                        var playerData = onlinePlayers[player];
                        if (playerData.Trade != null && !playerData.Trade.complete) {
                            isActiveTrade = true;
                        }
                    }
                    // Очищаем лут только если это не активная торговля
                    if (!isActiveTrade) {
                        player.EndLooting();
                        player.inventory.loot.entitySource = null;
                        player.inventory.loot.itemSource = null;
                        player.inventory.loot.containers.Clear();
                    }
                }
            }
            catch (Exception ex) {
                Puts(string.Format("Error clearing loot in OnPlayerDisconnected: {0}", ex.Message));
            }
        }
        void OnPlayerLootEnd (PlayerLoot inventory) {
            var player = inventory.GetComponent<BasePlayer> ();
            if (player == null) return;
            OnlinePlayer onlinePlayer;
            if (onlinePlayers.TryGetValue (player, out onlinePlayer) && onlinePlayer.View != null) {
                if (onlinePlayer.View == inventory.entitySource && onlinePlayer.Trade != null) {
                    OpenTrade t = onlinePlayer.Trade;
                    if (!t.closing) {
                        t.closing = true;
                        if (!onlinePlayer.Trade.complete) {
                            if (onlinePlayer.Trade.sourcePlayer == player) {
                                TradeReply (t, "Status: They Interrupted", "Status: You Interrupted");
                            }
                            else {
                                TradeReply (t, "Status: You Interrupted", "Status: They Interrupted");
                            }
                        }
                        CloseBoxView (player, (StorageContainer)inventory.entitySource);
                        // Дополнительная принудительная очистка при закрытии лута
                        try {
                            if (inventory.entitySource is StorageContainer container) {
                                if (container is BaseEntity entity) {
                                    entity.Kill(BaseNetworkable.DestroyMode.Gib);
                                }
                                if (container.net != null) {
                                    container.net.Destroy();
                                }
                                UnityEngine.Object.Destroy(container);
                            }
                        }
                        catch (Exception ex) {
                            Puts(string.Format("Error in OnPlayerLootEnd cleanup: {0}", ex.Message));
                        }
                    }
                }
            }
        }
        void OnItemAction (Item item, string cmd) {
            if (cmd == "drop") {
                BasePlayer player = item.GetOwnerPlayer ();
                if (player is BasePlayer) {
                    OnlinePlayer onlinePlayer;
                    if (onlinePlayers.TryGetValue (player, out onlinePlayer) && onlinePlayer.Trade != null && player.inventory != null) {
                        if (item.parent == player.inventory.containerMain && !onlinePlayer.Trade.IsInventorySufficient ()) {
                            ShowTrades (onlinePlayer.Trade, "Trade: Pending");
                        }
                    }
                }
            }
        }
        void OnItemAddedToContainer (ItemContainer container, Item item) {
            if (container.playerOwner is BasePlayer) {
                OnlinePlayer onlinePlayer;
                if (onlinePlayers.TryGetValue (container.playerOwner, out onlinePlayer) && onlinePlayer.Trade != null) {
                    OpenTrade t = onlinePlayers [container.playerOwner].Trade;
                    if (!t.complete) {
                        t.ResetAcceptance ();
                        if (t.IsValid ()) {
                            ShowTrades (t, "Trade: Pending");
                        }
                        else {
                            TradeCloseBoxes (t);
                        }
                    }
                }
            }
        }
        object CanMoveItem (Item item, PlayerInventory playerLoot, uint targetContainer, int targetSlot) {
            var player = playerLoot.GetComponent<BasePlayer> ();
            if (player == null) {
                return null;
            }
            OnlinePlayer onlinePlayer;
            if (onlinePlayers.TryGetValue (player, out onlinePlayer) && onlinePlayer.Trade != null) {
                OpenTrade t = onlinePlayers [player].Trade;
                if (t.closing) {
                    return false;
                }
            }
            return null;
        }
        void OnItemRemovedFromContainer (ItemContainer container, Item item) {
            if (container.playerOwner is BasePlayer) {
                OnlinePlayer onlinePlayer;
                if (onlinePlayers.TryGetValue (container.playerOwner, out onlinePlayer) && onlinePlayer.Trade != null) {
                    OpenTrade t = onlinePlayers [container.playerOwner].Trade;
                    if (!t.complete) {
                        t.ResetAcceptance ();
                        if (t.IsValid ()) {
                            ShowTrades (t, "Trade: Pending");
                        }
                        else {
                            TradeCloseBoxes (t);
                        }
                    }
                }
            }
        }
#endregion
#region Commands
        [ChatCommand ("trade")]
        void cmdTrade (BasePlayer player, string command, string [] args) {
            // Отладочная информация
            Puts(string.Format("cmdTrade called for player: {0}, args.Length: {1}", player.displayName, args.Length));
            if (args.Length > 0) Puts(string.Format("First arg: '{0}'", args[0]));
            if (args.Length == 1) {
                if (args [0] == "accept") {
                    Puts(string.Format("Player {0} is accepting trade", player.displayName));
                    if (!CanPlayerTrade (player, "trade.confirm")) return;
                    AcceptTrade (player);
                    return;
                }
            }
            if (args.Length == 0) {
                // Показываем меню выбора игроков
                ShowPlayerSelectMenu(player);
                return;
            }
            if (args.Length != 1) {
                if (pendingTrades.ContainsKey (player)) {
                    SendReply (player, GetMsg ("Syntax: Trade Accept", player));
                }
                else {
                    SendReply (player, GetMsg ("Syntax: Trade", player));
                }
                return;
            }
            var targetPlayer = FindPlayerByPartialName (args [0]);
            if (targetPlayer == null) {
                SendReply (player, GetMsg ("Player: Not Found", player));
                return;
            }
            if (targetPlayer == player) {
                SendReply (player, GetMsg ("Player: Yourself", player));
                return;
            }
            if (!CheckCooldown (player)) {
                return;
            }
            if (Ignore != null) {
                var IsIgnored = Ignore.Call ("IsIgnored", player.UserIDString, targetPlayer.UserIDString);
                if ((bool)IsIgnored == true) {
                    SendReply (player, GetMsg ("Denied: They Ignored You", player));
                    return;
                }
            }
            OnlinePlayer onlineTargetPlayer;
            if (onlinePlayers.TryGetValue (targetPlayer, out onlineTargetPlayer) && onlineTargetPlayer.Trade != null) {
                SendReply (player, GetMsg ("Denied: They Busy", player));
                return;
            }
            if (maxRadius > 0) {
                if (targetPlayer.Distance (player) > maxRadius) {
                    SendReply (player, GetMsg ("Denied: Distance", player));
                    return;
                }
            }
            if (!CanPlayerTrade (player, "trade.use")) return;
            if (pendingTrades.ContainsKey (player)) {
                SendReply (player, GetMsg ("Status: Pending", player));
            }
            else {
                SendReply (targetPlayer, GetMsg ("Status: Received", targetPlayer), player.displayName);
                SendReply (player, GetMsg ("Trade: Sent", player));
                // Показываем UI кнопку принятия торговли
                ShowTradeAcceptButton(targetPlayer, player.displayName);
                var pendingTrade = new PendingTrade (targetPlayer);
                pendingTrades.Add (player, pendingTrade);
                pendingTrade.Timer = timer.In (pendingSeconds, delegate () {
                    if (pendingTrades.ContainsKey (player)) {
                        pendingTrades.Remove (player);
                        SendReply (player, GetMsg ("Trade: They Declined", player));
                        SendReply (targetPlayer, GetMsg ("Trade: You Declined", targetPlayer));
                        // Скрываем UI кнопку принятия торговли
                        HideTradeAcceptButton(targetPlayer);
                    }
                }
                );
            }
        }
        [ConsoleCommand ("trade")]
        void ccTrade (ConsoleSystem.Arg arg) {
            if (arg.Connection == null) return;
            if (arg.Connection.player == null) return;
            cmdTrade (arg.Connection.player as BasePlayer, arg.cmd.Name, arg.Args);
        }
        [ConsoleCommand ("trade.decline")]
        void ccTradeDecline (ConsoleSystem.Arg arg) {
            if (arg.Connection == null) return;
            if (arg.Connection.player == null) return;
            var player = arg.Connection.player as BasePlayer;
            OnlinePlayer onlinePlayer;
            if (onlinePlayers.TryGetValue (player, out onlinePlayer) && onlinePlayer.Trade != null) {
                onlinePlayer.Trade.closing = true;
                var target = onlinePlayer.Trade.GetOther (player);
                SendReply (player, GetMsg ("Trade: You Declined", player));
                SendReply (target, GetMsg ("Trade: They Declined", target));
                TradeCloseBoxes (onlinePlayer.Trade);
            }
            else if (player is BasePlayer) {
                HideTrade (player);
            }
        }
        [ConsoleCommand ("trade.confirm")]
        void ccTradeConfirm (ConsoleSystem.Arg arg) {
            if (arg.Connection == null) return;
            if (arg.Connection.player == null) return;
            var player = arg.Connection.player as BasePlayer;
            // Отладочная информация
            Puts(string.Format("Trade confirm command called by player: {0}", player.displayName));
            TradeAccept (player);
        }
        [ConsoleCommand ("trade.accept.request")]
        void ccTradeAcceptRequest (ConsoleSystem.Arg arg) {
            if (arg.Connection == null) return;
            if (arg.Connection.player == null) return;
            var player = arg.Connection.player as BasePlayer;
            // Отладочная информация
            Puts(string.Format("Trade accept request command called by player: {0}", player.displayName));
            AcceptTrade (player);
        }
        void TradeAccept (BasePlayer player) {
            // Отладочная информация
            Puts(string.Format("TradeAccept called for player: {0}", player.displayName));
            OnlinePlayer onlinePlayer;
            if (onlinePlayers.TryGetValue (player, out onlinePlayer) && onlinePlayer.Trade != null) {
                Puts(string.Format("Player {0} has active trade", player.displayName));
                var t = onlinePlayers [player].Trade;
                if (t.sourcePlayer == player) {
                    Puts(string.Format("Player {0} is source player", player.displayName));
                    if (!CheckSourceInventory (t)) {
                        Puts(string.Format("Source inventory check failed for {0}", player.displayName));
                        return;
                    }
                    t.sourceAccept = true;
                    Puts(string.Format("Source accept set to true for {0}", player.displayName));
                }
                else if (t.targetPlayer == player) {
                    Puts(string.Format("Player {0} is target player", player.displayName));
                    if (!CheckTargetInventory (t)) {
                        Puts(string.Format("Target inventory check failed for {0}", player.displayName));
                        return;
                    }
                    t.targetAccept = true;
                    Puts(string.Format("Target accept set to true for {0}", player.displayName));
                }
                Puts(string.Format("Trade status - sourceAccept: {0}, targetAccept: {1}", t.sourceAccept, t.targetAccept));
                if (t.targetAccept == true && t.sourceAccept == true) {
                    Puts(string.Format("Both players accepted, completing trade for {0}", player.displayName));
                    CompleteTrade (t);
                }
                else {
                    Puts(string.Format("Trade pending, showing trades for {0}", player.displayName));
                    ShowTrades (t, "Trade: Pending");
                }
            }
            else {
                Puts(string.Format("Player {0} has no active trade or onlinePlayer is null", player.displayName));
                if (player is BasePlayer) {
                    HideTrade (player);
                }
            }
        }
        void CompleteTrade (OpenTrade t) {
            if (t.IsInventorySufficient ()) {
                t.ResetAcceptance ();
                ShowTrades (t, "Inventory: Generic");
                return;
            }
            if (t.complete) {
                return;
            }
            t.complete = true;
            t.closing = true;
            TradeCooldown (t);
            TradeReply (t, "Status: Completing");
            Interface.Oxide.NextTick (() => FinishTrade (t));
        }
        bool CheckSourceInventory (OpenTrade t) {
            var i = t.target.View.inventory.itemList.Count;
            var f = t.source.containerMain.capacity - t.source.containerMain.itemList.Count;
            if (i > f) {
                TradeReply (t, "Inventory: Them", "Inventory: You");
                t.sourceAccept = false;
                ShowTrades (t, "Inventory: Generic");
                return false;
            }
            return true;
        }
        bool CheckTargetInventory (OpenTrade t) {
            var i = t.source.View.inventory.itemList.Count;
            var f = t.target.containerMain.capacity - t.target.containerMain.itemList.Count;
            if (i > f) {
                TradeReply (t, "Inventory: You", "Inventory: Them");
                t.targetAccept = false;
                ShowTrades (t, "Inventory: Generic");
                return false;
            }
            return true;
        }
#endregion
#region GUI
        public string jsonTrade = @"[{""name"":""TradeMsg"",""parent"":""Overlay"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0.05 0.05 0.08 0.98"",""imagetype"":""Filled""},{""type"":""RectTransform"",""anchormax"":""0.75 0.99"",""anchormin"":""0.25 0.65""}]},{""name"":""TradeHeader"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0.1 0.1 0.15 0.95"",""imagetype"":""Filled""},{""type"":""RectTransform"",""anchormax"":""1 1"",""anchormin"":""0 0.85""}]},{""name"":""TradeTitle"",""parent"":""TradeHeader"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""МЕНЮ ОБМЕНА"",""fontSize"":""18"",""align"":""MiddleCenter"",""color"":""1 1 1 1"",""font"":""robotocondensed-bold.ttf""},{""type"":""RectTransform"",""anchormax"":""1 1"",""anchormin"":""0 0""}]},{""name"":""SourceLabel{1}"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""{sourcename}"",""fontSize"":""14"",""align"":""MiddleCenter"",""color"":""0.9 0.9 0.9 1"",""font"":""robotocondensed-bold.ttf""},{""type"":""RectTransform"",""anchormax"":""0.48 0.88"",""anchormin"":""0.02 0.85""}]},{""name"":""TargetLabel{2}"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""{targetname}"",""fontSize"":""14"",""align"":""MiddleCenter"",""color"":""0.9 0.9 0.9 1"",""font"":""robotocondensed-bold.ttf""},{""type"":""RectTransform"",""anchormax"":""0.98 0.88"",""anchormin"":""0.52 0.85""}]},{""name"":""SourceItemsPanel{3}"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0.12 0.12 0.15 0.9"",""imagetype"":""Filled""},{""type"":""RectTransform"",""anchormax"":""0.47 0.83"",""anchormin"":""0.02 0.12""}]},{""name"":""SourceItemsText"",""parent"":""SourceItemsPanel{3}"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""{sourceitems}"",""fontSize"":""12"",""align"":""UpperLeft"",""color"":""0.9 0.9 0.9 1""},{""type"":""RectTransform"",""anchormax"":""0.98 0.98"",""anchormin"":""0.02 0.02""}]},{""name"":""TargetItemsPanel{4}"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Image"",""color"":""0.12 0.12 0.15 0.9"",""imagetype"":""Filled""},{""type"":""RectTransform"",""anchormax"":""0.98 0.83"",""anchormin"":""0.52 0.12""}]},{""name"":""TargetItemsText"",""parent"":""TargetItemsPanel{4}"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""{targetitems}"",""fontSize"":""12"",""align"":""UpperLeft"",""color"":""0.9 0.9 0.9 1""},{""type"":""RectTransform"",""anchormax"":""0.98 0.98"",""anchormin"":""0.02 0.02""}]},{""name"":""AcceptTradeButton{5}"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Button"",""color"":""0.2 0.8 0.3 0.9"",""command"":""trade.confirm""},{""type"":""RectTransform"",""anchormax"":""0.48 0.08"",""anchormin"":""0.35 0.02""}]},{""name"":""AcceptTradeLabel"",""parent"":""AcceptTradeButton{5}"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""✅ ПОДТВЕРДИТЬ"",""fontSize"":""12"",""align"":""MiddleCenter"",""color"":""1 1 1 1"",""font"":""robotocondensed-bold.ttf""},{""type"":""RectTransform"",""anchormax"":""1 1"",""anchormin"":""0 0""}]},{""name"":""DeclineTradeButton{6}"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Button"",""color"":""0.8 0.2 0.2 0.9"",""command"":""trade.decline""},{""type"":""RectTransform"",""anchormax"":""0.15 0.08"",""anchormin"":""0.02 0.02""}]},{""name"":""DeclineTradeLabel"",""parent"":""DeclineTradeButton{6}"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""❌ ОТМЕНИТЬ"",""color"":""1 1 1 1"",""fontSize"":""12"",""align"":""MiddleCenter"",""font"":""robotocondensed-bold.ttf""},{""type"":""RectTransform"",""anchormax"":""1 1"",""anchormin"":""0 0""}]},{""name"":""TargetStatusLabel{7}"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""{targetstatus}"",""fontSize"":""11"",""align"":""MiddleCenter"",""color"":""0.8 0.8 0.8 1"",""font"":""robotocondensed-bold.ttf""},{""type"":""RectTransform"",""anchormax"":""0.98 0.1"",""anchormin"":""0.52 0.02""}]},{""name"":""CloseButton"",""parent"":""TradeMsg"",""components"":[{""type"":""UnityEngine.UI.Button"",""color"":""0.8 0.2 0.2 0.9"",""command"":""trade.decline""},{""type"":""RectTransform"",""anchormax"":""0.98 0.98"",""anchormin"":""0.9 0.9""}]},{""name"":""CloseText"",""parent"":""CloseButton"",""components"":[{""type"":""UnityEngine.UI.Text"",""text"":""✕"",""fontSize"":""20"",""align"":""MiddleCenter"",""color"":""1 1 1 1"",""font"":""robotocondensed-bold.ttf""},{""type"":""RectTransform"",""anchormax"":""1 1"",""anchormin"":""0 0""}]}]
";
        private void ShowTrade (BasePlayer player, OpenTrade trade, string status) {
            HideTrade (player);
            OnlinePlayer onlinePlayer;
            if (!onlinePlayers.TryGetValue (player, out onlinePlayer)) {
                return;
            }
            if (onlinePlayer.View == null) {
                return;
            }
            StorageContainer sourceContainer = onlinePlayer.View;
            StorageContainer targetContainer = null;
            BasePlayer target = null;
            if (trade.sourcePlayer == player && trade.target.View != null) {
                targetContainer = trade.target.View;
                target = trade.targetPlayer;
                if (target is BasePlayer) {
                    if (trade.targetAccept) {
                        status += string.Format (GetMsg ("Trade: They Accepted", player), CleanName (target.displayName));
                    }
                    else if (trade.sourceAccept) {
                        status += GetMsg ("Trade: You Accepted", player);
                    }
                }
                else {
                    return;
                }
            }
            else if (trade.targetPlayer == player && trade.source.View != null) {
                targetContainer = trade.source.View;
                target = trade.sourcePlayer;
                if (target is BasePlayer) {
                    if (trade.sourceAccept) {
                        status += string.Format (GetMsg ("Trade: They Accepted", player), CleanName (target.displayName));
                    }
                    else if (trade.targetAccept) {
                        status += GetMsg ("Trade: You Accepted", player);
                    }
                }
                else {
                    return;
                }
            }
            if (targetContainer == null || target == null) {
                return;
            }
            string send = jsonTrade;
            for (int i = 1; i < 100; i++) {
                send = send.Replace ("{" + i + "}", Oxide.Core.Random.Range (9999, 99999).ToString ());
            }
            send = send.Replace ("{sourcename}", CleanName (player.displayName));
            if (target != null) {
                send = send.Replace ("{targetname}", CleanName (target.displayName));
            }
            else {
                send = send.Replace ("{targetname}", GetMsg ("Player: Unknown", player));
            }
            send = send.Replace ("{targetstatus}", status);
            var slotsAvailable = target.inventory.containerMain.capacity - (target.inventory.containerMain.itemList.Count);
            List<string> sourceItems = new List<string> ();
            var x = 1;
            foreach (Item i in sourceContainer.inventory.itemList) {
                string n = "";
                if (i.IsBlueprint ()) {
                    n = i.amount + " x <color=lightblue>" + i.blueprintTargetDef.displayName.english + " [" + GetMsg ("Item: BP", player) + "]</color>";
                }
                else {
                    n = i.amount + " x " + i.info.displayName.english;
                    if(i.info.condition.enabled) {
                        var conditionPercent = System.Math.Round(i.condition * 100 / i.info.condition.max, 0);
                        if(conditionPercent <= 25f) {
                            n += " [<color=red>" + conditionPercent + "%</color>]";
                        }
                        else if(conditionPercent <= 75f) {
                            n += " [<color=yellow>" + conditionPercent + "%</color>]";
                        }
                        else if(conditionPercent <= 99f) {
                            n += " [<color=green>" + conditionPercent + "%</color>]";
                        }
                    }
                }
                if (x > slotsAvailable) {
                    n = "<color=red>" + n + "</color>";
                }
                x++;
                sourceItems.Add (n);
            }
            send = send.Replace ("{sourceitems}", string.Join ("\n", sourceItems.ToArray ()));
            if (player != target) {
                slotsAvailable = player.inventory.containerMain.capacity - (player.inventory.containerMain.itemList.Count);
                List<string> targetItems = new List<string> ();
                x = 1;
                if (targetContainer != null) {
                    foreach (Item i in targetContainer.inventory.itemList) {
                        string n2 = "";
                        if (i.IsBlueprint ()) {
                            n2 = i.amount + " x <color=lightblue>" + i.blueprintTargetDef.displayName.english + " [" + GetMsg ("Item: BP", player) + "]</color>";
                        }
                        else {
                            n2 = i.amount + " x " + i.info.displayName.english;
                            if (i.info.condition.enabled) {
                                var conditionPercent = System.Math.Round(i.condition * 100 / i.info.condition.max, 0);
                                if (conditionPercent <= 25f) {
                                    n2 += " [<color=red>" + conditionPercent + "%</color>]";
                                }
                                else if (conditionPercent <= 75f) {
                                    n2 += " [<color=yellow>" + conditionPercent + "%</color>]";
                                }
                                else if (conditionPercent <= 99f) {
                                    n2 += " [<color=green>" + conditionPercent + "%</color>]";
                                }
                            }
                        }
                        if (x > slotsAvailable) {
                            n2 = "<color=red>" + n2 + "</color>";
                        }
                        x++;
                        targetItems.Add (n2);
                    }
                }
                send = send.Replace ("{targetitems}", string.Join ("\n", targetItems.ToArray ()));
            }
            else {
                send = send.Replace ("{targetitems}", "");
            }
            CommunityEntity.ServerInstance.ClientRPCEx (new Network.SendInfo {
                connection = player.net.connection
            }
            , null, "AddUI", send);
        }
        private void HideTrade (BasePlayer player) {
            if (player.IsConnected) {
                // Очищаем основное меню торговли
                CommunityEntity.ServerInstance.ClientRPCEx (new Network.SendInfo {
                    connection = player.net.connection
                }
                , null, "DestroyUI", "TradeMsg");
                // Очищаем UI от IQSorter
                try {
                    // Используем CuiHelper для очистки UI от других плагинов
                    CuiHelper.DestroyUi(player, "IQ_HEADER_PLAYER");
                    CuiHelper.DestroyUi(player, "IQ_HEADER_CONTAINER");
                }
                catch (Exception ex) {
                    Puts(string.Format("Error clearing IQSorter UI: {0}", ex.Message));
                }
                // НЕ очищаем лут здесь - это может прервать активную торговлю
                // Очистка лута происходит только при завершении торговли
            }
        }
#endregion
#region Core Methods
        bool CheckCooldown (BasePlayer player) {
            if (cooldownMinutes > 0) {
                DateTime startTime;
                if (tradeCooldowns.TryGetValue (player.UserIDString, out startTime)) {
                    var endTime = DateTime.Now;
                    var span = endTime.Subtract (startTime);
                    if (span.TotalMinutes > 0 && span.TotalMinutes < Convert.ToDouble (cooldownMinutes)) {
                        double timeleft = System.Math.Round (Convert.ToDouble (cooldownMinutes) - span.TotalMinutes, 2);
                        if (timeleft < 1) {
                            double timelefts = System.Math.Round ((Convert.ToDouble (cooldownMinutes) * 60) - span.TotalSeconds);
                            SendReply (player, string.Format (GetMsg ("Cooldown: Seconds", player), timelefts.ToString ()));
                        }
                        else {
                            SendReply (player, string.Format (GetMsg ("Cooldown: Minutes", player), System.Math.Round (timeleft).ToString ()));
                        }
                        return false;
                    }
                    else {
                        tradeCooldowns.Remove (player.UserIDString);
                    }
                }
            }
            return true;
        }
        void TradeCloseBoxes (OpenTrade trade) {
            try {
                // Принудительно уничтожаем ящики
                if (trade.IsSourceValid () && trade.source.View != null) {
                    ForceDestroyBox(trade.source.View);
                    CloseBoxView (trade.sourcePlayer, trade.source.View);
                    // Дополнительная принудительная очистка
                    try {
                        if (trade.source.View is BaseEntity entity) {
                            entity.Kill(BaseNetworkable.DestroyMode.Gib);
                        }
                        if (trade.source.View.net != null) {
                            trade.source.View.net.Destroy();
                        }
                        UnityEngine.Object.Destroy(trade.source.View);
                    }
                    catch (Exception ex) {
                        Puts(string.Format("Error in TradeCloseBoxes source cleanup: {0}", ex.Message));
                    }
                }
                if (trade.IsTargetValid () && trade.targetPlayer != trade.sourcePlayer && trade.target.View != null) {
                    Puts(string.Format("TradeCloseBoxes: Cleaning target box for player: {0}", trade.targetPlayer?.displayName));
                    ForceDestroyBox(trade.target.View);
                    CloseBoxView (trade.targetPlayer, trade.target.View);
                    // Дополнительная принудительная очистка - БОЛЕЕ АГРЕССИВНАЯ для цели
                    try {
                        if (trade.target.View is BaseEntity entity) {
                            entity.Kill(BaseNetworkable.
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху