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

FREE ChaosPlugin : 3.0.10 3.0.10

Нет прав для скачивания
C#:
using HarmonyLib;
using System;
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
using ProtoBuf;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using UnityEngine.UI;

namespace Oxide.Plugins
{
    #region Compatibility Layer
    public class ChaosPlugin : RustPlugin 
    {
        public BaseConfigData ConfigurationData { get; set; }
        protected virtual void OnConfigurationUpdated(VersionNumber oldVersion) {}
        protected virtual ConfigurationFile OnLoadConfig(ref ConfigurationFile configurationFile) => null;
        protected virtual T GenerateDefaultConfiguration<T>() where T : class, new() => null;
        protected virtual string GetString(string key, BasePlayer player) => lang.GetMessage(key, this, player?.UserIDString);
        public NoEscapeWrapper NoEscape { get; } = new NoEscapeWrapper();

        public static string GetColor(string hex, float alpha)
        {
            if (string.IsNullOrEmpty(hex)) return "1 1 1 1";
            if (hex.StartsWith("#")) hex = hex.Substring(1);
            if (hex.Length == 6)
            {
                int r = int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
                int g = int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
                int b = int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
                string rStr = ((float)r / 255).ToString(System.Globalization.CultureInfo.InvariantCulture);
                string gStr = ((float)g / 255).ToString(System.Globalization.CultureInfo.InvariantCulture);
                string bStr = ((float)b / 255).ToString(System.Globalization.CultureInfo.InvariantCulture);
                string aStr = alpha.ToString(System.Globalization.CultureInfo.InvariantCulture);
                return $"{rStr} {gStr} {bStr} {aStr}";
            }
            return "1 1 1 1";
        }
    }

    public class NoEscapeWrapper
    {
        private Plugin _noEscape => Oxide.Core.Interface.Oxide.RootPluginManager.GetPlugin("NoEscape");
        public bool IsLoaded => _noEscape != null;
        public bool IsRaidBlocked(BasePlayer player) => (bool)(_noEscape?.Call("IsRaidBlocked", player) ?? false);
        public bool IsCombatBlocked(BasePlayer player) => (bool)(_noEscape?.Call("IsCombatBlocked", player) ?? false);
    }

    public class ConfigurationFile {}
    public class ConfigurationFile<T> : ConfigurationFile 
    {
        public ConfigurationFile(DynamicConfigFile config) {}
    }

    public interface IChaosUIComponent {}

    public static class ChaosUI
    {
        public static void Show(BasePlayer player, BaseContainer root)
        {
            if (player == null || root == null) return;
            CuiHelper.DestroyUi(player, root.Name);
            CuiHelper.AddUi(player, root.Elements);
        }

        public static void Destroy(BasePlayer player, string name)
        {
            if (player == null || string.IsNullOrEmpty(name)) return;
            CuiHelper.DestroyUi(player, name);
        }
    }

    public class Style
    {
        public Color ImageColor { get; set; }
        public string Material { get; set; }
        public string Sprite { get; set; }
        public UnityEngine.UI.Image.Type ImageType { get; set; }
        public int FontSize { get; set; }
        public TextAnchor Alignment { get; set; }
        public string Font { get; set; }
        public VerticalWrapMode WrapMode { get; set; }
    }

    public class Color
    {
        public string Hex { get; set; }
        public float Alpha { get; set; }
        public Color(string hex, float alpha) { Hex = hex; Alpha = alpha; }
        public static Color Clear => new Color("000000", 0.005f);
        public string ToCuiColor() => ChaosPlugin.GetColor(Hex, Alpha);
    }

    public class Anchor
    {
        public string Min { get; set; }
        public string Max { get; set; }
        public Anchor(string min, string max) { Min = min; Max = max; }
        public static Anchor Center => new Anchor("0.5 0.5", "0.5 0.5");
        public static Anchor CenterLeft => new Anchor("0 0.5", "0 0.5");
        public static Anchor CenterRight => new Anchor("1 0.5", "1 0.5");
        public static Anchor TopStretch => new Anchor("0 1", "1 1");
        public static Anchor FullStretch => new Anchor("0 0", "1 1");
    }

    public class Offset
    {
        public string Min { get; set; }
        public string Max { get; set; }
        public Offset(float xMin, float yMin, float xMax, float yMax) { Min = $"{xMin} {yMin}"; Max = $"{xMax} {yMax}"; }
        public static Offset zero => new Offset(0, 0, 0, 0);
    }

    public static class Layer { public const string Overall = "Overlay"; }
    public static class Materials { public const string BackgroundBlur = "assets/content/ui/uibackgroundblur.mat"; }
    public static class Sprites { public const string Background_Rounded = "assets/content/ui/ui.background.tile.psd"; }
    public static class Icon { 
        public const string Download = "assets/icons/download.png"; 
        public const string Close = "assets/icons/close.png"; 
    }
    public static class Font { public const string PermanentMarker = "permanentmarker.ttf"; }

    public class BaseContainer
    {
        public string Name { get; set; }
        public CuiElementContainer Elements { get; set; }
        public CuiElement CurrentElement { get; set; }

