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

FREE RemoveCardDoors : 1.0.4 1.0.4

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

namespace Oxide.Plugins
{
    [Info("Remove Card Doors", "FacepunchExpert", "1.0.4")]
    [Description("Removes keycard doors in Red Town monuments and keeps Missile Silo doors open")]
    public class RemoveCardDoors : CovalencePlugin
    {
        #region Fields
        private Configuration config;
        private Timer processingTimer;
        private readonly Dictionary<ulong, bool> managedDoors = new();
        private readonly HashSet<ulong> processedDoors = new();
        private readonly HashSet<Door> permanentlyOpenedDoors = new();
        private bool hasInitialized;
        #endregion Fields

        #region Configuration
        public class Configuration
        {
            [JsonProperty(nameof(RemoveDoorsFromMonuments))]
            public Dictionary<string, bool> RemoveDoorsFromMonuments { get; set; }

            [JsonProperty(nameof(OpenDoorsInMonuments))]
            public Dictionary<string, bool> OpenDoorsInMonuments { get; set; }

            [JsonProperty(nameof(MonumentNameIdentifiers))]
            public Dictionary<string, List<string>> MonumentNameIdentifiers { get; set; }

            [JsonProperty(nameof(DoorPrefabsToRemove))]
            public List<string> DoorPrefabsToRemove { get; set; }

            [JsonProperty(nameof(DoorPrefabsToOpen))]
            public List<string> DoorPrefabsToOpen { get; set; }

            [JsonProperty(nameof(LogActions))]
            public bool LogActions { get; set; }

            [JsonProperty(nameof(ActionInterval))]
            public float ActionInterval { get; set; }

            [JsonProperty(nameof(CardReaderSearchRadius))]
            public float CardReaderSearchRadius { get; set; }

            [JsonProperty(nameof(DebugMode))]
            public bool DebugMode { get; set; }

            [JsonProperty(nameof(InitialStartDelay))]
            public float InitialStartDelay { get; set; }

            [JsonProperty(nameof(PreventDoorSpawn))]
            public bool PreventDoorSpawn { get; set; }

            [JsonProperty(nameof(ProcessAllDoors))]
            public bool ProcessAllDoors { get; set; }

            public Configuration()
            {
                RemoveDoorsFromMonuments = new Dictionary<string, bool>
                {
                    ["RedTown"] = true,
                    ["MissileSilo"] = false,
                };

                OpenDoorsInMonuments = new Dictionary<string, bool>
                {
                    ["MissileSilo"] = true,
                    ["RedTown"] = false,
                };

                MonumentNameIdentifiers = new Dictionary<string, List<string>>
                {
                    ["RedTown"] = new List<string>
                    {
                        "radtown",
                        "red town",
                        "powerplant",
                        "power plant",
                        "train yard",
                        "trainyard",
                        "water treatment",
                        "sewer branch",
                        "satellite",
                        "airfield",
                        "dome",
                        "harbor",
                        "junkyard",
                        "gas station",
                        "supermarket",
                        "lighthouse",
                        "cabins",
                        "tunnels",
                        "military",
                        "launch site",
                        "mining outpost",
                        "arctic",
                        "excavator",
                        "underwater",
                        "labs",
                        "outpost",
                        "fishing",
                        "ranch",
                        "sphere",
                        "oil rig",
                        "abandoned",
                        "compound",
                        "camp",
                        "mining",
                        "refinery",
                        "cargo",
                        "terminal",
                    },
                    ["MissileSilo"] = new List<string> { "missile", "silo", "hatch" },
                };

                DoorPrefabsToRemove = new List<string>
                {
                    "door.hinged.security.red",
                    "door.hinged.security.blue",
                    "door.hinged.security.green",
                    "door.hinged.toptier",
                    "door.hinged.industrial.a",
                    "door.hinged.industrial.d",
                    "door.hinged.industrial.e",
                    "door.hinged.metal",
                    "door.hinged",
                    "door.double.hinged.metal",
                    "door.double.hinged.toptier",
                    "door.double.hinged.industrial.a",
                    "door.double.hinged.windowed",
                };

                DoorPrefabsToOpen = new List<string>
                {
                    "door.hinged.nms_hatch",
                    "door.hinged.silo",
                    "hatch",
                };

                LogActions = true;
                ActionInterval = 300f;
                CardReaderSearchRadius = 10f;
                DebugMode = false;
                InitialStartDelay = 5f;
                PreventDoorSpawn = true;
                ProcessAllDoors = true;
            }
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                LogError("Could not read config file, creating a new one");
                LoadDefaultConfig();
            }
        }

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

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

