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

FREE Recycle : 3.1.2 3.1.2

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

namespace Oxide.Plugins
{
    [Info("Recycle", "5Dev24", "3.1.2")]
    [Description("Recycle items into their resources")]
    public class Recycle : RustPlugin
    {
        private const string RecyclePrefab = "assets/bundled/prefabs/static/recycler_static.prefab",
            BackpackPrefab = "assets/prefabs/misc/item drop/item_drop_backpack.prefab",
            AdminPermission = "recycle.admin",
            RecyclerPermission = "recycle.use",
            CooldownBypassPermission = "recycle.bypass";

        private readonly Dictionary<ulong, EntityAndPlayer> _recyclers = new Dictionary<ulong, EntityAndPlayer>();
        private readonly Dictionary<ulong, EntityAndPlayer> _droppedBags = new Dictionary<ulong, EntityAndPlayer>();
        private readonly Dictionary<ulong, long> _cooldowns = new Dictionary<ulong, long>();
        private ConfigData _data;

        #region Hooks

        private void Init() => this.Unsubscribe(nameof(CanNetworkTo));

        private void Loaded()
        {
            this.LoadMessages();
            this.ValidateConfig();
            this._data = Config.ReadObject<ConfigData>();

            this.AddCovalenceCommand(this._data?.Settings?.RecycleCommand ?? "recycle", "RecycleCommand");

            permission.RegisterPermission(Recycle.AdminPermission, this);
            permission.RegisterPermission(Recycle.RecyclerPermission, this);
            permission.RegisterPermission(Recycle.CooldownBypassPermission, this);
        }

        private void Unload()
        {
            this.DestroyRecyclers();
            this.DestroyBags();
        }

        private void OnLootEntityEnd(BasePlayer p, BaseEntity e)
        {
            if (this.IsRecycleBox(e)) this.DestroyRecycler(e);
        }

        private void OnPlayerDisconnected(BasePlayer p, string reason)
        {
            BaseEntity result = this.RecyclerFromPlayer(p.userID);
            if (result != null) this.DestroyRecycler(result);

            EntityAndPlayer[] eaps = this._droppedBags.Values.Where(e => e.Player.userID == p.userID).ToArray();
            foreach (EntityAndPlayer eap in eaps)
                eap.Entity.Kill();
        }

        private object CanMoveItem(Item item, PlayerInventory pLoot, ItemContainerId targetContainerId, int targetSlot, int amount)
        {
            if (!this._data.Settings.ToInventory || targetSlot < 6) return null;

            foreach (ItemContainer con in pLoot.loot.containers)
            {
                if (con.uid != targetContainerId || con.entityOwner == null) continue;

                Recycler r = con.entityOwner as Recycler;
                if (this.IsRecycleBox(r)) return false;
            }

            return null;
        }

        private object CanAcceptItem(ItemContainer con, Item i, int target)
        {
            if (!(con.entityOwner is Recycler)) return null;

            Recycler owner = (Recycler)con.entityOwner;
            if (!this.IsRecycleBox(owner)) return null;

            BasePlayer p = this.PlayerFromRecycler(owner.net.ID.Value);
            if (p == null) return null;

            if (target < 6)
            {
                if (!this._data.Settings.RecyclableTypes.Contains(Enum.GetName(typeof(ItemCategory),
                        i.info.category)) ||
                    this._data.Settings.Blacklist.Contains(i.info.shortname))
                {
                    if (p != null) this.PrintToChat(p, this.GetMessage("Recycle", "Invalid", p));
                    return ItemContainer.CanAcceptResult.CannotAcceptRightNow;
                }
                else
                    NextFrame(() =>
                    {
                        if (owner == null || !owner.HasRecyclable()) return;

                        if (this._data.Settings.InstantRecycling)
                        {
                            if (owner.IsOn()) return;
                            owner.InvokeRepeating(owner.RecycleThink, 0, 0);
                            owner.SetFlag(BaseEntity.Flags.On, true);
                            owner.SendNetworkUpdateImmediate();
                        }
                        else owner.StartRecycling();
                    });
            }
            else if (this._data.Settings.ToInventory)
                NextFrame(() =>
                {
                    if (p == null || p.inventory == null || p.inventory.containerMain == null ||
                        p.inventory.containerBelt == null || i == null) return;

                    bool flag = false;
                    if (!p.inventory.containerMain.IsFull())
                        flag = i.MoveToContainer(p.inventory.containerMain);
                    if (!flag && !p.inventory.containerBelt.IsFull())
                        i.MoveToContainer(p.inventory.containerBelt);
                });