        public BaseContainer(string name, string parent, Anchor anchor, Offset offset, CuiElementContainer container = null)
        {
            Name = name;
            Elements = container ?? new CuiElementContainer();
            CurrentElement = new CuiElement
            {
                Name = name,
                Parent = parent,
                FadeOut = 0f,
                Components = {
                    new CuiRectTransformComponent { AnchorMin = anchor.Min, AnchorMax = anchor.Max, OffsetMin = offset.Min, OffsetMax = offset.Max }
                }
            };
            
            // Check if this is the root of the menu
            if (container == null)
            {
                Elements.Add(CurrentElement);
            }
            else
            {
                // For children, we still add them to the main container
                Elements.Add(CurrentElement);
            }
        }

        public static BaseContainer Create(string name, string parent, Anchor anchor, Offset offset) => new BaseContainer(name, parent, anchor, offset);
        public static BaseContainer Create(BaseContainer parent, Anchor anchor, Offset offset) => new BaseContainer(CuiHelper.GetGuid(), parent.Name, anchor, offset, parent.Elements);
        
        protected T GetComponent<T>() where T : ICuiComponent
        {
            foreach (var comp in CurrentElement.Components)
                if (comp is T t) return t;
            return default(T);
        }
        
        public BaseContainer WithChildren(Action<BaseContainer> action) { action(this); return this; }
        public BaseContainer NeedsCursor() { 
            var comp = new CuiNeedsCursorComponent();
            CurrentElement.Components.Add(comp); 
            return this; 
        }
        public BaseContainer NeedsKeyboard() { 
            var comp = new CuiNeedsKeyboardComponent();
            CurrentElement.Components.Add(comp); 
            return this; 
        }
        public BaseContainer DestroyExisting() { return this; }
        public string ToJson() { return Elements.ToJson(); }
        
        public BaseContainer WithOutline(OutlineComponent outline) { 
            CurrentElement.Components.Add(new CuiOutlineComponent { Color = outline.Color.ToCuiColor(), Distance = "1.0 -1.0", UseGraphicAlpha = true });
            return this; 
        }
        
        public BaseContainer WithColor(Color color) { 
            var img = GetComponent<CuiImageComponent>(); if (img != null) img.Color = color.ToCuiColor();
            var text = GetComponent<CuiTextComponent>(); if (text != null) text.Color = color.ToCuiColor();
            var btn = GetComponent<CuiButtonComponent>(); if (btn != null) btn.Color = color.ToCuiColor();
            return this; 
        }
        
        public BaseContainer WithSprite(string sprite) { 
            var img = GetComponent<CuiImageComponent>(); if (img != null) img.Sprite = sprite;
            return this; 
        }
        
        public BaseContainer WithMaterial(string mat) { 
            var img = GetComponent<CuiImageComponent>(); if (img != null) img.Material = mat;
            return this; 
        }
        
        public BaseContainer WithImageType(UnityEngine.UI.Image.Type type) { 
            var img = GetComponent<CuiImageComponent>(); if (img != null) img.ImageType = type;
            return this; 
        }
        
        public BaseContainer WithText(string text) { 
            var txt = GetComponent<CuiTextComponent>(); if (txt != null) txt.Text = text;
            var input = GetComponent<CuiInputFieldComponent>(); if (input != null) input.Text = text;
            return this; 
        }
        
        public BaseContainer WithAlignment(TextAnchor align) { 
            var txt = GetComponent<CuiTextComponent>(); if (txt != null) txt.Align = align;
            var input = GetComponent<CuiInputFieldComponent>(); if (input != null) input.Align = align;
            return this; 
        }
        
        public BaseContainer WithCharacterLimit(int limit) { 
            var input = GetComponent<CuiInputFieldComponent>(); if (input != null) input.CharsLimit = limit;
            return this; 
        }
        public BaseContainer WithCallback(CommandCallbackHandler handler, Action<ConsoleSystem.Arg> action, string name) { 
            name = name.Replace(".", "").Replace(" ", "");
            var fullCmd = $"aclock_cb {name}";
            var btn = GetComponent<CuiButtonComponent>(); if (btn != null) btn.Command = fullCmd;
            var input = GetComponent<CuiInputFieldComponent>(); if (input != null) input.Command = fullCmd + " ";
            handler?.Register(name, action);
            return this; 
        }

        public BaseContainer WithStyle(Style style) {
            if (style == null) return this;
            if (style.ImageColor != null) WithColor(style.ImageColor);
            if (style.Material != null) WithMaterial(style.Material);
            if (style.Sprite != null) WithSprite(style.Sprite);
            if (style.Font != null) {
                var txt = GetComponent<CuiTextComponent>(); if (txt != null) txt.Font = style.Font;
                var input = GetComponent<CuiInputFieldComponent>(); if (input != null) input.Font = style.Font;
            }
            if (style.FontSize > 0) {
                var txt = GetComponent<CuiTextComponent>(); if (txt != null) txt.FontSize = style.FontSize;
                var input = GetComponent<CuiInputFieldComponent>(); if (input != null) input.FontSize = style.FontSize;
            }
            WithAlignment(style.Alignment);
            return this;
        }
    }

    public class ImageContainer : BaseContainer
    {
        public ImageContainer(string name, string parent, Anchor anchor, Offset offset, CuiElementContainer container = null) : base(name, parent, anchor, offset, container) {
            CurrentElement.Components.Insert(0, new CuiImageComponent { Color = "1 1 1 1" });
        }
        public static new ImageContainer Create(string name, string parent, Anchor anchor, Offset offset) => new ImageContainer(name, parent, anchor, offset);
        public static new ImageContainer Create(BaseContainer parent, Anchor anchor, Offset offset) => new ImageContainer(CuiHelper.GetGuid(), parent.Name, anchor, offset, parent.Elements);
    }

