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

FREE Trade : 1.2.6 1.2.6

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Network;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Trade", "Orange", "1.2.6")]
    public class Trade : RustPlugin
    {
        #region Vars

        private const string prefabEntity = "assets/bundled/prefabs/static/wall.frame.shopfront.metal.static.prefab";
        private const string prefabTestPlayer = "assets/prefabs/player/player.prefab";
        private static bool isTradingEntity(BaseEntity entity) => entity != null && entity.name == keyName;
        private const string keyName = "TradePluginFront";
        private static Trade plugin;
        private static bool testTradeFlag;

        #endregion

        #region Oxide Hooks

        private void Init()
        {
            plugin = this;

            foreach (var command in config.command)
            {
                cmd.AddChatCommand(command, this, nameof(cmdControlChat));
                cmd.AddConsoleCommand(command, this, nameof(cmdControlConsole));
            }

            foreach (var command in config.acceptCommand)
            {
                cmd.AddChatCommand(command, this, nameof(cmdControlChat));
                cmd.AddConsoleCommand(command, this, nameof(cmdControlConsole));
            }

            foreach (var command in config.declineCommand)
            {
                cmd.AddChatCommand(command, this, nameof(cmdControlChat));
                cmd.AddConsoleCommand(command, this, nameof(cmdControlConsole));
            }

            foreach (var value in config.permissions)
            {
                permission.RegisterPermission(value.permission, this);
            }
        }

        private void OnServerInitialized()
        {
            LoadData();
        }

        private void Unload()
        {
            SaveData();
        }

        private void OnShopCompleteTrade(ShopFront entity)
        {
            if (isTradingEntity(entity) == false)
            {
                return;
            }

            if (config.logTrade == true)
            {
                LogTrade(entity);
            }

            var player1 = entity.vendorPlayer;
            var player2 = entity.customerPlayer;
            var data1 = Data.Get(player1.UserIDString, true);
            var data2 = Data.Get(player2.UserIDString, true);
            data1.lastTradeUse = DateTime.UtcNow;
            data2.lastTradeUse = DateTime.UtcNow;
            RunEffect(player1.transform.position, config.effectOnCompleteTrade, player1);
            RunEffect(player2.transform.position, config.effectOnCompleteTrade, player2);

            NextTick(() =>
            {
                if (entity.IsValid() == true && entity.HasFlag(BaseEntity.Flags.Reserved3) == false)
                {
                    entity.Kill();
                }
            });
        }

        private void OnLootEntityEnd(BasePlayer player, ShopFront entity)
        {
            if (isTradingEntity(entity) == false)
            {
                return;
            }

            NextTick(() =>
            {
                if (entity.IsValid() == true && entity.HasFlag(BaseEntity.Flags.Reserved3) == false)
                {
                    var player1 = entity.vendorPlayer;
                    var player2 = entity.customerPlayer;
                    entity.ReturnPlayerItems(player1);
                    entity.ReturnPlayerItems(player2);
                    entity.Kill();
                }
            });
        }

        private object OnEntityVisibilityCheck(BaseEntity ent, BasePlayer player, uint id, string debugName,
            float maximumDistance)
        {
            if (isTradingEntity(ent) == true)
            {
                return true;
            }

            return null;
        }

        // private object CanAcceptItem(ItemContainer container, Item item, int targetPos)
        // {
        //     var entity = item.parentItem?.parent?.entityOwner?.GetComponent<ShopFront>();
        //     if (isTradingEntity(entity) == true)
        //     {
        //         var isMod = item.GetHeldEntity()?.GetComponent<ProjectileWeaponMod>() != null;
        //         if (item.parentItem != null && isMod)
        //         {
        //             return ItemContainer.CanAcceptResult.CannotAccept;
        //         }
        //     }
        //
        //     return null;
        // }

        // private void OnItemSplit(Item item, int amount)
        // {
        //     var entity = item.parent?.entityOwner?.GetComponent<ShopFront>();
        //     if (isTradingEntity(entity) == true)
        //     {
        //         entity.ResetTrade();
        //     }
        // }

        #endregion

        #region Commands

        private void cmdControlConsole(ConsoleSystem.Arg arg)
        {
            cmdControlChat(arg.Player(), arg.cmd.FullName, arg.Args);
        }

        private void cmdControlChat(BasePlayer player, string command, string[] args)
        {
            var perm = GetPermission(player.userID, config.permissions);
            if (perm == null)
            {
                SendMessage(player, MessageType.Permission);
                return;
            }

            if (HaveAbilityForTrading(player) == false)
            {
                return;
            }

            if (config.acceptCommand.Contains(command))
            {
                AcceptOrCancelRequest(player, false);
                return;
            }

            if (config.declineCommand.Contains(command))
            {
                AcceptOrCancelRequest(player, true);
                return;
            }

            var action = args?.Length > 0 ? args[0] : "unknown";
            switch (action.ToLower())
            {
                case "accept":
                case "+":
                case "yes":
                case "y":
                case "a":
                    AcceptOrCancelRequest(player, false);
                    return;
                case "cancel":
                case "-":
                case "no":
                case "n":
                case "c":
                    AcceptOrCancelRequest(player, true);
                    return;

                case "test":
                    if (player.IsAdmin == true)
                    {
                        TestTrade(player);
                    }

                    return;

                default:
                    SendTradeRequest(player, action, perm.cooldown);
                    return;
            }
        }

        #endregion

        #region Core

        private void SendTradeRequest(BasePlayer sender, string receiverString, int cooldown)
        {
            var component = sender.GetComponent<PendingTrade>();
            if (component != null)
            {
                SendMessage(sender, MessageType.RequestAlreadyPending);
                return;
            }

            var data = Data.Get(sender.UserIDString, true);
            var passed = (DateTime.UtcNow - data.lastTradeUse).TotalSeconds;
            var leftSeconds = cooldown - passed;
            if (leftSeconds > 0)
            {
                SendMessage(sender, MessageType.Cooldown, "{seconds}", leftSeconds.ToString("0.0"));
                return;
            }

            var target = FindPlayer(receiverString);
            if (target is string)
            {
                var text = target.ToString();
                if (text == receiverString)
                {
                    SendMessage(sender, MessageType.NoPlayers, "{name}", receiverString);
                    return;
                }

                SendMessage(sender, MessageType.MultiplePlayers, "{list}", text);
                return;
            }

            var targetPlayer = target as BasePlayer;
            if (targetPlayer == null)
            {
                SendMessage(sender, "Error: targetPlayer == null");
                return;
            }

            var pendingScript = targetPlayer.GetComponent<PendingTrade>();
            if (pendingScript != null)
            {
                SendMessage(sender, MessageType.RequestAlreadyPending);
                return;
            }

            targetPlayer.gameObject.AddComponent<PendingTrade>().Setup(sender);
            SendMessage(sender, MessageType.RequestSent, "{name}", targetPlayer.displayName);
            SendMessage(targetPlayer, MessageType.RequestReceived, "{name}", sender.displayName);
        }

        private void AcceptOrCancelRequest(BasePlayer player1, bool cancel)
        {
            var script = player1.GetComponent<PendingTrade>();
            if (script == null)
            {
                SendMessage(player1, MessageType.NoPending);
                return;
            }

            var player2 = script.callerPlayer;
            UnityEngine.Object.Destroy(script);
            if (cancel == true || HaveAbilityForTrading(player1) == false || HaveAbilityForTrading(player2) == false)
            {
                SendMessage(player1, MessageType.TradeCancelled);
                SendMessage(player2, MessageType.TradeCancelled);
                return;
            }

            if (player2 == null)
            {
                return;
            }
            

            BeginTrade(player1, player2);
        }

        private bool HaveAbilityForTrading(BasePlayer player)
        {
            if (player.CanBuild() == false && config.blockInBuildingPrivilege == true)
            {
                SendMessage(player, MessageType.CantRightNow);
                return false;
            }
            
            if (config.blockInRaidblock == true && InRaidBlock(player) == true)
            {
                SendMessage(player, MessageType.CantRightNow);
                return false;
            }

            var message = CanUseTrade(player);
            if (string.IsNullOrEmpty(message) == false)
            {
                SendMessage(player, message);
                return false;
            }

            return true;
        }

        private void BeginTrade(BasePlayer player1, BasePlayer player2)
        {
            SendMessage(player1, MessageType.TradeBegins, "{name1}", player1.displayName, "{name2}", player2.displayName);
            SendMessage(player2, MessageType.TradeBegins, "{name1}", player1.displayName, "{name2}", player2.displayName);
            var perm1 = GetPermission(player1.userID, config.permissions);
            var perm2 = GetPermission(player2.userID, config.permissions);
            if (perm1 == null)
            {
                SendMessage(player1, MessageType.Permission);
                return;
            }

            if (perm2 == null)
            {
                SendMessage(player2, MessageType.Permission);
                return;
            }

            var maxSize = perm1.size > perm2.size ? perm1.size : perm2.size;
            if (maxSize > 12)
            {
                maxSize = 12;
            }

            var front = GameManager.server.CreateEntity(prefabEntity, GetRandomPosition())?.GetComponent<ShopFront>();
            if (front == null)
            {
                return;
            }

            UnityEngine.Object.Destroy(front.GetComponent<DestroyOnGroundMissing>());
            UnityEngine.Object.Destroy(front.GetComponent<GroundWatch>());
            front.globalBroadcast = true;
            front.name = keyName;
            front.enableSaving = false;
            front.Spawn();    

            timer.Once(1f, () =>
            {
                if (player1.IsValid() == false || player2.IsValid() == false)
                {
                    return;
                }

                SendEntity(player1, player2);
                SendEntity(player2, player1);
                var customerInventory = front.customerInventory;
                var vendorInventory = front.inventory;
                customerInventory.capacity = maxSize;
                vendorInventory.capacity = maxSize;
                OpenContainer(player1, front, vendorInventory);
                OpenContainer(player2, front, vendorInventory);
                front.customerPlayer = player1;
                player1.inventory.loot.AddContainer(customerInventory);
                player1.inventory.loot.SendImmediate();
                front.vendorPlayer = player2;
                player2.inventory.loot.AddContainer(customerInventory);
                player2.inventory.loot.SendImmediate();
                front.UpdatePlayers();
                ModifyFront(front);
                MimicPlayer(front, player2.userID.IsSteamId() ? player1 : player2);
                
                if (config.startCooldownAtAccepting == true)
                {
                    var data1 = Data.Get(player1.UserIDString, true);
                    var data2 = Data.Get(player2.UserIDString, true);
                    data1.lastTradeUse = DateTime.UtcNow;
                    data2.lastTradeUse = DateTime.UtcNow;
                }
            });
        }

        private static Vector3 GetRandomPosition()
        {
            var randomX = Core.Random.Range(-1000, 1000);
            var randomZ = Core.Random.Range(-1000, 1000);
            var randomPos = new Vector3(randomX, -1000, randomZ);
            return randomPos;
        }

        private static void ModifyFront(ShopFront front)
        {
            front.customerInventory.MarkDirty();
            front.vendorInventory.MarkDirty();
            front.customerInventory.onItemAddedRemoved += (item, b) => UpdateItem(item, b);
            front.vendorInventory.onItemAddedRemoved  += (item, b) => UpdateItem(item, b);
            front.customerInventory.canAcceptItem += (item, i) =>
            {
                return CanAcceptItem(item, i, front, false);
            };
            front.vendorInventory.canAcceptItem += (item, i) =>
            {
                return CanAcceptItem(item, i, front, true);
            };
        }

        private static bool CanAcceptItem(Item item, int slot, ShopFront entity, bool forVendor)
        {
            var itemOwner = item.GetOwnerPlayer();
            var itemParent = item.parent;
            var word = forVendor ? "Vendor" : "Customer";
            var allowedPlayer = forVendor ? entity.vendorPlayer : entity.customerPlayer;
            var allowedInventory = forVendor ? entity.vendorInventory : entity.customerInventory;
            var flag1 = allowedPlayer == itemOwner;
            var flag2 = itemParent == allowedInventory;
            var flag3 = allowedInventory.GetSlot(slot) == null;
            var flagFinal = (flag1 || flag2) && flag3;
            
            if (itemOwner != null && itemOwner.IsAdmin == true)
            {
                itemOwner.ConsoleMessage($"Can accept '{item.info.shortname} x{item.amount}' in {word}: {flagFinal} ({flag1}, {flag2}, {flag3})");
            }
            
            if (flagFinal == true)
            {
                RemoveMods(item);
                return true;
            }
            else
            {
                return false;
            }
        }

        private void MimicPlayer(ShopFront front, BasePlayer player)
        {
            if (player.userID.IsSteamId() == true)
            {
                return;
            }
            
            var inventory = front.vendorPlayer == player ? front.vendorInventory : front.customerInventory;

            timer.Repeat(5f, 12, () =>
            {
                if (front.IsValid() == true && player.IsValid() == true)
                {
                    if (inventory.itemList.Count == 0)
                    {
                        var item = ItemManager.CreateByName("rifle.ak");
                        var sub = ItemManager.CreateByName("weapon.mod.8x.scope");
                        var item2 = ItemManager.CreateByName("wood", 1000);
                        sub.MoveToContainer(item.contents);
                        player.GiveItem(item);
                        player.GiveItem(item2);
                        item.MoveToContainer(inventory);
                        item2.MoveToContainer(inventory);
                    }
                        
                    front.AcceptClicked(new BaseEntity.RPCMessage {player = player});
                }
            });
        }

        private static void OpenContainer(BasePlayer player, BaseEntity entity, ItemContainer container)
        {
            player.EndLooting();
            var loot = player.inventory.loot;
            if (entity == null)
            {
                var position = player.transform.position + new Vector3(0, 500, 0);
                entity = GameManager.server.CreateEntity("assets/prefabs/visualization/sphere.prefab", position);
                if (entity != null)
                {
                    entity.enableSaving = false;
                    entity.Spawn();
                    container.entityOwner = entity;
                }
                else
                {
                    return;
                }
            }

            container.playerOwner = player;
            loot.Clear();
            loot.PositionChecks = false;
            loot.entitySource = entity;
            loot.itemSource = (Item) null;
            loot.MarkDirty();
            loot.AddContainer(container);
            loot.SendImmediate();
            player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", "shopfront");
            player.SendNetworkUpdateImmediate();
        }

        private void TestTrade(BasePlayer player1)
        {
            var position = new Vector3(1000, 2000, 1000);
            var player2 = GameManager.server.CreateEntity(prefabTestPlayer, position).GetComponent<BasePlayer>();
            if (player2 != null)
            {
                player2.Spawn();
                if (testTradeFlag == true)
                {
                    BeginTrade(player1, player2);
                }
                else
                {
                    BeginTrade(player2, player1);
                }

                var type = testTradeFlag ? "cusomer" : "vendor";
                testTradeFlag = !testTradeFlag;
                player1.ChatMessage($"Test trade flag is now: {testTradeFlag}, you are now {type}");
            }
        }

        private static void RemoveMods(Item item)
        {
            if (item == null)
            {
                return;
            }

            var parent = item.parent;
            if (parent != null && item.contents != null)
            {
                foreach (var mod in item.contents.itemList.ToArray())
                {
                    if (mod.MoveToContainer(parent) == false)
                    {
                        mod.Drop(item.parent.dropPosition, Vector3.zero);
                    }
                }
            }
        }

        private static void ResetFront(Item item)
        {
            var parent = item.parent?.entityOwner as ShopFront;
            if (parent != null)
            {
                parent.ResetTrade();
            }
        }

        private static void UpdateItem(Item item, bool action)
        {
            if (action)
            {
                item.OnDirty += ResetFront;
            }
            else
            {
                item.OnDirty -= ResetFront;
            }
        }

        #endregion

        #region Utils

        private static object FindPlayer(string targetName)
        {
            var match = new Predicate<BasePlayer>(x =>
                x.UserIDString == targetName || x.displayName.Contains(targetName, CompareOptions.IgnoreCase));
            var targets = BasePlayer.activePlayerList.Where(x => match(x)).ToArray();
            if (targets.Length == 0)
            {
                return targetName;
            }

            if (targets.Length > 1)
            {
                return targets.Select(x => x.displayName).ToSentence();
            }

            return targets[0];
        }

        private static void RunEffect(Vector3 position, string prefab, BasePlayer player = null)
        {
            var effect = new Effect();
            
            effect.Init(Effect.Type.Generic, position, Vector3.zero);
            effect.pooledString = prefab;

            var repeats = Convert.ToInt32(config.effectsVolume);
            if (repeats < 1)
            {
                repeats = 1;
                position -= new Vector3(0, Math.Abs(config.effectsVolume), 0);
            }

            for (var i = 0; i < repeats; i++)
            {
                if (player != null)
                {
                    EffectNetwork.Send(effect, player.net.connection);
                }
                else
                {
                    EffectNetwork.Send(effect);
                }
            }
        }

        private static void SendEntity(BasePlayer player, BaseEntity entity)
        {
            // var connection = player.Connection;
            // if (Network.Net.sv.write.Start() == false || connection == null) return;
            // ++connection.validate.entityUpdates;
            // var saveInfo = new BaseNetworkable.SaveInfo() {forConnection = connection, forDisk = false};
            // Network.Net.sv.write.PacketID(Network.Message.Type.Entities);
            // Network.Net.sv.write.UInt32(connection.validate.entityUpdates);
            // entity.ToStreamForNetwork((Stream) Network.Net.sv.write, saveInfo);
            // Network.Net.sv.write.Send(new SendInfo(connection));
            
            if ((UnityEngine.Object) entity == (UnityEngine.Object) null || entity.net == null)
                return;
            var netWrite = Network.Net.sv.StartWrite();
            ++player.net.connection.validate.entityUpdates;
            var saveInfo = new BaseNetworkable.SaveInfo()
            {
                forConnection = player.net.connection,
                forDisk = false
            };
            netWrite.PacketID(Network.Message.Type.Entities);
            netWrite.UInt32(player.net.connection.validate.entityUpdates);
            entity.ToStreamForNetwork((Stream) netWrite, saveInfo);
            netWrite.Send(new SendInfo(player.net.connection));
        }
        
        private void LogTrade(ShopFront entity)
        {
            var player1 = entity.vendorPlayer;
            var player2 = entity.customerPlayer;
            var inventory1 = entity.vendorInventory;
            var inventory2 = entity.customerInventory;
            var text = $"\n{player1.displayName}[{player1.userID}] (Vendor) and {player2.displayName}[{player2.userID}] (Customer)\n" +
                       $"Finished trade at {DateTime.UtcNow} (UTC) with {inventory1.itemList.Count} + {inventory2.itemList.Count} items!\n";
 
            text += "Vendor sent:\n";
            foreach (var item in inventory1.itemList)
            {
                text += $" * {item.info.shortname} x{item.amount}\n";
            }
            
            text += "Customer sent:\n";
            foreach (var item in inventory2.itemList)
            {
                text += $" * {item.info.shortname} x{item.amount}\n";
            }
            
            LogToFile("results", text, this);
        }

        #endregion

        #region Configuration | 2.0.0

        private static ConfigData config = new ConfigData();

        private class ConfigData
        {
            [JsonProperty(PropertyName = "Command")]
            public string[] command =
            {
                "trade",
                "t"
            };

            [JsonProperty(PropertyName = "Extra accept command")]
            public string[] acceptCommand =
            {
                "ta",
                "taccept"
            };

            [JsonProperty(PropertyName = "Extra decline command")]
            public string[] declineCommand =
            {
                "td",
                "tcancel",
            };

            [JsonProperty(PropertyName = "Effect on completing trade")]
            public string effectOnCompleteTrade = "assets/prefabs/building/wall.frame.shopfront/effects/metal_transaction_complete.prefab";

            [JsonProperty(PropertyName = "Effect on pending request")]
            public string effectOnRequest = "assets/bundled/prefabs/fx/invite_notice.prefab";

            [JsonProperty(PropertyName = "Log trades")]
            public bool logTrade = false;

            [JsonProperty(PropertyName = "Block trade in raidblock")]
            public bool blockInRaidblock = true;
 
            [JsonProperty(PropertyName = "Block in building privilege")]
            public bool blockInBuildingPrivilege = true;

            [JsonProperty(PropertyName = "Start cooldown after accepting trade")]
            public bool startCooldownAtAccepting = false;

            [JsonProperty(PropertyName = "Effects volume")]
            public float effectsVolume = 1f;

            [JsonProperty("Chat sender id")]
            public ulong senderId = 0;

            [JsonProperty(PropertyName = "Permissions")]
            public PermissionEntry[] permissions =
            {
                new PermissionEntry {permission = "trade.default", priority = 1, size = 2, cooldown = 600,},
                new PermissionEntry {permission = "trade.vip", priority = 2, size = 6, cooldown = 300,},
                new PermissionEntry {permission = "trade.top", priority = 3, size = 12, cooldown = 60,},
            };
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<ConfigData>();
                if (config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                PrintError("Configuration file is corrupt! Check your config file at https://jsonlint.com/");
                timer.Every(10f,
                    () =>
                    {
                        PrintError("Configuration file is corrupt! Check your config file at https://jsonlint.com/");
                    });
                LoadDefaultConfig();
                return;
            }

            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            config = new ConfigData();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(config);
        }

        #endregion
        
        #region Language | 24.05.2020
        
        private Dictionary<object, string> langMessages = new Dictionary<object, string>
        {
            {MessageType.Usage, "Usage:\n/trade playerName\n/trade yes\n/trade no"}, 
            {MessageType.NoPending, "There are no pending trades!"},
            {MessageType.RequestAlreadyPending, "That player already have pending requests!"},
            {MessageType.TradeBegins, "Trade between {name1} and {name2} begins!"},
            {MessageType.RequestSent, "You sent trade request to {name}"},
            {MessageType.RequestReceived, "You received trade request from {name}"},
            {MessageType.TradeCancelled, "Trade was cancelled"}, 
            {MessageType.CantRightNow, "You can't do that right now"},
            {MessageType.Cooldown, "Cooldown for {seconds}"},
            {MessageType.Permission, "You don't have permission to do that!"},
            {MessageType.NoPlayers, "There are no players with that 'Name' or 'Steam ID' ({name})"},
            {MessageType.MultiplePlayers, "There are multiple players with that 'Name' :\n{list}"}
        };

        private enum MessageType
        {
            Usage,
            Permission,
            Cooldown,
            NoPending,
            RequestAlreadyPending,
            TradeBegins,
            TradeCancelled,
            RequestSent,
            RequestReceived,
            CantRightNow,
            MultiplePlayers,
            NoPlayers
        }
        
        protected override void LoadDefaultMessages()
        {
            var dictionary = new Dictionary<string, string>();
            foreach (var pair in langMessages)
            {
                var key = pair.Key.ToString();
                var value = pair.Value;
                dictionary.TryAdd(key, value);
            }
            lang.RegisterMessages(dictionary, this);
        }

        private string GetMessage(MessageType key, string playerID = null, params object[] args)
        {
            var keyString = key.ToString();
            var message = lang.GetMessage(keyString, this, playerID);
            if (message == keyString)
            {
                return $"{keyString} is not defined in lang!";
            }
            
            var organized = OrganizeArgs(args);
            message = ReplaceArgs(message, organized);
            return message;
        }
        
        private static Dictionary<string, object> OrganizeArgs(object[] args)
        {
            var dic = new Dictionary<string, object>();
            for (var i = 0; i < args.Length; i += 2)
            {
                var value = args[i].ToString();
                var nextValue = i + 1 < args.Length ? args[i + 1] : null;
                dic.TryAdd(value, nextValue);
            }

            return dic;
        }

        private static string ReplaceArgs(string message, Dictionary<string, object> args)
        {
            if (args == null || args.Count < 1)
            {
                return message;
            }
            
            foreach (var pair in args)
            {
                var s0 = "{" + pair.Key + "}";
                var s1 = pair.Key;
                var s2 = pair.Value != null ? pair.Value.ToString() : "null";
                message = message.Replace(s0, s2, StringComparison.OrdinalIgnoreCase);
                message = message.Replace(s1, s2, StringComparison.OrdinalIgnoreCase);
            }

            return message;
        }

        private void SendMessage(object receiver, MessageType key, params object[] args)
        {
            var userID = (receiver as BasePlayer)?.UserIDString;
            var message = GetMessage(key, userID, args);
            SendMessage(receiver, message);
        }
        
        private void SendMessage(object receiver, string message)
        {
            if (receiver == null)
            {
                Puts(message);
                return;
            }
            
            var console = receiver as ConsoleSystem.Arg;
            if (console != null)
            {
                SendReply(console, message);
                return;
            }
            
            var player = receiver as BasePlayer;
            if (player != null)
            {
                if (config.senderId == 0)
                {
                    player.ChatMessage(message);
                }
                else
                {
                    player.SendConsoleCommand("chat.add", (object) 2, (object) config.senderId, (object) message);
                }
               
                return;
            }
        }

        private void Broadcast(string message)
        {
            foreach (var player in BasePlayer.activePlayerList)
            {
                player.ChatMessage(message);
            }
        }

        #endregion
        
        #region Data | 2.2.0
        
        private static PluginData Data = new PluginData();
        private string dataFilename => $"{Name}\\data";
        private bool dataValid = false;

        private class DataEntry
        {
            [JsonProperty] private DateTime lastUse = DateTime.UtcNow;
            [JsonProperty] private int loadsCount = 0;
            [JsonIgnore] public double daysSinceLastUse => (DateTime.UtcNow - lastUse).TotalDays;
            [JsonProperty] public DateTime lastTradeUse;

            public void MarkUsed()
            {
                lastUse = DateTime.UtcNow;
                loadsCount++;
            }
        }
        
        private class PluginData
        {
            /* ### Values ### */
            // ReSharper disable once MemberCanBePrivate.Local
            [JsonProperty] private Dictionary<string, DataEntry> values = new Dictionary<string, DataEntry>();
            [JsonProperty] public readonly DateTime creationTime = SaveRestore.SaveCreatedTime;
            [JsonIgnore] private Dictionary<string, DataEntry> cache = new Dictionary<string, DataEntry>();
            
            /* ### Variables ### */
            [JsonIgnore] public bool needWipe => differentCreationDates;
            [JsonIgnore] public bool needCleanup => values.Count > minimalLimitForCleanup;
            [JsonIgnore] private bool differentCreationDates => (SaveRestore.SaveCreatedTime - creationTime).TotalHours > 1;
            [JsonIgnore] private static int cacheLifeSpan => 300;
            [JsonIgnore] public static int unusedDataLifeSpanDays => 14;
            [JsonIgnore] private static int minimalLimitForCleanup => 500;
            [JsonIgnore] public int valuesCount => values.Count;
            
            public DataEntry Get(object param, bool createNewOnMissing)
            {
                var key = GetKeyFrom(param);
                if (string.IsNullOrEmpty(key) == true)
                {
                    return null;
                }
                
                var value = (DataEntry) null;
                if (cacheLifeSpan > 0 && cache.TryGetValue(key, out value) == true)
                {
                    return value;
                }

                if (values.TryGetValue(key, out value) == false && createNewOnMissing == true)
                {
                    value = new DataEntry();
                    values.Add(key, value);
                }

                if (value != null)
                {
                    value.MarkUsed();

                    if (cacheLifeSpan > 0)
                    {
                        cache.TryAdd(key, value);
                    }
                }
                
                return value;
            }
            
            public void Set(object param, DataEntry value)
            {
                var key = GetKeyFrom(param);
                if (string.IsNullOrEmpty(key) == true)
                {
                    return;
                }

                if (value == null)
                {
                    if (values.ContainsKey(key) == true)
                    {
                        values.Remove(key);
                    }
                    
                    if (cache.ContainsKey(key) == true)
                    {
                        cache.Remove(key);
                    }
                }
                else
                {
                    if (values.TryAdd(key, value) == false)
                    {
                        values[key] = value;
                    
                        if (cache.ContainsKey(key) == true)
                        {
                            cache[key] = value;
                        }
                    }
                }
            }

            public void Cleanup()
            {
                var keys = new List<string>();
                foreach (var pair in values)
                {
                    var key = pair.Key;
                    var value = pair.Value;
                    
                    if (value.daysSinceLastUse > unusedDataLifeSpanDays)
                    {
                        keys.Add(key);
                    }
                }

                foreach (var key in keys)
                {
                    Set(key, null);
                }
            }

            public void ResetCache()
            {
                cache.Clear();
            }

            private static string GetKeyFrom(object obj)
            {
                if (obj == null)
                {
                    return null;
                }

                if (obj is string)
                {
                    return obj as string;
                }

                if (obj is BasePlayer)
                {
                    return (obj as BasePlayer).UserIDString;
                }

                if (obj is BaseNetworkable)
                {
                    return (obj as BaseNetworkable).net?.ID.ToString();
                }

                return obj.ToString();
            }
        }

        private void LoadData()
        {
            try
            {
                Data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>($"{dataFilename}");
                
                if (Data.needWipe == true)
                {
                    Interface.Oxide.DataFileSystem.WriteObject($"{dataFilename}_old", Data);
                    Data = new PluginData();
                    PrintWarning($"Data was wiped by auto-wiping function (Old: {Data.creationTime}, New: {SaveRestore.SaveCreatedTime})");
                }

                if (Data.needCleanup == true)
                {
                    var oldCount = Data.valuesCount;
                    Data.Cleanup();
                    var newCount = Data.valuesCount;
                    PrintWarning($"Removed {oldCount - newCount} values that are older than {PluginData.unusedDataLifeSpanDays} days (Was: {oldCount}, Now: {newCount})");
                }

                dataValid = true;
                timer.Every(Core.Random.Range(500, 700), SaveData);
                SaveData();
            }
            catch (Exception e)
            {
                Data = new PluginData();
                dataValid = false;

                for (var i = 0; i < 5; i++)
                {
                    PrintError("!!! CRITICAL DATA ERROR !!!\n * Data was not loaded!\n * Data auto-save was disabled!");
                }
                
                LogToFile("errors", $"\n\nError: {e.Message}\n\nTrace: {e.StackTrace}\n\n", this);
            }
        }

        private void SaveData()
        {
            if (Data != null && dataValid == true)
            {
                Data.ResetCache();
                Interface.Oxide.DataFileSystem.WriteObject(dataFilename, Data);
            }
        }

        #endregion

        #region Permission Support

        private class PermissionEntry
        {
            [JsonProperty(PropertyName = "Permission")]
            public string permission;

            [JsonProperty(PropertyName = "Priority")]
            public int priority;

            [JsonProperty(PropertyName = "Size")] 
            public int size;

            [JsonProperty(PropertyName = "Cooldown")]
            public int cooldown;
        }

        private PermissionEntry GetPermission(ulong playerID, PermissionEntry[] permissions)
        {
            var value = (PermissionEntry) null;
            var idString = playerID.ToString();
            var num = -1;
            foreach (var entry in permissions)
            {
                if (permission.UserHasPermission(idString, entry.permission) && entry.priority > num)
                {
                    num = entry.priority;
                    value = entry;
                }
            }

            if (playerID.IsSteamId() == false)
            {
                value = permissions.FirstOrDefault();
            }

            return value;
        }

        #endregion

        #region Scripts

        private class PendingTrade : MonoBehaviour
        {
            private BasePlayer targetPlayer;
            public BasePlayer callerPlayer;

            private void Awake()
            {
                targetPlayer = GetComponent<BasePlayer>();
            }

            private void Start()
            {
                RunEffect(targetPlayer.transform.position, config.effectOnRequest, targetPlayer);
                RunEffect(callerPlayer.transform.position, config.effectOnRequest, callerPlayer);
                Invoke(nameof(TimedDestroy), 30f);
            }

            public void Setup(BasePlayer v2)
            {
                callerPlayer = v2;
            }

            public void TimedDestroy()
            {
                Destroy(this);
                plugin.SendMessage(targetPlayer, MessageType.TradeCancelled);
            }
        }

        #endregion

        #region NoEscape API

        [PluginReference] private Plugin NoEscape;

        private bool InRaidBlock(BasePlayer player)
        {
            return NoEscape?.Call<bool>("IsRaidBlocked", player) ?? false;
        }

        private static string CanUseTrade(BasePlayer player)
        {
            var result = Interface.CallHook("CanTrade", player);
            return result?.ToString();
        }

        #endregion
    }
}

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