            return null;
        }

        private object OnItemRecycle(Item item, Recycler recycler)
        {
            if (!this.IsRecycleBox(recycler)) return null;

            BasePlayer p = this.PlayerFromRecycler(recycler.net.ID.Value);
            if (p == null || recycler.transform.position == p.transform.position) return null;

            Transform transform = recycler.transform;
            Vector3 old = transform.position;

            transform.position = p.transform.position;
            recycler.SendNetworkUpdateImmediate();
            this.NextFrame(() =>
            {
                if (recycler == null) return;
                transform.position = old;
                recycler.SendNetworkUpdateImmediate();
            });

            return null;
        }

        private object CanLootEntity(BasePlayer p, DroppedItemContainer con)
        {
            if (this._droppedBags.ContainsKey(con.net.ID.Value) &&
                this._droppedBags[con.net.ID.Value].Player.userID != p.userID) return false;
            return null;
        }

        private object CanNetworkTo(BaseNetworkable e, BasePlayer p)
        {
            if (e == null || p == null || p == e || p.IsAdmin) return null;

            if (this.IsRecycleBox(e))
                return (this.PlayerFromRecycler(e.net.ID.Value)?.userID ?? 0) == p.userID;
            return null;
        }

        private void OnEntityKill(BaseNetworkable e)
        {
            if (e is DroppedItemContainer && this._droppedBags.ContainsKey(e.net.ID.Value))
                this._droppedBags.Remove(e.net.ID.Value);
        }

        private void LoadMessages()
        {
            Func<string, string> youCannot = (thing) => "You cannot recycle while " + thing;

            lang.RegisterMessages(new Dictionary<string, string>
            {
                { "Recycle -> DestroyedAllBags", "All bags have been destroyed" },
                { "Recycle -> DestroyedAll", "All recyclers have been destroyed" },
                { "Recycle -> Dropped", "You left some items in the recycler!" },
                { "Recycle -> Invalid", "You cannot recycle that!" },
                { "Denied -> Permission", "You don't have permission to use that command" },
                { "Denied -> Privilege", "You cannot recycle within someone's building privilege" },
                { "Denied -> Swimming", youCannot("swimming") },
                { "Denied -> Falling", youCannot("falling") },
                { "Denied -> Mounted", youCannot("mounted") },
                { "Denied -> Wounded", youCannot("wounded") },
                { "Denied -> Irradiation", youCannot("irradiated") },
                { "Denied -> Ship", youCannot("on a ship") },
                { "Denied -> Elevator", youCannot("on an elevator") },
                { "Denied -> Balloon", youCannot("on a balloon") },
                { "Denied -> Safe Zone", youCannot("in a safe zone") },
                { "Denied -> Hook Denied", "You can't recycle right now" },
                { "Cooldown -> In", "You need to wait {0} before recycling" },
                { "Timings -> second", "second" },
                { "Timings -> seconds", "seconds" },
                { "Timings -> minute", "minute" },
                { "Timings -> minutes", "minutes" }
            }, this);
        }

        #endregion

        #region HumanNPC Support

        private void OnUseNPC(BasePlayer npc, BasePlayer p)
        {
            if (this._data?.Settings?.NPCIds != null && !this._data.Settings.NPCIds.Contains(npc.UserIDString)) return;
            this.OpenRecycler(p);
        }

        #endregion

        #region Commands