    public class TextContainer : BaseContainer
    {
        public TextContainer(string name, string parent, Anchor anchor, Offset offset, CuiElementContainer container = null) : base(name, parent, anchor, offset, container) {
            CurrentElement.Components.Insert(0, new CuiTextComponent { Text = "", Color = "1 1 1 1", FontSize = 14, Align = TextAnchor.MiddleCenter });
        }
        public static new TextContainer Create(BaseContainer parent, Anchor anchor, Offset offset) => new TextContainer(CuiHelper.GetGuid(), parent.Name, anchor, offset, parent.Elements);
    }

    public class ButtonContainer : BaseContainer
    {
        public ButtonContainer(string name, string parent, Anchor anchor, Offset offset, CuiElementContainer container = null) : base(name, parent, anchor, offset, container) {
            CurrentElement.Components.Insert(0, new CuiButtonComponent { Color = "1 1 1 1" });
        }
        public static new ButtonContainer Create(BaseContainer parent, Anchor anchor, Offset offset) => new ButtonContainer(CuiHelper.GetGuid(), parent.Name, anchor, offset, parent.Elements);
    }

    public class InputFieldContainer : BaseContainer
    {
        public InputFieldContainer(string name, string parent, Anchor anchor, Offset offset, CuiElementContainer container = null) : base(name, parent, anchor, offset, container) {
            CurrentElement.Components.Insert(0, new CuiInputFieldComponent { Text = "", Color = "1 1 1 1", FontSize = 14, Align = TextAnchor.MiddleLeft });
        }
        public static new InputFieldContainer Create(BaseContainer parent, Anchor anchor, Offset offset) => new InputFieldContainer(CuiHelper.GetGuid(), parent.Name, anchor, offset, parent.Elements);
    }

    public class OutlineComponent
    {
        public Color Color;
        public OutlineComponent(Color color) { Color = color; }
    }

    public class CommandCallbackHandler
    {
        public Dictionary<string, Action<ConsoleSystem.Arg>> Callbacks = new Dictionary<string, Action<ConsoleSystem.Arg>>();
        private AutoCodeLock _plugin;
        public CommandCallbackHandler(AutoCodeLock plugin) { _plugin = plugin; }
        public void Register(string name, Action<ConsoleSystem.Arg> action)
        {
            Callbacks[name] = action;
        }
    }

    public static class BasePlayerExtensions
    {
        public static bool HasPermission(this BasePlayer player, string perm)
        {
            if (player == null || string.IsNullOrEmpty(perm)) return false;
            return Oxide.Core.Interface.Oxide.GetLibrary<Permission>().UserHasPermission(player.userID.ToString(), perm);
        }
    }


    public class BaseConfigData { public VersionNumber Version; }
    #endregion

    [Info("AutoCodeLock", "k1lly0u", "3.0.10")]
    [Description("Codelock & door automation tools")]
    public class AutoCodeLock : ChaosPlugin
    {
        public static AutoCodeLock Instance { get; private set; }

        public AutoCodeLock()
        {
            Instance = this;
        }

        #region Fields
        private const string PERMISSION_DEPLOY_DOOR = "autocodelock.deploydoor";    
        private const string PERMISSION_DEPLOY_BOX = "autocodelock.deploybox";    
        private const string PERMISSION_DEPLOY_LOCKER = "autocodelock.deploylocker";    
        private const string PERMISSION_DEPLOY_CUPBOARD = "autocodelock.deploycup";    
        private const string PERMISSION_AUTO_LOCK = "autocodelock.autolock";    
        private const string PERMISSION_NO_LOCK_NEEDED = "autocodelock.nolockneed";    
        private const string PERMISSION_DOOR_CLOSER = "autocodelock.doorcloser";    
        
        private static readonly DateTime Epoch = new DateTime(1970, 1, 1);
        #endregion

        #region Oxide Hooks
        private Harmony _harmony;

        private void Init()
        {
            try
            {
                _harmony = new Harmony("com.chaos.autocodelock");
                _harmony.PatchAll(System.Reflection.Assembly.GetExecutingAssembly());
            }
            catch (Exception ex)
            {
                Puts($"Failed to apply Harmony patches: {ex}");
            }
            
            Puts("AutoCodeLock: Init started...");
            permission.RegisterPermission(PERMISSION_DEPLOY_DOOR, this);
            permission.RegisterPermission(PERMISSION_DEPLOY_BOX, this);
            permission.RegisterPermission(PERMISSION_DEPLOY_LOCKER, this);
            permission.RegisterPermission(PERMISSION_DEPLOY_CUPBOARD, this);
            permission.RegisterPermission(PERMISSION_AUTO_LOCK, this);
            permission.RegisterPermission(PERMISSION_NO_LOCK_NEEDED, this);
            permission.RegisterPermission(PERMISSION_DOOR_CLOSER, this);
        }

        private void Loaded()
        {
            LoadConfig();
            
            if (Configuration == null)
            {
                Interface.Oxide.LogError("Configuration failed to load! Plugin features will not work correctly.");
                return;
            }

            string cmdMain = string.IsNullOrEmpty(Configuration.Command) ? "codelock" : Configuration.Command;
            string cmdCloser = string.IsNullOrEmpty(Configuration.CloserCommand) ? "closer" : Configuration.CloserCommand;

            cmd.AddChatCommand(cmdMain, this, nameof(CodelockCommand));
            cmd.AddChatCommand(cmdCloser, this, nameof(AutoDoorCommand));
            
            SetupUIComponents();
            LoadData();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                ConfigData data = Config.ReadObject<ConfigData>();
                if (data == null)
                {
                    LoadDefaultConfig();
                    return;
                }
                ConfigurationData = data;
            }
            catch
            {
                LoadDefaultConfig();
            }

