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

FREE FrameBox : 1.0.2 1.0.2

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

namespace Oxide.Plugins
{
    [Info("Frame Box", "MJSU", "1.0.2")]
    [Description("Deploys a frame on a box allowing the player to set the image")]
    internal class FrameBox : RustPlugin
    {
        #region Class Fields
        private StoredData _storedData; //Plugin Data
        private PluginConfig _pluginConfig; //Plugin Config

        private static FrameBox _ins;

        private const string UsePermission = "framebox.use";
        private const string NoCostPermission = "framebox.nocost";
        private const string AccentColor = "#de8732";

        private readonly Hash<NetworkableId, BoxData> _boxes = new Hash<NetworkableId, BoxData>();
        private readonly Hash<NetworkableId, FrameData> _frames = new Hash<NetworkableId, FrameData>();
        private readonly Hash<string, ContainerData> _containerPositions = new Hash<string, ContainerData>();
        #endregion

        #region Setup & Loading
        private void Init()
        {
            _ins = this;
            _storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);

            permission.RegisterPermission(UsePermission, this);
            permission.RegisterPermission(NoCostPermission, this);

            cmd.AddChatCommand(_pluginConfig.ChatCommand, this, SignBoxChatCommand);
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                [LangKeys.Chat] = $"<color=#bebebe>[<color={AccentColor}>{Title}</color>] {{0}}</color>",
                [LangKeys.NoPermission] = "You do not have permission to use this command",
                [LangKeys.MissingItem] = "{0}: {1}x",
                [LangKeys.MissingMessage] =
                    "You do not have enough items to add a frame to this box.You're missing:\n{0}",
                [LangKeys.CostPre] = "Cost to make:\n",
                [LangKeys.Cost] = "{0}: {1}x",
                [LangKeys.AddInvalidSyntax] =
                    $"Invalid Syntax: <color={AccentColor}>/{{0}} {{2}} front</color> - to add the frame to the front of the box" +
                    "\nAvailable frame positions for this container are {1}",
                [LangKeys.InvalidAddFramePosition] = "Invalid Frame Position.Available frame positions are:\n {0}",
                [LangKeys.NotLookingAt] = "You're not looking at a box or frame",
                [LangKeys.AddSlotIsTaken] = "The frame position {0} is already taken.Open positions are:\n{1}",
                [LangKeys.AddSuccess] = "You have successfully added a frame onto your box in position {0}." +
                                        "In order to access the box using the frame you need to first lock the frame." +
                                        "The only way to unlock the frame is using the /fb unlock command",
                [LangKeys.RemoveSuccess] = "You have successfully removed the frame from position {0}",
                [LangKeys.UnlockBuildingBlocked] = "Cannot unlock in a building blocked zone",
                [LangKeys.UnlockSuccess] = "You have successfully unlocked the sign.",
                [LangKeys.NotLookingAtFrame] = "You're not looking at a frame.",
                [LangKeys.NotLookingAtFrameBoxFrame] = "You're not looking at a frame box frame",
                [LangKeys.NotLookingAtFrameBox] = "You're not looking at a frame box or frame box frame",
                [LangKeys.NoFrameInPosition] = "There is no frame in position {0}",
                [LangKeys.ContainerNotAllowed] = "This container is not allowed to have a frame on it.",
                [LangKeys.NoUnlockPermission] = "You do not have permission to unlock this sign.",
                [LangKeys.AddSubCommand] = "add",
                [LangKeys.RemoveSubCommand] = "remove",
                [LangKeys.CostSubCommand] = "cost",
                [LangKeys.UnlockSubCommand] = "unlock",
                [LangKeys.AllSubOption] = "all",
                [LangKeys.HelpText] =
                    "Allows placing photo frames on boxes.After settings the sign and locking it you can now access the box while looking at the sign.\n" +
                    $"<color={AccentColor}>/{{0}} {{1}}</color> to see the available positions to palace a sign\n" +
                    $"<color={AccentColor}>/{{0}} {{1}} right</color> to place a sign on the right\n" +
                    $"<color={AccentColor}>/{{0}} {{1}} frontleft</color> to place a sign on the front left\n" +
                    $"<color={AccentColor}>/{{0}} {{2}}</color> to remove a sign you're looking at\n" +
                    $"<color={AccentColor}>/{{0}} {{3}}</color> to get the cost of the sign\n" +
                    $"<color={AccentColor}>/{{0}} {{4}}</color> to unlock the sign to allow edits again\n" +
                    $"<color={AccentColor}>/{{0}}</color> to see this help text again\n"
            }, this);
        }

        protected override void LoadDefaultConfig()
        {
            PrintWarning("Loading Default Config");
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            Config.Settings.DefaultValueHandling = DefaultValueHandling.Populate;
            _pluginConfig = AdditionalConfig(Config.ReadObject<PluginConfig>());
            Config.WriteObject(_pluginConfig);
        }

        //TODO: Fix config back to normal
        public PluginConfig AdditionalConfig(PluginConfig config)
        {
            config.Cost = config.Cost ?? new Hash<string, int>
            {
                ["wood"] = 150
            };

            config.SignPositions = config.SignPositions ?? new Hash<string, ContainerData>
            {
                ["box.wooden.large"] = new ContainerData
                {
                    ItemShortname = "photoframe.portrait",
                    PositionData = new Hash<string, PositionData>
                    {
                        ["Left"] = new PositionData
                        {
                            Offset = new Vector3(0.95f, 0.4f, 0),
                            Rotation = new Vector3(0, 90, 90),
                            IncludeAll = true
                        },
                        ["Right"] = new PositionData
                        {
                            Offset = new Vector3(-0.95f, 0.4f, 0),
                            Rotation = new Vector3(0, 270, 90),
                            IncludeAll = true
                        },
                        ["Front"] = new PositionData
                        {
                            Offset = new Vector3(0, 0.4f, 0.55f),
                            Rotation = new Vector3(0, 0, 90),
                            IncludeAll = false
                        },
                        ["FrontRight"] = new PositionData
                        {
                            Offset = new Vector3(-0.45f, 0.4f, 0.55f),
                            Rotation = new Vector3(0, 0, 90),
                            IncludeAll = true
                        },
                        ["FrontLeft"] = new PositionData
                        {
                            Offset = new Vector3(0.45f, 0.4f, 0.55f),
                            Rotation = new Vector3(0, 0, 90),
                            IncludeAll = true
                        },
                        ["Back"] = new PositionData
                        {
                            Offset = new Vector3(0, 0.4f, -0.55f),
                            Rotation = new Vector3(0, 180, 90),
                            IncludeAll = false
                        },
                        ["BackRight"] = new PositionData
                        {
                            Offset = new Vector3(-0.45f, 0.4f, -0.55f),
                            Rotation = new Vector3(0, 180, 90),
                            IncludeAll = true
                        },
                        ["BackLeft"] = new PositionData
                        {
                            Offset = new Vector3(0.45f, 0.4f, -0.55f),
                            Rotation = new Vector3(0, 180, 90),
                            IncludeAll = true
                        },
                        ["Top"] = new PositionData
                        {
                            Offset = new Vector3(0, 0.775f, 0),
                            Rotation = new Vector3(270, 0, 90),
                            IncludeAll = false
                        },
                        ["TopRight"] = new PositionData
                        {
                            Offset = new Vector3(-0.45f, 0.775f, 0),
                            Rotation = new Vector3(270, 0, 90),
                            IncludeAll = true
                        },
                        ["TopLeft"] = new PositionData
                        {
                            Offset = new Vector3(0.45f, 0.775f, 0),
                            Rotation = new Vector3(270, 0, 90),
                            IncludeAll = true
                        }
                    }
                },
                ["box.wooden"] = new ContainerData
                {
                    ItemShortname = "photoframe.portrait",
                    PositionData = new Hash<string, PositionData>
                    {
                        ["Left"] = new PositionData
                        {
                            Offset = new Vector3(0.49f, 0.35f, 0),
                            Rotation = new Vector3(0, 90, 90),
                            IncludeAll = true
                        },
                        ["Right"] = new PositionData
                        {
                            Offset = new Vector3(-0.49f, 0.35f, 0),
                            Rotation = new Vector3(0, 270, 90),
                            IncludeAll = true
                        },
                        ["Front"] = new PositionData
                        {
                            Offset = new Vector3(0, 0.35f,.39f),
                            Rotation = new Vector3(0, 0, 90),
                            IncludeAll = true
                        },
                        ["Back"] = new PositionData
                        {
                            Offset = new Vector3(0, 0.35f, -.39f),
                            Rotation = new Vector3(0, 180, 90),
                            IncludeAll = true
                        },
                        ["Top"] = new PositionData
                        {
                            Offset = new Vector3(0, 0.6f, 0),
                            Rotation = new Vector3(270, 0, 90),
                            IncludeAll = true
                        }
                    }
                }
            };
            return config;
        }

        private void OnServerInitialized()
        {
            foreach (KeyValuePair<string, ContainerData> entityPositions in _pluginConfig.SignPositions)
            {
                string containerShortname = GetShortPrefabName(entityPositions.Key);
                if (string.IsNullOrEmpty(containerShortname))
                {
                    continue;
                }

                string prefabName = GetPrefabName(entityPositions.Value.ItemShortname);
                if (string.IsNullOrEmpty(prefabName))
                {
                    continue;
                }

                Hash<string, PositionData> positions = new Hash<string, PositionData>();
                foreach (KeyValuePair<string, PositionData> position in entityPositions.Value.PositionData)
                {
                    PositionData data = position.Value;
                    data.DisplayName = position.Key;
                    positions[position.Key.ToLower()] = data;
                }

                ContainerData containerData = new ContainerData
                {
                    ItemShortname = prefabName,
                    PositionData = positions
                };

                _containerPositions[containerShortname] = containerData;
            }

            foreach (KeyValuePair<ulong, Hash<string, ulong>> data in _storedData.FrameData.ToList())
            {
                BoxStorage box = BaseNetworkable.serverEntities.Find(new NetworkableId(data.Key)) as BoxStorage;
                if (box == null)
                {
                    _storedData.FrameData.Remove(data.Key);
                    continue;
                }

                BoxData boxData = new BoxData(box);

                foreach (KeyValuePair<string, ulong> framePos in data.Value.ToList())
                {
                    PhotoFrame frame = BaseNetworkable.serverEntities.Find(new NetworkableId(framePos.Value)) as PhotoFrame;
                    if (frame == null)
                    {
                        data.Value.Remove(framePos.Key);
                        continue;
                    }

                    if (!boxData.AddFrame(frame, framePos.Key))
                    {
                        data.Value.Remove(framePos.Key);
                        frame.Kill();
                    }
                }
            }

            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                OnPlayerConnected(player);
            }
        }

        private void OnNewSave(string filename)
        {
            _storedData = new StoredData();
            SaveData();
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            NextTick(() =>
            {
                if (player.IsAdmin || player.IsDeveloper)
                {
                    player.gameObject.AddComponent<AdminBoxBehavior>();
                }
            });
        }

        private void Unload()
        {
            foreach (AdminBoxBehavior adminBoxBehavior in GameObject.FindObjectsOfType<AdminBoxBehavior>())
            {
                adminBoxBehavior.DoDestroy();
            }

            SaveData();
            _ins = null;
        }
        #endregion

        #region Chat Command
        private void SignBoxChatCommand(BasePlayer player, string cmd, string[] args)
        {
            if (!HasPermission(player, UsePermission))
            {
                Chat(player, LangKeys.NoPermission);
                return;
            }

            if (args.Length == 0)
            {
                HandleHelp(player);
                return;
            }

            string subCommand = args[0];
            if (subCommand.Equals(Lang(LangKeys.AddSubCommand, player), StringComparison.InvariantCultureIgnoreCase))
            {
                HandleAdd(player, args);
            }
            else if (subCommand.Equals(Lang(LangKeys.RemoveSubCommand, player), StringComparison.InvariantCultureIgnoreCase))
            {
                HandleRemove(player, args);
            }
            else if (subCommand.Equals(Lang(LangKeys.CostSubCommand, player), StringComparison.InvariantCultureIgnoreCase))
            {
                HandleCost(player);
            }
            else if (subCommand.Equals(Lang(LangKeys.UnlockSubCommand, player), StringComparison.InvariantCultureIgnoreCase))
            {
                HandleUnlock(player, args);
            }
            else
            {
               HandleHelp(player);
            }
        }

        public void HandleHelp(BasePlayer player)
        {
            Chat(player, LangKeys.HelpText, _pluginConfig.ChatCommand, 
                Lang(LangKeys.AddSubCommand, player), 
                Lang(LangKeys.RemoveSubCommand, player), 
                Lang(LangKeys.CostSubCommand, player), 
                Lang(LangKeys.UnlockSubCommand, player));
        }

        public void HandleAdd(BasePlayer player, string[] args)
        {
            BaseCombatEntity box = Raycast<IItemContainerEntity>(player) as BaseCombatEntity;
            if (box == null)
            {
                Chat(player, LangKeys.NotLookingAt);
                return;
            }

            if (box is PhotoFrame)
            {
                FrameData data = _frames[box.net.ID];
                if (data == null)
                {
                    Chat(player, LangKeys.NotLookingAt);
                    return;
                }

                box = data.BoxData.Box;
            }
            
            ContainerData containerData = _containerPositions[box.ShortPrefabName];
            if (containerData == null)
            {
                Chat(player, LangKeys.ContainerNotAllowed);
                return;
            }

            if (args.Length < 2)
            {
                Chat(player, LangKeys.AddInvalidSyntax, _pluginConfig.ChatCommand, string.Join(", ", containerData.PositionData.Values.Select(cd => cd.DisplayName).ToArray()), Lang(LangKeys.AddSubCommand, player));
                return;
            }

            string pos = args[1].ToLower();
            if (!containerData.PositionData.ContainsKey(pos) && !pos.Equals(Lang(LangKeys.AllSubOption, player), StringComparison.InvariantCultureIgnoreCase))
            {
                Chat(player, LangKeys.InvalidAddFramePosition, string.Join(", ", containerData.PositionData.Values.Select(cd => cd.DisplayName).ToArray()));
                return;
            }

            BoxData boxData = _boxes[box.net.ID] ?? new BoxData(box);
            if (boxData.IsSlotTaken(pos))
            {
                Chat(player, LangKeys.AddSlotIsTaken, pos, string.Join(", ", boxData.GetOpenPositions(false)));
                return;
            }

            Hash<string, ulong> frameData = _storedData.FrameData[box.net.ID.Value];
            if (frameData == null)
            {
                frameData = new Hash<string, ulong>();
                _storedData.FrameData[box.net.ID.Value] = frameData;
            }

            if (pos.Equals(Lang(LangKeys.AllSubOption, player), StringComparison.InvariantCultureIgnoreCase))
            {
                if (!HasPermission(player, NoCostPermission) && !CanAfford(player, _pluginConfig.Cost, boxData.GetOpenPositions(true).Length))
                {
                    return;
                }

                foreach (KeyValuePair<string, PositionData> positionData in containerData.PositionData)
                {
                    if (!positionData.Value.IncludeAll)
                    {
                        continue;
                    }

                    frameData[positionData.Key] = AddFrame(boxData, containerData.ItemShortname, positionData.Value, positionData.Key);
                }
            }
            else
            {
                if (!HasPermission(player, NoCostPermission) && !CanAfford(player, _pluginConfig.Cost, 1))
                {
                    return;
                }

                PositionData framePos = containerData.PositionData[pos];
                frameData[pos] = AddFrame(boxData, containerData.ItemShortname, framePos, pos);
            }

            Chat(player, LangKeys.AddSuccess, pos);
            SaveData();
        }

        public ulong AddFrame(BoxData boxData, string prefabName, PositionData framePos, string pos)
        {
            PhotoFrame frame = GameManager.server.CreateEntity(prefabName, boxData.Box.transform.TransformPoint(framePos.Offset), boxData.Box.transform.rotation * Quaternion.Euler(framePos.Rotation)) as PhotoFrame;
            frame.Spawn();
            boxData.AddFrame(frame, pos);
            return frame.net.ID.Value;
        }

        public void HandleRemove(BasePlayer player, string[] args)
        {
            BoxData boxData;
            FrameData frameData;

            if (!GetFrameBox(player, out boxData, out frameData))
            {
                return;
            }

            string[] framesToRemove = null;
            if (args.Length == 1)
            {
                if (frameData == null)
                {
                    Chat(player, LangKeys.NotLookingAtFrame);
                    return;
                }
                
                framesToRemove = new [] {frameData.Position};
            }
            else if(args.Length > 1)
            {
                framesToRemove = ParseFramePositions(player, boxData, args[1].ToLower());
            }

            if (framesToRemove == null)
            {
                return;
            }

            int removed = 0;
            foreach (string pos in framesToRemove)
            {
                if (boxData.RemoveFrame(pos, true))
                {
                    removed++;
                }
            }

            if (removed == 0)
            {
                Chat(player, LangKeys.NoFrameInPosition, args[1].ToLower());
                return;
            }
            
            if (_pluginConfig.RefundOnRemove)
            {
                foreach (KeyValuePair<string, int> cost in _pluginConfig.Cost)
                {
                    int amount = Mathf.FloorToInt(cost.Value * _pluginConfig.RefundPercentage * removed);
                    if (amount <= 0)
                    {
                        continue;
                    }

                    Item item = ItemManager.CreateByName(cost.Key, amount);
                    player.GiveItem(item);
                }
            }
            
            Chat(player, LangKeys.RemoveSuccess, args[1]);
            SaveData();
        }

        public void HandleCost(BasePlayer player)
        {
            StringBuilder sb = new StringBuilder(Lang(LangKeys.CostPre, player));

            foreach (KeyValuePair<string, int> item in _pluginConfig.Cost)
            {
                sb.AppendLine(Lang(LangKeys.Cost, player, ItemManager.FindItemDefinition(item.Key)?.displayName.translated, item.Value));
            }

            Chat(player, sb.ToString());
        }

        public void HandleUnlock(BasePlayer player, string[] args)
        {
            BuildingPrivlidge priv = player.GetBuildingPrivilege();
            if (priv != null && !priv.IsAuthed(player))
            {
                Chat(player, LangKeys.UnlockBuildingBlocked);
                return;
            }

            BoxData boxData;
            FrameData frameData;

            if (!GetFrameBox(player, out boxData, out frameData))
            {
                return;
            }

            string[] framesToUnlock = null;
            if (args.Length == 1)
            {
                if (frameData == null)
                {
                    Chat(player, LangKeys.NotLookingAtFrame);
                    return;
                }
                
                framesToUnlock = new [] {frameData.Position};
            }
            else if(args.Length > 1)
            {
                framesToUnlock = ParseFramePositions(player, boxData, args[1].ToLower());
            }

            if (framesToUnlock == null)
            {
                return;
            }

            int unlocked = 0;
            foreach (string frame in framesToUnlock)
            {
                if (boxData.GetFrame(frame)?.Unlock(player) ?? false)
                {
                    unlocked++;
                }
            }

            if (unlocked == 0)
            {
                Chat(player, LangKeys.NoUnlockPermission);
                return;
            }
            

            Chat(player, LangKeys.UnlockSuccess);
        }

        private bool GetFrameBox(BasePlayer player, out BoxData boxData, out FrameData frameData)
        {
            boxData = null;
            frameData = null;

            BaseCombatEntity box = Raycast<IItemContainerEntity>(player) as BaseCombatEntity;
            if (box == null)
            {
                Chat(player, LangKeys.NotLookingAt);
                return false;
            }

            if (box is PhotoFrame)
            {
                frameData = _frames[box.net.ID];
                if (frameData == null)
                {
                    Chat(player, LangKeys.NotLookingAtFrameBoxFrame);
                    return false;
                }

                boxData = frameData.BoxData;
            }
            else
            {
                boxData = _boxes[box.net.ID];
                if (boxData == null)
                {
                    Chat(player, LangKeys.NotLookingAtFrameBox);
                    return false;
                }
            }

            return true;
        }

        public string[] ParseFramePositions(BasePlayer player, BoxData box, string pos)
        {
            if (pos.Equals(Lang(LangKeys.AllSubOption, player)))
            {
                return box.GetTakenFramePositions();
            }
            
            FrameData frameData = box.GetFrame(pos);
            if (frameData == null)
            {
                Chat(player, LangKeys.NoFrameInPosition, pos);
                return null;
            }

            return new []{pos};
        }
        #endregion

        #region Hooks
        private object CanLootEntity(BasePlayer player, PhotoFrame frame)
        {
            if (frame == null || !frame.IsLocked())
            {
                return null;
            }

            IItemContainerEntity box = _frames[frame.net.ID]?.BoxData.Box as IItemContainerEntity;
            if (box == null)
            {
                return null;
            }

            box.PlayerOpenLoot(player);
            return true;
        }

        private void OnEntityKill(BoxStorage box)
        {
            if (box == null)
            {
                PrintError($"Box is null???\n{Environment.StackTrace}");
            }
            
            _boxes[box.net.ID]?.OnKilled();
        }

        private void OnEntityKill(PhotoFrame frame)
        {
            if (frame == null)
            {
                PrintError($"frame is null???\n{Environment.StackTrace}");
            }
            
            _frames[frame.net.ID]?.OnKilled();
        }

        private void OnSignLocked(PhotoFrame frame, BasePlayer player)
        {
            FrameData frameData = _frames[frame.net.ID];
            if (frameData == null)
            {
                return;
            }

            frame.OwnerID = 0;
        }
        #endregion

        #region Sign Artist Hooks
        private object GetImageRotation(PhotoFrame frame)
        {
            if (!_frames.ContainsKey(frame.net.ID))
            {
                return null;
            }

            return RotateFlipType.Rotate270FlipNone;
        }
        #endregion

        #region Magic Remove Hooks
        private Hash<string, int> GetRemoveAdditionalRefund(BoxStorage entity, Hash<string, int> refund)
        {
            BoxData box = _boxes[entity.net.ID];
            if (box == null)
            {
                return null;
            }

            int frameCount = box.GetFrameCount();
            foreach (KeyValuePair<string, int> item in _pluginConfig.Cost)
            {
                int amount = Mathf.FloorToInt(item.Value * frameCount * _pluginConfig.RefundPercentage);
                if (amount == 0)
                {
                    continue;
                }

                refund[item.Key] += amount;
            }

            return refund;
        }
        #endregion

        #region Handle Paying
        public bool CanAfford(BasePlayer player, Hash<string, int> cost, int multiplier)
        {
            bool canAfford = true;
            StringBuilder missingItems = new StringBuilder();
            foreach (KeyValuePair<string, int> item in cost)
            {
                ItemDefinition def = ItemManager.FindItemDefinition(item.Key);
                int amount = player.inventory.GetAmount(def.itemid);
                if (amount < item.Value * multiplier)
                {
                    string itemName = ItemManager.FindItemDefinition(item.Key).displayName.english;
                    missingItems.AppendLine(Lang(LangKeys.MissingItem, player, itemName,
                        item.Value * multiplier - amount));
                    canAfford = false;
                }
            }

            if (!canAfford)
            {
                Chat(player, Lang(LangKeys.MissingMessage, player, missingItems));
                return false;
            }

            TakeCost(player, cost, multiplier);

            return true;
        }

        public void TakeCost(BasePlayer player, Hash<string, int> cost, int multiplier)
        {
            List<Item> items = Pool.GetList<Item>();
            foreach (KeyValuePair<string, int> item in cost)
            {
                ItemDefinition def = ItemManager.FindItemDefinition(item.Key);
                player.inventory.Take(items, def.itemid, item.Value * multiplier);
                player.Command("note.inv", def.itemid, -item.Value * multiplier);
            }

            foreach (Item item in items)
            {
                item.Remove();
            }

            Pool.FreeList(ref items);
        }
        #endregion

        #region Helper Methods
        public string GetShortPrefabName(string shortname)
        {
            ItemDefinition def = ItemManager.FindItemDefinition(shortname);
            if (def == null)
            {
                PrintWarning($"{shortname} is not a valid item shortname!");
                return null;
            }

            string prefabName = def.GetComponent<ItemModDeployable>()?.entityPrefab.Get().GetComponent<BaseEntity>().ShortPrefabName;
            if (string.IsNullOrEmpty(prefabName))
            {
                PrintWarning($"{shortname} does not contain a deployable item and cannot be used");
                return null;
            }

            return prefabName;
        }

        public string GetPrefabName(string shortname)
        {
            ItemDefinition def = ItemManager.FindItemDefinition(shortname);
            if (def == null)
            {
                PrintWarning($"{shortname} is not a valid item shortname!");
                return null;
            }

            string prefabName = def.GetComponent<ItemModDeployable>()?.entityPrefab.Get().GetComponent<BaseEntity>().PrefabName;
            if (string.IsNullOrEmpty(prefabName))
            {
                PrintWarning($"{shortname} does not contain a deployable item and cannot be used");
                return null;
            }

            return prefabName;
        }

        public T Raycast<T>(BasePlayer player) where T : class
        {
            RaycastHit[] hits = Physics.RaycastAll(player.eyes.HeadRay(), _pluginConfig.MaxDistance);
            GamePhysics.Sort(hits);
            foreach (RaycastHit hit in hits)
            {
                BaseEntity entity = hit.GetEntity();
                if (entity == null)
                {
                    continue;
                }

                T type = entity as T;
                if (type == null)
                {
                    continue;
                }

                if (Vector3.Distance(player.eyes.position, entity.transform.position) > _pluginConfig.MaxDistance + 3)
                {
                    continue;
                }

                return type;
            }

            return default(T);
        }

        public void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, _storedData);

        public void Chat(BasePlayer player, string key, params object[] args) =>
            PrintToChat(player, Lang(LangKeys.Chat, player, Lang(key, player, args)));

        public string Lang(string key, BasePlayer player = null, params object[] args)
        {
            try
            {
                return string.Format(lang.GetMessage(key, this, player?.UserIDString), args);
            }
            catch (Exception ex)
            {
                PrintError($"Lang Key '{key}' threw exception:\n{ex}");
                throw;
            }
        }

        public bool HasPermission(BasePlayer player, string perm) =>
            permission.UserHasPermission(player.UserIDString, perm);
        #endregion

        #region Data Classes
        public class FrameData
        {
            public PhotoFrame Frame { get; }
            public BoxData BoxData { get; }
            public string Position { get; }

            public FrameData(PhotoFrame frame, BoxData boxData, string position)
            {
                Frame = frame;
                BoxData = boxData;
                Position = position;
                DestroyGroundWatch(Frame);
                _ins._frames[frame.net.ID] = this;
            }

            public bool Unlock(BasePlayer player)
            {
                if (Frame.OwnerID != 0 && !Frame.CanUnlockSign(player))
                {
                    return false;
                }

                Frame.SetFlag(BaseEntity.Flags.Locked, false);
                Frame.SendNetworkUpdate();
                return true;
            }

            private void DestroyGroundWatch(BaseEntity entity)
            {
                DestroyOnGroundMissing missing = entity.GetComponent<DestroyOnGroundMissing>();
                if (missing != null)
                {
                    GameObject.Destroy(missing);
                }

                GroundWatch watch = entity.GetComponent<GroundWatch>();
                if (watch != null)
                {
                    GameObject.Destroy(watch);
                }
            }

            public void OnKilled()
            {
                BoxData.RemoveFrame(Position, false);
            }

            public void RemoveFrame(bool kill)
            {
                _ins._frames.Remove(Frame.net.ID);
                _ins._storedData.FrameData.Remove(Frame.net.ID.Value);
                if (kill)
                {
                    Frame.Kill();
                }
            }
        }

        public class BoxData
        {
            public BaseCombatEntity Box { get; }
            private Hash<string, FrameData> BoxFrames { get; }

            public BoxData(BaseCombatEntity box)
            {
                Box = box;
                BoxFrames = new Hash<string, FrameData>();
                _ins._boxes[Box.net.ID] = this;
            }

            public FrameData GetFrame(string position)
            {
                return BoxFrames[position];
            }

            public bool AddFrame(PhotoFrame frame, string position)
            {
                if (IsSlotTaken(position))
                {
                    return false;
                }

                BoxFrames[position] = new FrameData(frame, this, position);
                return true;
            }

            public bool RemoveFrame(string position, bool kill)
            {
                FrameData frame = BoxFrames[position];
                if (frame == null)
                {
                    return false;
                }

                frame.RemoveFrame(kill);
                BoxFrames.Remove(position);
                
                Hash<string, ulong> data = _ins._storedData.FrameData[Box.net.ID.Value];
                if (data != null)
                {
                    data.Remove(position);
                    if (data.Count == 0)
                    {
                        _ins._storedData.FrameData.Remove(Box.net.ID.Value);
                        _ins._boxes.Remove(Box.net.ID);
                    }
                }
                
                return true;
            }

            public bool IsSlotTaken(string position)
            {
                return BoxFrames.ContainsKey(position);
            }

            public string[] GetOpenPositions(bool allOnly)
            {
                return _ins._containerPositions[Box.ShortPrefabName].PositionData.Where(fp => !BoxFrames.ContainsKey(fp.Key) && (!allOnly || fp.Value.IncludeAll)).Select(fp => fp.Value.DisplayName).ToArray();
            }

            public string[] GetTakenFramePositions()
            {
                return BoxFrames.Keys.ToArray();
            }

            public int GetFrameCount()
            {
                return BoxFrames.Count;
            }

            public void OnKilled()
            {
                foreach (string frame in BoxFrames.Keys.ToList())
                {
                    RemoveFrame(frame, true);
                }

                _ins._boxes.Remove(Box.net.ID);
                _ins._storedData.FrameData.Remove(Box.net.ID.Value);
            }
        }
        #endregion

        #region Admin Behavior
        //Players with Admin or Developer flag can always edit signs.We use this to open box for them.public class AdminBoxBehavior : FacepunchBehaviour
        {
            private BasePlayer Player { get; set; }
            private bool IsDown { get; set; }

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

            private void Update()
            {
                if (Player.inventory.loot.IsLooting())
                {
                    return;
                }

                bool isDown = Player.serverInput.IsDown(BUTTON.USE);
                if (isDown == IsDown)
                {
                    return;
                }

                IsDown = isDown;
                if (!IsDown)
                {
                    return;
                }

                PhotoFrame frame = _ins.Raycast<PhotoFrame>(Player);
                if (frame == null || !frame.IsLocked())
                {
                    return;
                }

                FrameData frameData = _ins._frames[frame.net.ID];
                if (frameData == null)
                {
                    return;
                }

                StartCoroutine(OpenBox(frame, frameData.BoxData.Box as IItemContainerEntity));
            }

            //Needed because we need to be sure the sign is destroyed on the client before we try to open the box
            private IEnumerator OpenBox(PhotoFrame frame, IItemContainerEntity box)
            {
                frame.DestroyOnClient(Player.Connection);
                yield return null;
                yield return null;

                box?.PlayerOpenLoot(Player);

                yield return new WaitForSeconds(0.05f);

                frame.SendNetworkUpdate();
            }

            public void DoDestroy()
            {
                Destroy(this);
            }
        }
        #endregion

        #region Classes
        public class PluginConfig
        {
            [DefaultValue("fb")]
            [JsonProperty(PropertyName = "Chat Command")]
            public string ChatCommand { get; set; }

            [DefaultValue(true)]
            [JsonProperty(PropertyName = "Refund on remove")]
            public bool RefundOnRemove { get; set; }

            [DefaultValue(1f)]
            [JsonProperty(PropertyName = "Refund % (0 none - 1 max)")]
            public float RefundPercentage { get; set; }

            [DefaultValue(5f)]
            [JsonProperty(PropertyName = "Max distance (Meters)")]
            public float MaxDistance { get; set; }

            [JsonProperty(PropertyName = "Cost")]
            public Hash<string, int> Cost { get; set; }

            [JsonProperty(PropertyName = "Sign Positions")]
            public Hash<string, ContainerData> SignPositions { get; set; }
        }

        public class StoredData
        {
            public Hash<ulong, Hash<string, ulong>> FrameData = new Hash<ulong, Hash<string, ulong>>();
        }

        public class ContainerData
        {
            [JsonProperty(PropertyName = "Frame Item Shortname")]
            public string ItemShortname { get; set; }

            [JsonProperty(PropertyName = "Frame Positions")]
            public Hash<string, PositionData> PositionData { get; set; }
        }

        public class PositionData
        {
            [JsonConverter(typeof(Vector3Converter))]
            [JsonProperty(PropertyName = "Frame Position Offset")]
            public Vector3 Offset { get; set; }

            [JsonConverter(typeof(Vector3Converter))]
            [JsonProperty(PropertyName = "Frame Position Rotation")]
            public Vector3 Rotation { get; set; }

            [JsonProperty(PropertyName = "Include Position In All Option")]
            public bool IncludeAll { get; set; }

            [JsonIgnore]
            public string DisplayName { get; set; }
        }

        public class LangKeys
        {
            public const string Chat = nameof(Chat);
            public const string NoPermission = nameof(NoPermission);
            public const string HelpText = nameof(HelpText) + "_V1";
            public const string MissingItem = nameof(MissingItem);
            public const string MissingMessage = nameof(MissingMessage);
            public const string CostPre = nameof(CostPre) + "_V1";
            public const string Cost = nameof(Cost);
            public const string AddInvalidSyntax = nameof(AddInvalidSyntax) + "_V1";
            public const string InvalidAddFramePosition = nameof(InvalidAddFramePosition) + "_V1";
            public const string NotLookingAt = nameof(NotLookingAt);
            public const string AddSlotIsTaken = nameof(AddSlotIsTaken);
            public const string AddSuccess = nameof(AddSuccess);
            public const string RemoveSuccess = nameof(RemoveSuccess);
            public const string UnlockBuildingBlocked = nameof(UnlockBuildingBlocked);
            public const string UnlockSuccess = nameof(UnlockSuccess);
            public const string NotLookingAtFrame = nameof(NotLookingAtFrame);
            public const string NotLookingAtFrameBoxFrame = nameof(NotLookingAtFrameBoxFrame);
            public const string NotLookingAtFrameBox = nameof(NotLookingAtFrameBox);
            public const string NoFrameInPosition = nameof(NoFrameInPosition);
            public const string ContainerNotAllowed = nameof(ContainerNotAllowed) + "_V1";
            public const string NoUnlockPermission = nameof(NoUnlockPermission);
            public const string AddSubCommand = nameof(AddSubCommand);
            public const string RemoveSubCommand = nameof(RemoveSubCommand);
            public const string CostSubCommand = nameof(CostSubCommand);
            public const string UnlockSubCommand = nameof(UnlockSubCommand);
            public const string AllSubOption = nameof(AllSubOption);
        }
        #endregion

        #region JSON Converters
        public class Vector3Converter : JsonConverter
        {
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                Vector3 pos = (Vector3) value;
                writer.WriteValue($"{pos.x} {pos.y} {pos.z}");
            }

            public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
                JsonSerializer serializer)
            {
                string[] values = reader.Value.ToString().Trim().Split(' ');
                return new Vector3(Convert.ToSingle(values[0]), Convert.ToSingle(values[1]),
                    Convert.ToSingle(values[2]));
            }

            public override bool CanConvert(Type objectType)
            {
                return objectType == typeof(Vector3);
            }
        }
        #endregion
    }
}

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