        private void RecycleCommand(IPlayer iP, string cmd, string[] args)
        {
            BasePlayer p = iP.Object as BasePlayer;
            if (p == null || this._data.Settings.NPCOnly || !this.CanPlayerOpenRecycler(p)) return;

            this.OpenRecycler(p);
            if (this._data.Settings.Cooldown <= 0) return;

            if (this._cooldowns.ContainsKey(p.userID))
                this._cooldowns[p.userID] = DateTimeOffset.Now.ToUnixTimeSeconds();
            else
                this._cooldowns.Add(p.userID, DateTimeOffset.Now.ToUnixTimeSeconds());
        }

        [ChatCommand("purgerecyclers")]
        private void PurgeRecyclersChatCommand(BasePlayer p, string cmd, string[] args)
        {
            if (this.CanManageRecyclers(p.userID))
            {
                this.DestroyRecyclers();
                this.PrintToChat(p, this.GetMessage("Recycle", "DestroyedAll", p));
            }
            else this.PrintToChat(p, this.GetMessage("Denied", "Permission", p));
        }

        [ChatCommand("purgebags")]
        private void PurgeBagsChatCommand(BasePlayer p, string cmd, string[] args)
        {
            if (this.CanManageRecyclers(p.userID))
            {
                this.DestroyBags();
                this.PrintToChat(p, this.GetMessage("Recycle", "DestroyedAllBags", p));
            }
            else this.PrintToChat(p, this.GetMessage("Denied", "Permission", p));
        }

        #endregion

        #region Structs

        public struct EntityAndPlayer
        {
            public BaseEntity Entity;
            public BasePlayer Player;
        }

        public class ConfigData
        {
            public class SettingsWrapper
            {
                [JsonProperty("Command To Open Recycler")]
                public string RecycleCommand = "recycle";

                [JsonProperty("Cooldown (in minutes)")]
                public float Cooldown = 5.0f;

                [JsonProperty("Maximum Radiation")] public float RadiationMax = 1f;
                [JsonProperty("Refund Ratio")] public float RefundRatio = 0.5f;
                [JsonProperty("NPCs Only")] public bool NPCOnly;

                [JsonProperty("Allowed In Safe Zones")]
                public bool AllowedInSafeZones = true;

                [JsonProperty("Instant Recycling")] public bool InstantRecycling = false;

                [JsonProperty("Send Recycled Items To Inventory")]
                public bool ToInventory = false;

                [JsonProperty("Send Items To Inventory Before Bag")]
                public bool InventoryBeforeBag = false;

                [JsonProperty("NPC Ids")] public List<object> NPCIds = new List<object>();
                [JsonProperty("Recyclable Types")] public List<object> RecyclableTypes = new List<object>();
                [JsonProperty("Blacklisted Items")] public List<object> Blacklist = new List<object>();
            }

            public SettingsWrapper Settings = new SettingsWrapper();
            public string VERSION = "3.1.0";
        }

        #endregion

        #region Configuration

        protected override void LoadDefaultConfig()
        {
            ConfigData tmp = new ConfigData
            {
                Settings =
                {
                    RecyclableTypes = new List<object>()
                    {
                        "Ammunition", "Attire", "Common", "Component", "Construction", "Electrical",
                        "Fun", "Items", "Medical", "Misc", "Tool", "Traps", "Weapon"
                    }
                }
            };

            Config.WriteObject(tmp, true);
            this._data = tmp;
        }

        private T GetSetting<T>(string val, T defaultVal)
        {
            if (val == null) return default(T);
            object gotten = Config.Get("Settings", val);
            if (gotten == null)
            {
                Config.Set("Settings", val, defaultVal);
                return defaultVal;
            }

            return this.ConvertType(gotten, defaultVal);
        }

        private T ConvertType<T>(object val, T defaultVal)
        {
            if (val == null) return defaultVal;
            return (T)Convert.ChangeType(val, typeof(T));
        }