            // Ensure nested objects are initialized to prevent NREs
            if (Configuration.Other == null) Configuration.Other = new ConfigData.OtherOptions();
            if (Configuration.Delay == null) Configuration.Delay = new ConfigData.DelayOptions();
            if (Configuration.Defaults == null) Configuration.Defaults = new ConfigData.DefaultSettings();
            if (Configuration.Data == null) Configuration.Data = new ConfigData.DataManagement();
            if (Configuration.Colors == null) Configuration.Colors = new ConfigData.UIColors();

            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            Puts("Generating new configuration file");
            ConfigurationData = GenerateDefaultConfiguration<BaseConfigData>();
        }

        protected override void SaveConfig()
        {
            if (Configuration != null)
                Config.WriteObject(Configuration, true);
        }

        private void OnServerInitialized()
        {
            if (Configuration == null || Configuration.Data == null)
            {
                Interface.Oxide.LogError("Configuration is not properly initialized!");
                return;
            }

            FindRegisterEntities();
            
            if (Configuration.Data.PurgeAfter > 0)
                PurgeOldData();
            
            foreach (BasePlayer player in BasePlayer.activePlayerList)
                OnPlayerConnected(player);

            PlayerEntities.EnqueueUpdateDoorCloserDelays();
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (HasAnyPermission(player))
            {
                StoredData.PlayerData playerData = storedData.FindPlayerData(player.userID);
                if (playerData == null)
                    playerData = storedData.SetupPlayer(player.userID, Configuration);
                
                playerData.UpdateDelays(Configuration.Delay);
                playerData.SetLastOnline(UnixTimeStampUtc());
            }
        }

        private void OnPlayerDisconnected(BasePlayer player)
        {
            StoredData.PlayerData playerData = storedData.FindPlayerData(player.userID);
            playerData?.SetLastOnline(UnixTimeStampUtc());
        }
        
        private void OnEntitySpawned(CodeLock codeLock) => NextTick(() =>
        {
            if (!codeLock)
                return;

            PlayerEntities.GetOrCreate(codeLock.OwnerID)?.AddEntity(codeLock);
        });
        
        private void OnEntitySpawned(DoorCloser doorCloser) => NextTick(() =>
        {
            if (!doorCloser)
                return;

            PlayerEntities.GetOrCreate(doorCloser.OwnerID)?.AddEntity(doorCloser);
        });

        private void OnEntityKill(CodeLock codeLock)
        {
            if (!codeLock)
                return;

            PlayerEntities.Get(codeLock.OwnerID)?.RemoveEntity(codeLock, true);
        }
        
        private void OnEntityKill(DoorCloser doorCloser)
        {
            if (!doorCloser)
                return;

            PlayerEntities.Get(doorCloser.OwnerID)?.RemoveEntity(doorCloser);
        }
        
        private void OnItemDeployed(Deployer deployer, BaseEntity entity)
        {
            if (!deployer || !entity || entity.OwnerID == 0UL)
                return;

            if (deployer.GetDeployable().slot != BaseEntity.Slot.Lock || entity.GetSlot(BaseEntity.Slot.Lock) is not CodeLock)
                return;
            
            BasePlayer owner = deployer.GetOwnerPlayer();
            if (!owner)
                return;

            if (owner.HasPermission(PERMISSION_AUTO_LOCK))
            {
                StoredData.PlayerData playerData = storedData.FindPlayerData(owner.userID) ?? storedData.SetupPlayer(owner.userID, Configuration);

                if (!playerData.IsSet(Options.AutoLock) || !CanDeployLock(owner, entity))
                    return;
                
                CodeLock codelock = entity.GetSlot(BaseEntity.Slot.Lock) as CodeLock;
                if (!codelock)
                    return;
                
                SetCodeLock(codelock, owner, playerData);
            }
        }
        
        private void OnEntityBuilt(Planner planner, GameObject obj)
        {
            if (!obj)
                return;
            
            BaseEntity entity = obj.ToBaseEntity();
            if (!planner || !entity || entity.OwnerID == 0UL)
                return;

            if (entity is not (Door or BoxStorage or Locker or BuildingPrivlidge))
                return;

            BasePlayer player = planner.GetOwnerPlayer();
            if (!player)
                return;

            StoredData.PlayerData playerData = storedData.FindPlayerData(player.userID);
            if (playerData == null)
                return;

            NextTick(() =>
            {
                if (!player || !entity || entity.IsDestroyed)
                    return;
                
                if (entity is Door door)
                {
                    if (door.canTakeLock && player.HasPermission(PERMISSION_DEPLOY_DOOR))
                        PlaceCodeLock(player, door, playerData);

                    if ((door.canTakeCloser || door.HasSlot(BaseEntity.Slot.UpperModifier)) &&
                        player.HasPermission(PERMISSION_DOOR_CLOSER) && playerData.IsSet(Options.DeployDoorCloser))
                        PlaceDoorCloser(player, door, playerData);
                    return;
                }

                if (entity is BoxStorage && entity.HasSlot(BaseEntity.Slot.Lock))
                {
                    if (player.HasPermission(PERMISSION_DEPLOY_BOX))
                        PlaceCodeLock(player, entity, playerData);
                    return;
                }

                if (entity is Locker && entity.HasSlot(BaseEntity.Slot.Lock))
                {
                    if (player.HasPermission(PERMISSION_DEPLOY_LOCKER))
                        PlaceCodeLock(player, entity, playerData);
                    return;
                }

                if (entity is BuildingPrivlidge && entity.HasSlot(BaseEntity.Slot.Lock))
                {
                    if (player.HasPermission(PERMISSION_DEPLOY_CUPBOARD))
                        PlaceCodeLock(player, entity, playerData);
                    return;
                }
            });
        }
        