        #region Oxide Hooks
        private void Init()
        {
            // Register permission for admin commands
            permission.RegisterPermission("removedoors.admin", this);

            // Register commands
            AddCovalenceCommand("removedoors.process", nameof(CmdProcessDoors));
            AddCovalenceCommand("removedoors.debug", nameof(CmdToggleDebug));
            AddCovalenceCommand("removedoors.listalldoors", nameof(CmdListAllDoors));

            // Register chat commands (shorter aliases)
            AddCovalenceCommand("rd.doors", nameof(CmdListAllDoors));
            AddCovalenceCommand("rd.process", nameof(CmdProcessDoors));
            AddCovalenceCommand("rd.debug", nameof(CmdToggleDebug));

            // Register simple chat commands for players
            AddCovalenceCommand("doors", nameof(ChatCommandListDoors));
            AddCovalenceCommand("rddebug", nameof(ChatCommandToggleDebug));
            AddCovalenceCommand("rdprocess", nameof(ChatCommandProcess));
        }

        private void OnServerInitialized()
        {
            // Immediate initial processing
            LogWarning("Starting initial door processing - immediate processing");
            _ = timer.Once(
                0.1f,
                () =>
                {
                    try
                    {
                        ProcessDoorsAggressively();
                        Puts("Initial door processing completed");
                    }
                    catch (Exception ex)
                    {
                        LogError($"Error in initial door processing: {ex}");
                    }
                }
            );

            // Secondary startup processing with a delay
            LogWarning(
                $"Scheduling secondary door processing in {config.InitialStartDelay} seconds"
            );
            _ = timer.Once(
                config.InitialStartDelay,
                () =>
                {
                    try
                    {
                        ProcessDoorsAggressively();
                        hasInitialized = true;
                        Puts("Secondary door processing completed - initialization complete");

                        // Additional aggressive processing to ensure all doors are handled
                        _ = timer.Once(
                            10f,
                            () =>
                            {
                                ProcessDoorsAggressively();
                                Puts("Final door processing completed");
                            }
                        );
                    }
                    catch (Exception ex)
                    {
                        LogError($"Error in secondary door processing: {ex}");
                    }
                }
            );

            // Start the repeating timer to process doors
            processingTimer = timer.Every(
                config.ActionInterval,
                () =>
                {
                    try
                    {
                        ProcessAllDoorsMethod();
                        MaintainPermanentlyOpenDoors();
                    }
                    catch (Exception ex)
                    {
                        LogError($"Error in door processing: {ex}");
                    }
                }
            );
        }

        private void Unload()
        {
            // Clear timer
            processingTimer?.Destroy();
            processingTimer = null;
        }

        private object OnEntitySpawned(Door door)
        {
            // Don't process during map generation or before initialization
            if (!hasInitialized && TerrainMeta.Path?.Monuments == null)
            {
                return null;
            }

            if (door?.IsDestroyed != false)
            {
                return null;
            }