        private void ValidateConfig()
        {
            this.LoadConfig();
            try
            {
                object version = Config.Get("VERSION");
                if (version == null) this.LoadDefaultConfig();
                else if (version.Equals("2.1.10"))
                {
                    this._data = new ConfigData
                    {
                        Settings = new ConfigData.SettingsWrapper
                        {
                            Cooldown = this.GetSetting("cooldownMinutes", 5f),
                            RefundRatio = this.GetSetting("refundRatio", 0.5f),
                            RadiationMax = this.GetSetting("radiationMax", 1f),
                            NPCOnly = this.GetSetting("NPCOnly", false),
                            NPCIds = this.GetSetting("NPCIDs", new List<object>()),
                            RecyclableTypes = this.GetSetting("recyclableTypes", new List<object>()
                            {
                                "Ammunition", "Attire", "Common", "Component", "Construction", "Electrical",
                                "Fun", "Items", "Medical", "Misc", "Tool", "Traps", "Weapon"
                            }),
                            Blacklist = this.GetSetting("blacklist", new List<object>()),
                            AllowedInSafeZones = this.GetSetting("allowSafeZone", true)
                        }
                    };
                    this.UpdateAndSave();
                }
                else if (version.Equals("3.0.0") || version.Equals("3.0.1") || version.Equals("3.0.3") ||
                         version.Equals("3.0.4") || version.Equals("3.0.5") || version.Equals("3.1.0"))
                {
                    /* All of these versions should handle updating fine due to
                     * the ConfigData object having defaults
                     */
                    this._data = Config.ReadObject<ConfigData>();
                    if (this._data?.Settings == null) this.LoadDefaultConfig();
                    else this.UpdateAndSave();
                }
                else
                {
                    this._data = Config.ReadObject<ConfigData>(); // Pray?
                }
            }
            catch (NullReferenceException)
            {
            }
        }

        private void UpdateAndSave()
        {
            this._data.VERSION = Version.ToString();
            Config.Clear();
            Config.WriteObject(this._data, true);
            Config.Save();
        }

        #endregion

        #region Helpers

        private void CreateRecycler(BasePlayer p)
        {
            Recycler r =
                GameManager.server.CreateEntity(Recycle.RecyclePrefab, p.transform.position + Vector3.down * 500) as
                    Recycler;

            if (r == null) return;

            r.Spawn();

            r.recycleEfficiency = this._data.Settings.RefundRatio;
            r.enableSaving = false;
            r.SetFlag(BaseEntity.Flags.Locked, true);
            r.UpdateNetworkGroup();

            if (!r.isSpawned) return;
            r.gameObject.layer = 0;
            r.SendNetworkUpdateImmediate(true);
            this.Subscribe(nameof(CanNetworkTo));
            this.OpenContainer(p, r);
            this._recyclers.Add(r.net.ID.Value, new EntityAndPlayer { Entity = r, Player = p });
        }

        private void OpenContainer(BasePlayer p, StorageContainer con)
        {
            timer.In(.1f, () =>
            {
                p.EndLooting();
                if (!p.inventory.loot.StartLootingEntity(con, false)) return;
                p.inventory.loot.AddContainer(con.inventory);
                p.inventory.loot.SendImmediate();
                p.ClientRPCPlayer(null, p, "RPC_OpenLootPanel", con.panelName);
                p.SendNetworkUpdate();
            });
        }