        private object CanPickupEntity(BasePlayer player, DoorCloser closer)
        {
            if (player.IsAdmin && Configuration.Other.AdminBypass)
                return null;

            if (Configuration.Other.PreventDoorCloserPickup)
                return false;
            
            return null;
        }

        private void OnServerSave() => SaveData();

        private void Unload()
        {
            _harmony?.UnpatchAll("com.chaos.autocodelock");

            if (!Interface.Oxide.IsShuttingDown)
                SaveData();
            
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                CuiHelper.DestroyUi(player, UI_MENU);
                CuiHelper.DestroyUi(player, UI_BG);
            }
            
            UpdateQueue.OnUnload();
        }
        #endregion

        #region Functions
        private void FindRegisterEntities()
        {
            foreach (BaseNetworkable baseNetworkable in BaseNetworkable.serverEntities)
            {
                if (baseNetworkable is DoorCloser doorCloser)
                {
                    AdjustDoorCloserPosition(doorCloser.GetParentEntity(), doorCloser);
                    PlayerEntities.GetOrCreate(doorCloser.OwnerID)?.AddEntity(doorCloser);
                }
                else if (baseNetworkable is CodeLock codeLock)
                    PlayerEntities.GetOrCreate(codeLock.OwnerID)?.AddEntity(codeLock);
            }
        }

        private bool CanDeployLock(BasePlayer player, BaseEntity entity)
        {
            if (!(player.IsAdmin && Configuration.Other.AdminBypass))
            {
                if (player.userID != entity.OwnerID)
                {
                    SendMessage(player, "Notification.NotLocked");
                    return false;
                }

                object externalPlugins = Interface.CallHook("CanAutoLock", player);
                if (externalPlugins != null)
                {
                    SendMessage(player, "Notification.NotLocked.Plugin", externalPlugins is string ? (string) externalPlugins : string.Empty);
                    return false;
                }

                if (NoEscape.IsLoaded)
                {
                    if (Configuration.Other.CheckRaidBlock)
                    {
                        if (NoEscape.IsRaidBlocked(player))
                        {
                            SendMessage(player, "Notification.NotLocked.RaidBlock");
                            return false;
                        }
                    }

                    if (Configuration.Other.CheckCombatBlock)
                    {
                        if (NoEscape.IsCombatBlocked(player))
                        {
                            SendMessage(player, "Notification.NotLocked.CombatBlock");
                            return false;
                        }
                    }
                }
            }

            return true;
        }
        
        private void PlaceCodeLock(BasePlayer player, BaseEntity entity, StoredData.PlayerData playerData)
        {
            if (!CanDeployLock(player, entity))
                return;
            
            const string CODELOCK_PREFAB = "assets/prefabs/locks/keypad/lock.code.prefab";
            
            CodeLock codelock = GameManager.server.CreateEntity(CODELOCK_PREFAB) as CodeLock;
            if (!codelock) 
                return;
            
            codelock.OwnerID = player.userID;
            codelock.SetParent(entity, entity.GetSlotAnchorName(BaseEntity.Slot.Lock));
            
            if (player.HasPermission(PERMISSION_AUTO_LOCK) && playerData.IsSet(Options.AutoLock))
                SetCodeLock(codelock, player, playerData);
            
            codelock.Spawn();
            entity.SetSlot(BaseEntity.Slot.Lock, codelock);
        }
        
        private void PlaceDoorCloser(BasePlayer player, BaseEntity entity, StoredData.PlayerData playerData)
        {
            const string DOOR_CLOSER_PREFAB = "assets/prefabs/misc/doorcloser/doorcloser.prefab";
            
            DoorCloser doorCloser = GameManager.server.CreateEntity(DOOR_CLOSER_PREFAB) as DoorCloser;
            if (!doorCloser) 
                return;
            
            doorCloser.gameObject.Identity();

            doorCloser.OwnerID = player.userID;
            
            if (entity.ShortPrefabName is "floor.ladder.hatch" or "floor.triangle.ladder.hatch")
                doorCloser.delay = playerData.hatchCloseDelay;
            else doorCloser.delay = playerData.doorCloseDelay;
            
            doorCloser.SetParent(entity, entity.GetSlotAnchorName(BaseEntity.Slot.UpperModifier));
            doorCloser.OnDeployed(entity, null, null);

            AdjustDoorCloserPosition(entity, doorCloser);
            
            doorCloser.Spawn();
            entity.SetSlot(BaseEntity.Slot.UpperModifier, doorCloser);
        }

        private void AdjustDoorCloserPosition(BaseEntity entity, DoorCloser doorCloser)
        {
            if (!entity || !doorCloser)
                return;
            
            bool isHidden = Configuration.HideDoorClosers;
            
            if (entity.ShortPrefabName == "floor.ladder.hatch")
                doorCloser.transform.localPosition = isHidden ? new Vector3(0.75f, 0f, 0f) : new Vector3(0.7f, 0f, 0f);
            else if (entity.ShortPrefabName == "floor.triangle.ladder.hatch")
                doorCloser.transform.localPosition = isHidden ? new Vector3(-0.85f, 0f, 0f) : new Vector3(-0.8f, 0f, 0f);
            else if (entity.ShortPrefabName.StartsWith("door.double.hinged"))
            {
                doorCloser.transform.localPosition = isHidden ? new Vector3(0f, 2.4f, 0f) : new Vector3(0f, 2.3f, 0f);
                doorCloser.transform.localRotation = isHidden ? Quaternion.Euler(0f, 0f, 90f) : Quaternion.identity;
            }
            else if (entity.ShortPrefabName == "wall.frame.garagedoor") 
                doorCloser.transform.localPosition = isHidden ? new Vector3(-0.15f, 2.9f, 0f) : new Vector3(0f, 2.85f, 0f);
            else
            {
                doorCloser.transform.localPosition = isHidden ? new Vector3(0.01f, 0.21f, 0f) : Vector3.zero;
                doorCloser.transform.localRotation = isHidden ? Quaternion.Euler(0f, 0f, 90f) : Quaternion.identity;
            }
        }

        private void SetCodeLock(CodeLock codelock, BasePlayer owner, StoredData.PlayerData playerData)
        {
            codelock.code = GetOrSetPin(playerData);
            codelock.hasCode = true;
            codelock.whitelistPlayers.Add(owner.userID);

            codelock.SetFlag(BaseEntity.Flags.Locked, true, false);
            Effect.server.Run("assets/prefabs/locks/keypad/effects/lock.code.updated.prefab", codelock.transform.position);

            bool streamerMode = owner.net.connection.info.GetBool("global.streamermode");
            
            string code = streamerMode ? "****" : codelock.code;
            SendMessage(owner, "Notification.CodelockSecured", code);
        }

        private string GetOrSetPin(StoredData.PlayerData playerData)
        {
            if (string.IsNullOrEmpty(playerData.pinCode))
                playerData.pinCode = $"{UnityEngine.Random.Range(1, 9999)}".PadLeft(4, '0');
            
            return playerData.pinCode;
        }
        
        private string GetOrSetGuest(StoredData.PlayerData playerData)
        {
            if (string.IsNullOrEmpty(playerData.guestCode))
                playerData.guestCode = $"{UnityEngine.Random.Range(1, 9999)}".PadLeft(4, '0');
            
            return playerData.guestCode;
        }
        
        private static int UnixTimeStampUtc() => (int)DateTime.UtcNow.Subtract(Epoch).TotalSeconds;

        private void SendMessage(BasePlayer player, string key, params object[] args)
        {
            string prefix = Configuration.Other.ChatPrefix ? lang.GetMessage("Prefix", this, player.UserIDString) : string.Empty;

            if (args?.Length > 0)
                player.ChatMessage(prefix + string.Format(lang.GetMessage(key, this, player.UserIDString), args));
            else player.ChatMessage(prefix + lang.GetMessage(key, this, player.UserIDString));
        }
        
        private void PurgeOldData()
        {
            List<ulong> purgeList = Facepunch.Pool.Get<List<ulong>>();

            int currentTimeStamp = UnixTimeStampUtc();

            foreach (KeyValuePair<ulong, StoredData.PlayerData> kvp in storedData.playerData)
            {
                if (currentTimeStamp - kvp.Value.lastOnline > (Configuration.Data.PurgeAfter * 86400))
                    purgeList.Add(kvp.Key);
            }

            for (int i = 0; i < purgeList.Count; i++)
                storedData.playerData.Remove(purgeList[i]);

            Facepunch.Pool.FreeUnmanaged(ref purgeList);
        }
        #endregion
        
        #region Commands

        private bool HasAnyPermission(BasePlayer player) => player.HasPermission(PERMISSION_AUTO_LOCK) || player.HasPermission(PERMISSION_DEPLOY_BOX) || 
                                                            player.HasPermission(PERMISSION_DEPLOY_DOOR) || player.HasPermission(PERMISSION_DOOR_CLOSER) || 
                                                            player.HasPermission(PERMISSION_DEPLOY_LOCKER) || player.HasPermission(PERMISSION_DEPLOY_CUPBOARD);

        private void CodelockCommand(BasePlayer player, string command, string[] args)
        {
            if (!HasAnyPermission(player))
            {
                SendMessage(player, "Notification.NoPermission");
                return;
            }
            
            BaseContainer bg = ImageContainer.Create(UI_BG, Layer.Overall, Anchor.FullStretch, Offset.zero)
                .WithColor(new Color("000000", 0.0f))
                .NeedsCursor()
                .NeedsKeyboard()
                .WithChildren(uiContainer => 
                {
                    ButtonContainer.Create(uiContainer, Anchor.FullStretch, Offset.zero)
                        .WithColor(new Color("000000", 0.0f))
                        .WithCallback(m_CallbackHandler, (arg) => CloseMenu(player), $"exitbg{player.userID}");
                });
            ChaosUI.Show(player, bg);
            
            CreateCodelockUI(player);
        }
        
        private void CloseMenu(BasePlayer player)
        {
            ChaosUI.Destroy(player, UI_MENU);
            ChaosUI.Destroy(player, UI_BG);
        }
        
        private void AutoDoorCommand(BasePlayer player, string command, string[] args)
        {
            if (!player.HasPermission(PERMISSION_DOOR_CLOSER))
            {
                SendMessage(player, "Notification.NoPermission");
                return;
            }

            if (!player.IsBuildingAuthed())
            {
                SendMessage(player, "Notification.NoBuildPriv");
                return;
            }
            
            if (Physics.Raycast(player.eyes.HeadRay(), out RaycastHit raycastHit, 3f, 1 << (int)Rust.Layer.Construction, QueryTriggerInteraction.Ignore))
            {
                Door door = raycastHit.GetEntity() as Door;
                if (door)
                {
                    StoredData.PlayerData playerData = storedData.FindPlayerData(player.userID) ?? storedData.SetupPlayer(player.userID, Configuration);
                    
                    if (door.OwnerID != player.userID)
                    {
                        SendMessage(player, "Notification.NotDoorOwner");
                        return;
                    }

                    DoorCloser doorCloser = door.GetSlot(BaseEntity.Slot.UpperModifier) as DoorCloser;
                    if (doorCloser)
                    {
                        doorCloser.Kill(BaseNetworkable.DestroyMode.None);
                        SendMessage(player, "Notification.DoorCloserRemoved");
                    }
                    else
                    {
                        PlaceDoorCloser(player, door, playerData);
                        SendMessage(player, "Notification.DoorCloserPlaced");
                    }

                    return;
                }
            }
            
            SendMessage(player, "Notification.NoDoorFound");
        }
        
        [ConsoleCommand("aclock_cb")]
        private void CuiCallback(ConsoleSystem.Arg arg)
        {
            if (arg != null && arg.Args != null && arg.Args.Length > 0)
            {
                string name = arg.Args[0];
                if (m_CallbackHandler != null && m_CallbackHandler.Callbacks.TryGetValue(name, out var action))
                {
                    action(arg);
                }
            }
        }
        #endregion
        
        #region UI
        private const string UI_MENU = "acl.menu";
        private const string UI_BG = "acl.menu.bg";
        
        private Style m_BackgroundStyle;
        private Style m_PanelStyle;
        private Style m_ButtonStyle;
        private Style m_TitleStyle;
        private Style m_CloseStyle;

        private Color m_ToggleColor;
        private OutlineComponent m_OutlineRed;

        private CommandCallbackHandler m_CallbackHandler;

        private void SetupUIComponents()
        {
            m_CallbackHandler = new CommandCallbackHandler(this);

            m_BackgroundStyle = new Style
            {
                ImageColor = new Color(Configuration.Colors.Background.Hex, Configuration.Colors.Background.Alpha),
                Sprite = Sprites.Background_Rounded,
                ImageType = Image.Type.Tiled
            };

            m_PanelStyle = new Style
            {
                ImageColor = new Color(Configuration.Colors.Panel.Hex, Configuration.Colors.Panel.Alpha),
                Sprite = Sprites.Background_Rounded,
                ImageType = Image.Type.Tiled
            };

            m_ButtonStyle = new Style
            {
                ImageColor = new Color(Configuration.Colors.Button.Hex, Configuration.Colors.Button.Alpha),
                Sprite = Sprites.Background_Rounded,
                ImageType = Image.Type.Tiled,
                Alignment = TextAnchor.MiddleCenter,
                FontSize = 14
            };
            
            m_TitleStyle = new Style
            {
                FontSize = 18,
                Font = Font.PermanentMarker,
                Alignment = TextAnchor.MiddleLeft,
                WrapMode = VerticalWrapMode.Overflow
            };
            
            m_CloseStyle = new Style
            {
                FontSize = 18,
                Alignment = TextAnchor.MiddleCenter,
                WrapMode = VerticalWrapMode.Overflow,
            };

            m_ToggleColor = new Color(Configuration.Colors.Highlight.Hex, Configuration.Colors.Highlight.Alpha);
            m_OutlineRed = new OutlineComponent(new Color(Configuration.Colors.Close.Hex, Configuration.Colors.Close.Alpha));
        }

        private void CreateCodelockUI(BasePlayer player)
        {
            StoredData.PlayerData playerData = storedData.FindPlayerData(player.userID) ?? storedData.SetupPlayer(player.userID, Configuration);
            
            const float BASE_HEIGHT = 45;
            const float ELEMENT_HEIGHT = 30;
            
            float height = BASE_HEIGHT;
            
            bool canAutoLock = player.HasPermission(PERMISSION_AUTO_LOCK);
            if (canAutoLock)
            {
                if (playerData.IsSet(Options.AutoLock))
                {
                    height += ELEMENT_HEIGHT * 2; // For toggle and pin code
                }
                else height += ELEMENT_HEIGHT;
            }

            bool canDoorCloser = player.HasPermission(PERMISSION_DOOR_CLOSER);
            if (canDoorCloser)
                height += ELEMENT_HEIGHT * 4;



            height += 5f;

            BaseContainer root = BaseContainer.Create(UI_MENU, UI_BG, Anchor.FullStretch, Offset.zero)
                .DestroyExisting()
                .WithChildren(uiContainer =>
                {
                    // The actual menu panel
                    ImageContainer.Create(uiContainer, Anchor.Center, new Offset(-165f, -(height * 0.5f), 165f, (height * 0.5f)))
                    .WithStyle(m_BackgroundStyle)
                    .WithChildren(parent =>
                    {
                        CreateHeaderBar(parent, player);

                        ImageContainer.Create(parent, Anchor.FullStretch, new Offset(5f, 5f, -5f, -40f))
                            .WithStyle(m_PanelStyle)
                            .WithChildren(layout =>
                            {
                                int elementIndex = 0;

                                if (canAutoLock)
                                {
                                    CreateToggleElement(layout, player, playerData, Options.AutoLock, ++elementIndex);

                                    if (playerData.IsSet(Options.AutoLock))
                                    {
                                        CreateInputElement(layout, player, playerData, Options.PinCode, ++elementIndex, 4);
                                    }
                                }

                                if (canDoorCloser)
                                {
                                    CreateToggleElement(layout, player, playerData, Options.DeployDoorCloser, ++elementIndex);
                                    CreateInputElement(layout, player, playerData, Options.DoorDelay, ++elementIndex);
                                    CreateInputElement(layout, player, playerData, Options.HatchDelay, ++elementIndex);
                                    CreateToggleElement(layout, player, playerData, Options.DisableCloser, ++elementIndex);
                                }
                                

                            });
                    });
                });

            ChaosUI.Show(player, root);
        }

        private void CreateHeaderBar(BaseContainer parent, BasePlayer player)
        {
            ImageContainer.Create(parent, Anchor.TopStretch, new Offset(5f, -35f, -5f, -5f))
                .WithStyle(m_PanelStyle)
                .WithChildren(titleBar =>
                {
                    TextContainer.Create(titleBar, Anchor.CenterLeft, new Offset(5f, -15f, 285f, 15f))
                        .WithStyle(m_TitleStyle)
                        .WithText(GetString("Label.Title", player));

                    ImageContainer.Create(titleBar, Anchor.CenterRight, new Offset(-25f, -10f, -5f, 10f))
                        .WithStyle(m_ButtonStyle)
                        .WithOutline(m_OutlineRed)
                        .WithChildren(exit =>
                        {
                            ImageContainer.Create(exit, Anchor.FullStretch, new Offset(2.5f, 2.5f, -2.5f, -2.5f))
                                .WithColor(new Color("ff4d4d", 1f))
                                .WithSprite(Icon.Close);

                            ButtonContainer.Create(exit, Anchor.FullStretch, Offset.zero)
                                .WithColor(new Color("000000", 0.0f))
                                .WithCallback(m_CallbackHandler, (arg) => CloseMenu(player), $"{player.UserIDString}.exit");
                        });
                });
        }

        private void CreateInputElement(BaseContainer layout, BasePlayer player, StoredData.PlayerData playerData, Options option, int index, int characterLimit = 0)
        {
            const float ELEMENT_HEIGHT = 30;
            float bottom = -(ELEMENT_HEIGHT * index);
            
            BaseContainer.Create(layout, Anchor.TopStretch, new Offset(5f, bottom, -5, bottom + 25f))
                .WithChildren(inputTemplate =>
                {
                    ImageContainer.Create(inputTemplate, Anchor.FullStretch, new Offset(0f, 0f, -95f, 0f))
                        .WithStyle(m_PanelStyle);

                    ImageContainer.Create(inputTemplate, Anchor.FullStretch, new Offset(217.5f, 0f, -27.5f, 0f))
                        .WithStyle(m_PanelStyle);
                    
                    ImageContainer.Create(inputTemplate, Anchor.CenterRight, new Offset(-25f, -12.5f, 0f, 12.5f))
                        .WithStyle(m_PanelStyle);

                    TextContainer.Create(inputTemplate, Anchor.FullStretch, new Offset(5f, 0f, 0f, 0f))
                        .WithText(GetString($"Label.{option}", player))
                        .WithAlignment(TextAnchor.MiddleLeft);

                    ImageContainer.Create(inputTemplate, Anchor.CenterRight, new Offset(-90f, -10f, -30f, 10f))
                        .WithStyle(m_ButtonStyle)
                        .WithChildren(inputField =>
                        {
                            string currentValue = GetValue(player, playerData, option);
                            
                            InputFieldContainer.Create(inputField, Anchor.FullStretch, Offset.zero)
                                .WithText(currentValue)
                                .WithAlignment(TextAnchor.MiddleCenter)
                                .WithCharacterLimit(characterLimit)
                                .WithCallback(m_CallbackHandler, arg =>
                                {
                                    SetValue(playerData, option, arg);
                                    CreateCodelockUI(player);
                                }, $"{player.UserIDString}.{option}");

                        });
                    
                    ImageContainer.Create(inputTemplate, Anchor.CenterRight, new Offset(-22.5f, -10f, -2.5f, 10f))
                        .WithStyle(m_ButtonStyle)
                        .WithChildren(applyButton =>
                        {
                            ImageContainer.Create(applyButton, Anchor.FullStretch, new Offset(2.5f, 2.5f, -2.5f, -2.5f))
                                .WithSprite(Icon.Download);

                            ButtonContainer.Create(applyButton, Anchor.FullStretch, Offset.zero)
                                .WithColor(Color.Clear)
                                .WithCallback(m_CallbackHandler, arg => ApplyChanges(player, playerData, option), $"{player.UserIDString}.{option}.apply")
// ... [Code preview truncated due to length. Full source in attached file] ...

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