            try
            {
                // Process the door with a short delay to ensure proper monument binding
                _ = timer.Once(
                    0.1f,
                    () =>
                    {
                        // Skip if already processed
                        if (
                            door?.IsDestroyed != false
                            || processedDoors.Contains(door.net.ID.Value)
                        )
                        {
                            return;
                        }

                        // Check if door should be processed based on prefab name
                        bool shouldProcess = ShouldProcessDoorByPrefab(door, out bool shouldOpen);

                        if (shouldProcess)
                        {
                            if (shouldOpen)
                            {
                                ProcessDoorForOpening(door);
                            }
                            else
                            {
                                LogInfo(
                                    $"Removing door by prefab name: {door.PrefabName} at {door.transform.position}"
                                );
                                _ = processedDoors.Add(door.net.ID.Value);
                                door.Kill();
                            }
                            return;
                        }

                        // Get monument and type
                        MonumentInfo monument = GetMonumentInfo(door);
                        if (monument == null)
                        {
                            return;
                        }

                        string monumentType = IdentifyMonumentType(monument);
                        if (string.IsNullOrEmpty(monumentType))
                        {
                            return;
                        }

                        // Check if this door should be blocked from spawning
                        if (
                            config.PreventDoorSpawn
                            && ShouldRemoveDoor(monumentType)
                            && IsCardLocked(door)
                        )
                        {
                            if (config.LogActions || config.DebugMode)
                            {
                                LogInfo(
                                    $"PREVENTED keycard door spawn at {monumentType} monument: {door.transform.position}"
                                );
                            }
                            _ = processedDoors.Add(door.net.ID.Value);
                            door.Kill();
                            return;
                        }

                        // Otherwise, process normally
                        TryProcessDoor(door);
                    }
                );
            }
            catch (Exception ex)
            {
                LogError($"Error in OnEntitySpawned for door: {ex}");
            }

            return null;
        }

        private void OnEntitySpawned(CardReader cardReader)
        {
            // Don't process during map generation or before initialization
            if (!hasInitialized && TerrainMeta.Path?.Monuments == null)
            {
                return;
            }

            if (cardReader?.IsDestroyed != false)
            {
                return;
            }

            try
            {
                // Check nearby doors with a small delay
                _ = timer.Once(
                    0.5f,
                    () =>
                    {
                        if (cardReader?.IsDestroyed != false)
                        {
                            return;
                        }

                        // Get monument and type for this card reader
                        MonumentInfo monument = GetMonumentInfoFromPosition(
                            cardReader.transform.position
                        );
                        if (monument == null)
                        {
                            return;
                        }

                        string monumentType = IdentifyMonumentType(monument);
                        if (string.IsNullOrEmpty(monumentType))
                        {
                            return;
                        }

                        if (config.DebugMode)
                        {
                            LogInfo($"CardReader found in monument type: {monumentType}");
                        }

                        List<Door> nearbyDoors = new();
                        Vis.Entities(
                            cardReader.transform.position,
                            config.CardReaderSearchRadius,
                            nearbyDoors
                        );

                        foreach (Door door in nearbyDoors)
                        {
                            if (
                                door?.IsDestroyed != false
                                || processedDoors.Contains(door.net.ID.Value)
                            )
                            {
                                continue;
                            }

                            // Check if door should be processed based on prefab name
                            bool shouldProcess = ShouldProcessDoorByPrefab(
                                door,
                                out bool shouldOpen
                            );

                            if (shouldProcess)
                            {
                                if (shouldOpen)
                                {
                                    ProcessDoorForOpening(door);
                                }
                                else
                                {
                                    LogInfo(
                                        $"Removing door by prefab name from card reader detection: {door.PrefabName} at {door.transform.position}"
                                    );
                                    _ = processedDoors.Add(door.net.ID.Value);
                                    door.Kill();
                                }
                                continue;
                            }

                            // Process door based on monument type
                            if (ShouldRemoveDoor(monumentType))
                            {
                                _ = processedDoors.Add(door.net.ID.Value);
                                if (config.LogActions)
                                {
                                    LogInfo(
                                        $"Removing keycard door from cardreader detection at {monumentType}: {door.transform.position}"
                                    );
                                }
                                door.Kill();
                            }
                            else if (ShouldOpenDoor(monumentType))
                            {
                                ProcessDoorForOpening(door);
                            }
                        }
                    }
                );
            }
            catch (Exception ex)
            {
                LogError($"Error in OnEntitySpawned for cardReader: {ex}");
            }
        }

        private void OnTerrainInitialized()
        {
            // Process all doors again now that the terrain is fully initialized
            LogWarning("Terrain initialized - processing all doors to ensure removal");
            _ = timer.Once(
                2f,
                () =>
                {
                    try
                    {
                        ProcessDoorsAggressively();
                        Puts("Terrain initialized door processing completed");

                        // Second processing for reliability
                        _ = timer.Once(
                            5f,
                            () =>
                            {
                                ProcessDoorsAggressively();
                                Puts("Second terrain initialized door processing completed");

                                // Final processing with focus on Missile Silo
                                _ = timer.Once(
                                    5f,
                                    () =>
                                    {
                                        ProcessMissileSiloDoors();
                                        Puts("Missile Silo doors processing completed");
                                    }
                                );
                            }
                        );
                    }
                    catch (Exception ex)
                    {
                        LogError($"Error in terrain initialization door processing: {ex}");
                    }
                }
            );
        }