        private void DropRecyclerContents(BaseEntity e)
        {
            if (!(e is Recycler) || !this.IsRecycleBox(e)) return;

            Recycler recycler = (Recycler)e;

            if ((recycler.inventory?.itemList?.Count ?? 0) == 0) return;

            BasePlayer p = this.PlayerFromRecycler(recycler.net.ID.Value);
            if (p == null) return;
            this.PrintToChat(p, this.GetMessage("Recycle", "Dropped", p));

            List<Item> items = recycler.inventory.itemList.ToList();

            if (this._data.Settings.InventoryBeforeBag)
            {
                for (int i = 0; i < items.Count; i++)
                {
                    Item item = items[i];

                    bool flag = false;

                    if (!p.inventory.containerMain.IsFull())
                        flag = item.MoveToContainer(p.inventory.containerMain);

                    if (!flag && !p.inventory.containerBelt.IsFull())
                    {
                        item.MoveToContainer(p.inventory.containerBelt);
                    }

                    if (!flag) continue;

                    items.RemoveAt(i);
                    i--;
                }
            }

            if (items.Count == 0) return;

            DroppedItemContainer bag =
                GameManager.server.CreateEntity(Recycle.BackpackPrefab, p.transform.position + Vector3.up,
                    Quaternion.identity) as DroppedItemContainer;

            if (bag == null) return;

            bag.enableSaving = false;
            bag.TakeFrom(new[] { recycler.inventory });
            bag.Spawn();
            bag.lootPanelName = "generic_resizable";
            bag.playerSteamID = p.userID;
            this._droppedBags.Add(bag.net.ID.Value, new EntityAndPlayer { Entity = bag, Player = p });
        }

        private void DestroyRecycler(BaseEntity e)
        {
            if (this.IsRecycleBox(e))
            {
                this.DropRecyclerContents(e);
                this._recyclers.Remove(e.net.ID.Value);
                e.Kill();
            }

            if (this._recyclers.Count == 0)
                this.Unsubscribe(nameof(CanNetworkTo));
        }

        private void DestroyRecyclers()
        {
            while (this._recyclers.Count > 0)
                this.DestroyRecycler(this._recyclers.FirstOrDefault().Value.Entity);

            this.Unsubscribe(nameof(CanNetworkTo));
            this._recyclers.Clear();
        }

        private void DestroyBags()
        {
            while (this._droppedBags.Count > 0)
            {
                KeyValuePair<ulong, EntityAndPlayer> ueap = this._droppedBags.FirstOrDefault();
                this._droppedBags.Remove(ueap.Value.Entity.net.ID.Value);
                ueap.Value.Entity.Kill();
            }

            this._droppedBags.Clear();
        }

        private string GetMessage(string top, string bottom, BasePlayer p)
        {
            string id = null;
            if (p != null)
                id = p.UserIDString;

            return lang.GetMessage(top + " -> " + bottom, this, id);
        }

        private int[] GetCooldown(ulong uid)
        {
            long time;
            if (!this._cooldowns.TryGetValue(uid, out time)) return new int[] { 0, 0 };

            time += (long)this._data.Settings.Cooldown * 60;
            long now = DateTimeOffset.Now.ToUnixTimeSeconds();

            if (now > time) return new int[] { 0, 0 };

            TimeSpan diff = TimeSpan.FromSeconds(time - DateTimeOffset.Now.ToUnixTimeSeconds());
            return new int[] { diff.Minutes, diff.Seconds };
        }

        private string CooldownTimesToString(int[] times, BasePlayer p)
        {
            if (times == null || times.Length != 2) return "";
            int mins = times[0], secs = times[1];
            return (
                string.Format(
                    mins == 0 ? "" : ("{0} " + this.GetMessage("Timings", mins == 1 ? "minute" : "minutes", p)), mins) +
                string.Format(" {0} " + this.GetMessage("Timings", secs == 1 ? "second" : "seconds", p), secs)
            ).Trim();
        }

        #endregion

        #region API

        public bool IsRecycler(ulong netID) => this._recyclers.ContainsKey(netID);

        public BasePlayer PlayerFromRecycler(ulong netID) =>
            !this.IsRecycler(netID) ? null : this._recyclers[netID].Player;

        public BaseEntity RecyclerFromPlayer(ulong uid)
        {
            foreach (EntityAndPlayer eap in this._recyclers.Values)
                if (eap.Player.userID == uid)
                    return eap.Entity;
            return null;
        }

        public bool IsOnCooldown(ulong uid) => !this.CanBypassCooldown(uid) && this._cooldowns.ContainsKey(uid) &&
                                               this._cooldowns[uid] + (int)(this._data?.Settings?.Cooldown ?? 5) * 60 >
                                               DateTimeOffset.Now.ToUnixTimeSeconds();