        /// <summary>
        /// Special method to focus on Missile Silo doors
        /// </summary>
        private void ProcessMissileSiloDoors()
        {
            LogInfo("Processing Missile Silo doors specifically...");

            foreach (Door door in UnityEngine.Object.FindObjectsOfType<Door>())
            {
                if (door?.IsDestroyed != false)
                {
                    continue;
                }

                string prefabName = door.PrefabName ?? string.Empty;

                // Check for missile silo related names
                if (
                    prefabName.Contains("silo")
                    || prefabName.Contains("hatch")
                    || prefabName.Contains("nms")
                )
                {
                    ProcessDoorForOpening(door);
                    LogInfo(
                        $"Missile Silo door found and opened: {prefabName} at {door.transform.position}"
                    );
                    continue;
                }

                // Check if door is in Missile Silo monument
                MonumentInfo monument = GetMonumentInfo(door);
                if (monument != null)
                {
                    string monumentName = monument.name.ToLower(
                        System.Globalization.CultureInfo.CurrentCulture
                    );
                    if (monumentName.Contains("missile") || monumentName.Contains("silo"))
                    {
                        ProcessDoorForOpening(door);
                        LogInfo(
                            $"Door in Missile Silo monument opened: {prefabName} at {door.transform.position}"
                        );
                    }
                }
            }
        }
        #endregion Oxide Hooks

        #region Commands
        private void CmdProcessDoors(IPlayer player, string command, string[] args)
        {
            if (player?.HasPermission("removedoors.admin") == false)
            {
                player.Reply("You don't have permission to use this command.");
                return;
            }

            player?.Reply("Processing all doors aggressively...");
            ProcessDoorsAggressively();
            player?.Reply("Door processing complete.");
        }

        private void CmdToggleDebug(IPlayer player, string command, string[] args)
        {
            if (player?.HasPermission("removedoors.admin") == false)
            {
                player.Reply("You don't have permission to use this command.");
                return;
            }

            config.DebugMode = !config.DebugMode;
            SaveConfig();
            player?.Reply($"Debug mode is now {(config.DebugMode ? "enabled" : "disabled")}");
        }

        private void CmdListAllDoors(IPlayer player, string command, string[] args)
        {
            if (player?.HasPermission("removedoors.admin") == false)
            {
                player.Reply("You don't have permission to use this command.");
                return;
            }

            Dictionary<string, int> doorTypes = new();
            int total = 0;

            foreach (Door door in UnityEngine.Object.FindObjectsOfType<Door>())
            {
                if (door?.IsDestroyed != false)
                {
                    continue;
                }

                total++;
                string prefabName = door.PrefabName;

                if (!doorTypes.TryGetValue(prefabName, out int value))
                {
                    value = 0;
                    doorTypes[prefabName] = value;
                }

                doorTypes[prefabName] = ++value;
            }

            player?.Reply($"Found {total} doors in the world:");

            foreach (KeyValuePair<string, int> kvp in doorTypes.OrderByDescending(kv => kv.Value))
            {
                player?.Reply($"- {kvp.Key}: {kvp.Value}");
            }
        }
        #endregion Commands

        #region Core Functions
        private void ProcessDoorForOpening(Door door)
        {
            // Set permanently open
            _ = processedDoors.Add(door.net.ID.Value);
            door.SetFlag(BaseEntity.Flags.Open, true);
            door.SendNetworkUpdateImmediate();
            _ = permanentlyOpenedDoors.Add(door);

            if (config.LogActions)
            {
                LogInfo($"Permanently opened door {door.PrefabName} at {door.transform.position}");
            }
        }