        public bool CanUseRecycler(ulong uid) =>
            this.permission.UserHasPermission(uid + "", Recycle.RecyclerPermission);

        public bool CanManageRecyclers(ulong uid) =>
            this.permission.UserHasPermission(uid + "", Recycle.AdminPermission);

        public bool CanBypassCooldown(ulong uid) =>
            this.permission.UserHasPermission(uid + "", Recycle.CooldownBypassPermission);

        #region Friendly API

        // Backwards compatability support
        public bool IsRecycleBox(BaseNetworkable e)
        {
            if (e == null || e.net == null) return false;
            return this.IsRecycler(e.net.ID.Value);
        }

        public bool CanPlayerOpenRecycler(BasePlayer p)
        {
            if (p == null || p.IsDead()) this.PrintToChat(p, this.GetMessage("Denied", "Hook Denied", p));
            else if (!this.CanUseRecycler(p.userID) && !this.CanManageRecyclers(p.userID))
                this.PrintToChat(p, this.GetMessage("Denied", "Permission", p));
            else if (this._data.Settings.Cooldown > 0 && this.IsOnCooldown(p.userID))
                this.PrintToChat(p, this.GetMessage("Cooldown", "In", p),
                    this.CooldownTimesToString(this.GetCooldown(p.userID), p));
            else if (p.IsWounded()) this.PrintToChat(p, this.GetMessage("Denied", "Wounded", p));
            else if (!p.CanBuild()) this.PrintToChat(p, this.GetMessage("Denied", "Privilege", p));
            else if (this._data.Settings.RadiationMax > 0 && p.radiationLevel > this._data.Settings.RadiationMax)
                this.PrintToChat(p, this.GetMessage("Denied", "Irradiation", p));
            else if (p.IsSwimming()) this.PrintToChat(p, this.GetMessage("Denied", "Swimming", p));
            else if (!p.IsOnGround() || p.IsFlying || p.isInAir)
                this.PrintToChat(p, this.GetMessage("Denied", "Falling", p));
            else if (p.isMounted) this.PrintToChat(p, this.GetMessage("Denied", "Mounted", p));
            else if (p.GetComponentInParent<CargoShip>()) this.PrintToChat(p, this.GetMessage("Denied", "Ship", p));
            else if (p.GetComponentInParent<HotAirBalloon>())
                this.PrintToChat(p, this.GetMessage("Denied", "Balloon", p));
            else if (p.GetComponentInParent<Lift>()) this.PrintToChat(p, this.GetMessage("Denied", "Elevator", p));
            else if (!this._data.Settings.AllowedInSafeZones && p.InSafeZone())
                this.PrintToChat(p, this.GetMessage("Denied", "Safe Zone", p));
            else
            {
                object ret = Interface.Call("CanOpenRecycler", p);
                if (ret is bool && !(bool)ret)
                    this.PrintToChat(p, this.GetMessage("Denied", "Hook Denied", p));
                else return true;
            }

            return false;
        }

        public bool IsOnCooldown(BasePlayer p) => this.IsOnCooldown(p.userID);

        public void OpenRecycler(BasePlayer p)
        {
            if (p == null) return;
            BaseEntity result = this.RecyclerFromPlayer(p.userID);
            if (result == null) this.CreateRecycler(p);
            else
            {
                this.DestroyRecycler(result);
                this.CreateRecycler(p);
            }
        }

        public void AddNpc(string id)
        {
            if (this._data?.Settings?.NPCIds == null) return;

            this._data.Settings.NPCIds.Add(id);
            Config.WriteObject(this._data, true);
        }

        public void RemoveNpc(string id)
        {
            if (this._data?.Settings?.NPCIds == null) return;
            if (this._data.Settings.NPCIds.Remove(id))
                Config.WriteObject(this._data, true);
        }

        #endregion

        #endregion
    }
}

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