        private bool ShouldProcessDoorByPrefab(Door door, out bool shouldOpen)
        {
            shouldOpen = false;

            if (door?.IsDestroyed != false)
            {
                return false;
            }

            string prefabName = door.PrefabName;

            // Check if this door should be opened
            if (config.DoorPrefabsToOpen.Contains(prefabName))
            {
                shouldOpen = true;
                return true;
            }

            // Check if this door should be removed
            return config.DoorPrefabsToRemove.Contains(prefabName);
        }

        private void ProcessDoorsAggressively()
        {
            LogInfo("Aggressively processing all doors...");

            // Reset these in case we're re-processing doors
            processedDoors.Clear();
            permanentlyOpenedDoors.Clear();

            int foundDoors = 0;
            int removedDoors = 0;
            int openedDoors = 0;

            // Process doors directly by type, ignoring monument boundaries for guaranteed removal
            foreach (Door door in UnityEngine.Object.FindObjectsOfType<Door>())
            {
                if (door?.IsDestroyed != false)
                {
                    continue;
                }

                foundDoors++;

                // Skip if already processed in this run
                if (processedDoors.Contains(door.net.ID.Value))
                {
                    continue;
                }

                string prefabName = door.PrefabName ?? string.Empty;
                LogInfo($"Processing door: {prefabName} at {door.transform.position}");

                // Immediately remove all doors with prefabs in DoorPrefabsToRemove regardless of monument
                if (config.DoorPrefabsToRemove.Contains(prefabName))
                {
                    _ = processedDoors.Add(door.net.ID.Value);
                    LogInfo(
                        $"Removing door by prefab match: {prefabName} at {door.transform.position}"
                    );
                    door.Kill();
                    removedDoors++;
                    continue;
                }

                // Immediately open all doors with prefabs in DoorPrefabsToOpen
                if (config.DoorPrefabsToOpen.Contains(prefabName))
                {
                    _ = processedDoors.Add(door.net.ID.Value);
                    door.SetFlag(BaseEntity.Flags.Open, true);
                    door.SendNetworkUpdateImmediate();
                    _ = permanentlyOpenedDoors.Add(door);
                    LogInfo(
                        $"Permanently opened door by prefab match: {prefabName} at {door.transform.position}"
                    );
                    openedDoors++;
                    continue;
                }

                // Get monument and type for additional processing if needed
                MonumentInfo monument = GetMonumentInfo(door);

                // If monument not found and debug is enabled, log it
                if (monument == null)
                {
                    if (config.DebugMode)
                    {
                        LogInfo($"Door not in any monument: {door.transform.position}");
                    }
                    continue;
                }

                string monumentType = IdentifyMonumentType(monument);
                if (string.IsNullOrEmpty(monumentType))
                {
                    if (config.DebugMode)
                    {
                        LogInfo($"Monument type not identified for: {monument.name}");
                    }
                    continue;
                }

                LogInfo($"Door found in monument type: {monumentType}");

                // Check if this is a keycard door
                bool isCardLocked = IsCardLocked(door);

                // Process door based on monument type
                _ = processedDoors.Add(door.net.ID.Value);

                if ((isCardLocked || config.ProcessAllDoors) && ShouldRemoveDoor(monumentType))
                {
                    LogInfo(
                        $"Removing door in {monumentType}: {prefabName} at {door.transform.position}"
                    );
                    door.Kill();
                    removedDoors++;
                }
                else if ((isCardLocked || config.ProcessAllDoors) && ShouldOpenDoor(monumentType))
                {
                    door.SetFlag(BaseEntity.Flags.Open, true);
                    door.SendNetworkUpdateImmediate();
                    _ = permanentlyOpenedDoors.Add(door);
                    LogInfo(
                        $"Permanently opened door in {monumentType}: {prefabName} at {door.transform.position}"
                    );
                    openedDoors++;
                }
            }

            LogWarning(
                $"Aggressive processing completed: Found {foundDoors} doors total, removed {removedDoors}, permanently opened {openedDoors}"
            );
        }

        private void TryProcessDoor(Door door)
        {
            if (door?.IsDestroyed != false)
            {
                return;
            }

            // Skip if already processed
            if (processedDoors.Contains(door.net.ID.Value))
            {
                return;
            }

            // First check if this door should be processed by prefab name
            bool shouldProcess = ShouldProcessDoorByPrefab(door, out bool shouldOpen);

            if (shouldProcess)
            {
                _ = processedDoors.Add(door.net.ID.Value);

                if (shouldOpen)
                {
                    ProcessDoorForOpening(door);
                }
                else
                {
                    if (config.LogActions)
                    {
                        LogInfo(
                            $"Removing door by prefab match: {door.PrefabName} at {door.transform.position}"
                        );
                    }
                    door.Kill();
                }
                return;
            }

            // Get the monument the door belongs to
            MonumentInfo monument = GetMonumentInfo(door);
            if (monument == null)
            {
                if (config.DebugMode)
                {
                    LogInfo($"Door not in any monument: {door.transform.position}");
                }
                return;
            }

            if (config.DebugMode)
            {
                LogInfo($"Door in monument: {monument.name}");
            }

            // Check if the door has a card reader
            if (!IsCardLocked(door) && !config.ProcessAllDoors)
            {
                if (config.DebugMode)
                {
                    LogInfo($"Door not card locked: {door.transform.position}");
                }
                return;
            }

            if (config.DebugMode)
            {
                LogInfo($"Door is card locked: {door.transform.position}");
            }

            // Get monument type
            string monumentType = IdentifyMonumentType(monument);
            if (string.IsNullOrEmpty(monumentType))
            {
                if (config.DebugMode)
                {
                    LogInfo($"Monument type not identified: {monument.name}");
                }
                return;
            }

            if (config.DebugMode)
            {
                LogInfo($"Monument type: {monumentType}");
            }

            // Process door based on monument type
            ProcessDoor(door, monumentType);
        }

        private void ProcessAllDoorsMethod()
        {
            if (config.DebugMode)
            {
                LogInfo("Processing all doors...");
            }

            int foundDoors = 0;
            // Process all doors in the game
            foreach (Door door in UnityEngine.Object.FindObjectsOfType<Door>())
            {
                foundDoors++;
                TryProcessDoor(door);
            }

            if (config.DebugMode)
            {
                LogInfo($"Processed {foundDoors} doors total");
            }
        }

        private void MaintainPermanentlyOpenDoors()
        {
            // Clean up any destroyed doors
            _ = permanentlyOpenedDoors.RemoveWhere(door => door?.IsDestroyed != false);

            // Ensure doors that should be permanently open remain open
            foreach (Door door in permanentlyOpenedDoors)
            {
                if (door?.IsDestroyed == false && !door.IsOpen())
                {
                    door.SetFlag(BaseEntity.Flags.Open, true);
                    door.SendNetworkUpdateImmediate();

                    if (config.DebugMode)
                    {
                        LogInfo(
                            $"Re-opening door that was closed: {door.PrefabName} at {door.transform.position}"
                        );
                    }
                }
            }
        }

        private void ProcessDoor(Door door, string monumentType)
        {
            // Skip if already processed
            if (processedDoors.Contains(door.net.ID.Value))
            {
                return;
            }

            // Mark as processed
            _ = processedDoors.Add(door.net.ID.Value);

            // Store initial state
            managedDoors[door.net.ID.Value] = door.IsOpen();

            // Check if we should remove this door
            if (ShouldRemoveDoor(monumentType))
            {
                // Remove door
                if (config.LogActions)
                {
                    LogInfo(
                        $"Removing keycard door at {monumentType} monument: {door.PrefabName} at {door.transform.position}"
                    );
                }
                door.Kill();
            }
            // Check if we should keep door open
            else if (ShouldOpenDoor(monumentType))
            {
                // Set the door to be permanently open
                door.SetFlag(BaseEntity.Flags.Open, true);
                door.SendNetworkUpdateImmediate();

                // Track this door for continuous monitoring
                _ = permanentlyOpenedDoors.Add(door);

                if (config.LogActions)
                {
                    LogInfo(
                        $"Permanently opened keycard door at {monumentType} monument: {door.PrefabName} at {door.transform.position}"
                    );
                }

                // Use a timer to ensure the door stays open
                _ = timer.Once(
                    1f,
                    () =>
                    {
                        if (door?.IsDestroyed == false && !door.IsOpen())
                        {
                            door.SetFlag(BaseEntity.Flags.Open, true);
                            door.SendNetworkUpdateImmediate();
                        }
                    }
                );
            }
        }

        private bool ShouldRemoveDoor(string monumentType)
        {
            return config.RemoveDoorsFromMonuments.TryGetValue(monumentType, out bool shouldRemove)
                && shouldRemove;
        }

        private bool ShouldOpenDoor(string monumentType)
        {
            return config.OpenDoorsInMonuments.TryGetValue(monumentType, out bool shouldOpen)
                && shouldOpen;
        }

        private string IdentifyMonumentType(MonumentInfo monument)
        {
            if (monument == null)
            {
                return string.Empty;
            }

            string monumentName = monument.name.ToLower(
                System.Globalization.CultureInfo.CurrentCulture
            );

            if (config.DebugMode)
            {
                LogInfo($"Checking monument: {monumentName}");
            }

            foreach (KeyValuePair<string, List<string>> entry in config.MonumentNameIdentifiers)
            {
                foreach (string identifier in entry.Value)
                {
                    if (monumentName.Contains(identifier))
                    {
                        if (config.DebugMode)
                        {
                            LogInfo(
                                $"Matched {monumentName} as {entry.Key} (matched on '{identifier}')"
                            );
                        }
                        return entry.Key;
                    }
                }
            }

            return string.Empty;
        }

        private MonumentInfo GetMonumentInfo(Door door)
        {
            if (door == null)
            {
                return null;
            }

            return GetMonumentInfoFromPosition(door.transform.position);
        }

        private MonumentInfo GetMonumentInfoFromPosition(Vector3 position)
        {
            // Try finding the monument directly
            if (TerrainMeta.Path?.Monuments != null)
            {
                foreach (MonumentInfo monument in TerrainMeta.Path.Monuments)
                {
                    if (monument?.IsInBounds(position) == true)
                    {
                        return monument;
                    }
                }
            }

            return null;
        }

        private bool IsCardLocked(Door door)
        {
            if (door == null)
            {
                return false;
            }

            // Check if door has any nearby card readers
            List<CardReader> cardReaders = new();
            Vis.Entities(door.transform.position, config.CardReaderSearchRadius, cardReaders);

            // Door is considered card-locked if there's at least one card reader nearby
            return cardReaders.Count > 0;
        }

        private void LogInfo(string message)
        {
            if (config.LogActions || config.DebugMode)
            {
                Puts(message);
            }
        }

        private void LogWarning(string message)
        {
            Puts($"[WARNING] {message}");
        }
        #endregion Core Functions

        /// <summary>
        /// Chat command handlers
        /// </summary>
        /// <param name="player"></param>
        /// <param name="command"></param>
        /// <param name="args"></param>
        private void ChatCommandListDoors(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("removedoors.admin"))
            {
                player.Reply("У вас нет прав для использования этой команды.");
                return;
            }

            Dictionary<string, int> doorTypes = new();
            int total = 0;

            foreach (Door door in UnityEngine.Object.FindObjectsOfType<Door>())
            {
                if (door?.IsDestroyed != false)
                {
                    continue;
                }

                total++;
                string prefabName = door.PrefabName;

                if (!doorTypes.TryGetValue(prefabName, out int value))
                {
                    value = 0;
                    doorTypes[prefabName] = value;
                }

                doorTypes[prefabName] = ++value;
            }

            player.Reply($"Найдено {total} дверей в мире:");

            foreach (KeyValuePair<string, int> kvp in doorTypes.OrderByDescending(kv => kv.Value))
            {
                player.Reply($"- {kvp.Key}: {kvp.Value}");
            }
        }

        private void ChatCommandToggleDebug(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("removedoors.admin"))
            {
                player.Reply("У вас нет прав для использования этой команды.");
                return;
            }

            config.DebugMode = !config.DebugMode;
            SaveConfig();
            player.Reply($"Режим отладки теперь {(config.DebugMode ? "включен" : "выключен")}");
        }

        private void ChatCommandProcess(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("removedoors.admin"))
            {
                player.Reply("У вас нет прав для использования этой команды.");
                return;
            }

            player.Reply("Обработка всех дверей...");
            ProcessDoorsAggressively();
            player.Reply("Обработка дверей завершена.");
        }
    }
}

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