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

FREE OutpostRespawn : 1.3.1 1.3.1

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

namespace Oxide.Plugins
{
    [Info("Outpost Respawn", "RubMyBricks", "1.3.1")]
    [Description("Allows players to respawn at Outpost or Bandit during death.")]
    public class OutpostRespawn : RustPlugin
    {
        #region Variables

        private Configuration configuration;

        private MonumentInfo outpostMonument;
        private MonumentInfo banditCampMonument;

        private Dictionary<ulong, Dictionary<string, float>> playerCooldowns
            = new Dictionary<ulong, Dictionary<string, float>>();

        private Dictionary<ulong, Dictionary<string, float>> playerUIUnlocks
            = new Dictionary<ulong, Dictionary<string, float>>();

        private readonly Dictionary<(ulong, string), SleepingBag> invisibleBags
            = new Dictionary<(ulong, string), SleepingBag>();

        private readonly Dictionary<SleepingBag, string> bagLocations
            = new Dictionary<SleepingBag, string>();

        private readonly Dictionary<ulong, Dictionary<string, (bool singleButton, bool leftSide)>> playerUIState
            = new Dictionary<ulong, Dictionary<string, (bool, bool)>>();

        private readonly List<Vector3> outpostO = new List<Vector3>
        {
            new Vector3(6.7235f, 0.0444f, 41.9094f),
            new Vector3(15.6741f, 0.0443f, -42.1317f),
            new Vector3(-24.2365f, 0.2488f, -9.2070f),
            new Vector3(-23.2494f, 0.0537f, -36.2637f),
        };
        private readonly List<Vector3> outpostR = new List<Vector3>
        {
            new Vector3(0.7998979f, 182.3819f, 0.0f),
            new Vector3(1.6999058f, 271.2569f, 0.0f),
            new Vector3(1.8124722f, 88.7819f, 0.0f),
            new Vector3(2.3749706f, 54.6948f, 0.0f),
        };

        private readonly List<Vector3> banditO = new List<Vector3>
        {
            new Vector3(63.3794f, 2.0065f, -46.4379f),
            new Vector3(53.4470f, 2.4929f, 63.9125f),
            new Vector3(-5.3252f, 2.9515f, -76.1143f),
            new Vector3(52.6162f, 2.4362f, 63.1438f),
        };
        private readonly List<Vector3> banditR = new List<Vector3>
        {
            new Vector3(0.4624849f, 314.457458f, 0.0f),
            new Vector3(3.9499995f, 230.532516f, 0.0f),
            new Vector3(1.2500077f, 345.5074f,  0.0f),
            new Vector3(1.1249817f, 233.10228f, 0.0f),
        };

        private const float OFFSET_FACTOR = 0.01f;

        #endregion

        #region Configuration

        public class Configuration
        {
            [JsonProperty("Options")]
            public OptionsConfig Options { get; set; } = new OptionsConfig();

            [JsonProperty("Outpost")]
            public OutpostConfig Outpost { get; set; } = new OutpostConfig();

            [JsonProperty("Bandit Camp")]
            public BanditCampConfig BanditCamp { get; set; } = new BanditCampConfig();
        }

        public class OptionsConfig
        {
            [JsonProperty("Enable Sleeping Bags (Disables UI)")]
            public bool EnableSleepingBagsDisablesUI { get; set; } = false;

            [JsonProperty("Enable Permissions")]
            public bool EnablePermissions { get; set; } = true;

            [JsonProperty("Enable Outpost")]
            public bool EnableOutpost { get; set; } = true;

            [JsonProperty("Enable Bandit")]
            public bool EnableBandit { get; set; } = true;

            [JsonProperty("Enable Cooldown")]
            public bool EnableCooldown { get; set; } = true;

            [JsonProperty("Enable Auto Wake Up")]
            public bool EnableAutoWakeUp { get; set; } = true;
        }

        public class OutpostConfig
        {
            [JsonProperty("Use Permission")]
            public bool UsePermission { get; set; } = true;

            [JsonProperty("Cooldown")]
            public float Cooldown { get; set; } = 300f;

            [JsonProperty("Unlock Timer")]
            public float UnlockTimer { get; set; } = 0.0f;

            [JsonProperty("Remove Hostility")]
            public bool RemoveHostile { get; set; } = true;

            [JsonProperty("Use Auto Wake Up")]
            public bool UseAutoWakeUp { get; set; } = true;

            [JsonProperty("Outpost UI Settings")]
            public OutpostUISettings OutpostUISettings { get; set; } = new OutpostUISettings();

            [JsonProperty("Outpost Sleeping Bag Settings")]
            public OutpostSleepingBagSettings OutpostSleepingBagSettings { get; set; } = new OutpostSleepingBagSettings();
        }

        public class OutpostUISettings
        {
            [JsonProperty("Button Title Text")]
            public string ButtonTitleText { get; set; } = "Outpost";

            [JsonProperty("Button Respawn Text")]
            public string ButtonRespawnText { get; set; } = "RESPAWN »";

            [JsonProperty("Button Cooldown Text")]
            public string ButtonCooldownText { get; set; } = "COOLDOWN!";

            [JsonProperty("Button Color")]
            public string ButtonColor { get; set; } = "0.34 0.39 0.21 0.8";

            [JsonProperty("Button UI Image URL")]
            public string ButtonUIImageURL { get; set; } = "https://i.imgur.com/nqFeINB.png";

            [JsonProperty("Button UI Size")]
            public float ButtonUISize { get; set; } = 1.0f;

            [JsonProperty("Button Horizontal Offset")]
            public float ButtonHorizontalOffset { get; set; } = 0.0f;

            [JsonProperty("Button Vertical Offset")]
            public float ButtonVerticalOffset { get; set; } = 0.0f;
        }

        public class OutpostSleepingBagSettings
        {
            [JsonProperty("Sleeping Bag Name")]
            public string SleepingBagName { get; set; } = "Outpost";

            [JsonProperty("Bag Location Cycle")]
            public bool BagLocationCycle { get; set; } = false;

            [JsonProperty("Respawn At Sleeping Bag")]
            public bool RespawnAtBag { get; set; } = false;
        }

        public class BanditCampConfig
        {
            [JsonProperty("Use Permission")]
            public bool UsePermission { get; set; } = true;

            [JsonProperty("Cooldown")]
            public float Cooldown { get; set; } = 300f;

            [JsonProperty("Unlock Timer")]
            public float UnlockTimer { get; set; } = 0.0f;

            [JsonProperty("Remove Hostility")]
            public bool RemoveHostile { get; set; } = true;

            [JsonProperty("Use Auto Wake Up")]
            public bool UseAutoWakeUp { get; set; } = true;

            [JsonProperty("Bandit Camp UI Settings")]
            public BanditCampUISettings BanditCampUISettings { get; set; } = new BanditCampUISettings();

            [JsonProperty("Bandit Camp Sleeping Bag Settings")]
            public BanditCampSleepingBagSettings BanditCampSleepingBagSettings { get; set; } = new BanditCampSleepingBagSettings();
        }

        public class BanditCampUISettings
        {
            [JsonProperty("Button Title Text")]
            public string ButtonTitleText { get; set; } = "Bandit Camp";

            [JsonProperty("Button Respawn Text")]
            public string ButtonRespawnText { get; set; } = "RESPAWN »";

            [JsonProperty("Button Cooldown Text")]
            public string ButtonCooldownText { get; set; } = "COOLDOWN!";

            [JsonProperty("Button Color")]
            public string ButtonColor { get; set; } = "0.34 0.39 0.21 0.8";

            [JsonProperty("Button UI Image URL")]
            public string ButtonUIImageURL { get; set; } = "https://i.imgur.com/nqFeINB.png";

            [JsonProperty("Button UI Size")]
            public float ButtonUISize { get; set; } = 1.0f;

            [JsonProperty("Button Horizontal Offset")]
            public float ButtonHorizontalOffset { get; set; } = 0.0f;

            [JsonProperty("Button Vertical Offset")]
            public float ButtonVerticalOffset { get; set; } = 0.0f;
        }

        public class BanditCampSleepingBagSettings
        {
            [JsonProperty("Sleeping Bag Name")]
            public string SleepingBagName { get; set; } = "Bandit Camp";

            [JsonProperty("Bag Location Cycle")]
            public bool BagLocationCycle { get; set; } = false;

            [JsonProperty("Respawn At Sleeping Bag")]
            public bool RespawnAtBag { get; set; } = false;
        }

        protected override void LoadDefaultConfig()
        {
            configuration = new Configuration
            {
                Options = new OptionsConfig
                {
                    EnableSleepingBagsDisablesUI = false,
                    EnablePermissions = true,
                    EnableOutpost = true,
                    EnableBandit = true,
                    EnableCooldown = true,
                    EnableAutoWakeUp = true
                },
                Outpost = new OutpostConfig
                {
                    UsePermission = true,
                    Cooldown = 300.0f,
                    UnlockTimer = 0.0f,
                    RemoveHostile = true,
                    UseAutoWakeUp = true,
                    OutpostUISettings = new OutpostUISettings
                    {
                        ButtonTitleText = "Outpost",
                        ButtonRespawnText = "RESPAWN »",
                        ButtonCooldownText = "COOLDOWN!",
                        ButtonColor = "0.34 0.39 0.21 0.8",
                        ButtonUIImageURL = "https://i.imgur.com/nqFeINB.png",
                        ButtonUISize = 1.0f,
                        ButtonHorizontalOffset = 0.0f,
                        ButtonVerticalOffset = 0.0f
                    },
                    OutpostSleepingBagSettings = new OutpostSleepingBagSettings
                    {
                        SleepingBagName = "Outpost",
                        BagLocationCycle = false,
                        RespawnAtBag = false
                    }
                },
                BanditCamp = new BanditCampConfig
                {
                    UsePermission = true,
                    Cooldown = 300.0f,
                    UnlockTimer = 0.0f,
                    RemoveHostile = true,
                    UseAutoWakeUp = true,
                    BanditCampUISettings = new BanditCampUISettings
                    {
                        ButtonTitleText = "Bandit Camp",
                        ButtonRespawnText = "RESPAWN »",
                        ButtonCooldownText = "COOLDOWN!",
                        ButtonColor = "0.34 0.39 0.21 0.8",
                        ButtonUIImageURL = "https://i.imgur.com/nqFeINB.png",
                        ButtonUISize = 1.0f,
                        ButtonHorizontalOffset = 0.0f,
                        ButtonVerticalOffset = 0.0f
                    },
                    BanditCampSleepingBagSettings = new BanditCampSleepingBagSettings
                    {
                        SleepingBagName = "Bandit Camp",
                        BagLocationCycle = false,
                        RespawnAtBag = false
                    }
                }
            };
            SaveConfig();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                configuration = Config.ReadObject<Configuration>();
                if (configuration == null)
                    throw new Exception("Config was null after reading.");
            }
            catch
            {
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(configuration);

        #endregion

        #region Initialization

        private void OnServerInitialized()
        {
            LoadConfig();
            RegisterPermissions();

            AttemptMonumentDetection();

            if (configuration.Options.EnableSleepingBagsDisablesUI)
            {
                foreach (var p in BasePlayer.activePlayerList)
                {
                    RemoveOldBagsForPlayer(p);
                    CreateOrRelocateBagsForPlayer(p);
                }
            }
            else
            {
                foreach (var p in BasePlayer.activePlayerList)
                {
                    StartUILocksForPlayer(p);

                    if (p.IsDead())
                    {
                        timer.Once(2f, () =>
                        {
                            ShowMonumentUI(p);
                        });
                    }
                }
            }
        }

        private void AttemptMonumentDetection()
        {
            if (configuration.Options.EnableOutpost)
            {
                outpostMonument = FindMonumentByName("outpost");
                if (outpostMonument == null)
                {
                    PrintWarning("Outpost has not been found and has been disabled.");
                    configuration.Options.EnableOutpost = false;
                }
            }
            if (configuration.Options.EnableBandit)
            {
                banditCampMonument = FindMonumentByName("bandit camp");
                if (banditCampMonument == null)
                {
                    PrintWarning("Banditcamp has not been found and has been disabled.");
                    configuration.Options.EnableBandit = false;
                }
            }
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (configuration.Options.EnableSleepingBagsDisablesUI)
            {
                CreateOrRelocateBagsForPlayer(player);
            }
            else
            {
                StartUILocksForPlayer(player);

                if (player.IsDead())
                {
                    timer.Once(2f, () =>
                    {
                        if (player.IsDead())
                            ShowMonumentUI(player);
                    });
                }
            }
        }

        private void OnPlayerDeath(BasePlayer player, HitInfo info)
        {
            if (configuration.Options.EnableSleepingBagsDisablesUI)
            {
                RandomizeBagsForPlayer(player);
            }
            else
            {
                timer.Once(4f, () =>
                {
                    if (player.IsDead())
                        ShowMonumentUI(player);
                });
            }
        }

        private void OnPlayerRespawned(BasePlayer player)
        {
            RemoveRespawnButtonUI(player);

            if (configuration.Options.EnableSleepingBagsDisablesUI)
            {
                var usedBag = FindRecentlyUsedBag(player);
                if (usedBag != null && bagLocations.ContainsKey(usedBag))
                {
                    string locationKey = bagLocations[usedBag];

                    bool respawnAtBag = locationKey.Equals("Outpost", StringComparison.OrdinalIgnoreCase)
                        ? configuration.Outpost.OutpostSleepingBagSettings.RespawnAtBag
                        : configuration.BanditCamp.BanditCampSleepingBagSettings.RespawnAtBag;

                    if (!respawnAtBag)
                    {
                        TeleportToRandomLocation(player, locationKey);
                    }

                    ApplyRespawnSettings(player, locationKey);
                }
            }

            NextTick(() =>
            {
                if (player != null && player.IsConnected && !player.IsSleeping())
                {
                    player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, false);
                    player.UpdateNetworkGroup();
                    player.SendNetworkUpdateImmediate();
                    player.ClearEntityQueue();
                    player.SendFullSnapshot();
                }
            });
        }

        private SleepingBag FindRecentlyUsedBag(BasePlayer player, float maxDistance = 3f)
        {
            SleepingBag bestBag = null;
            float bestDist = float.MaxValue;
            Vector3 pPos = player.transform.position;
            foreach (var kvp in invisibleBags)
            {
                var (userID, bagLocationKey) = kvp.Key;
                var bagEntity = kvp.Value;
                if (userID != player.userID || bagEntity == null || bagEntity.IsDestroyed)
                    continue;
                float dist = Vector3.Distance(pPos, bagEntity.transform.position);
                if (dist < bestDist && dist <= maxDistance)
                {
                    bestDist = dist;
                    bestBag = bagEntity;
                }
            }
            return bestBag;
        }

        private void RegisterPermissions()
        {
            if (!configuration.Options.EnablePermissions)
                return;
            if (!permission.PermissionExists("outpostrespawn.outpost"))
                permission.RegisterPermission("outpostrespawn.outpost", this);
            if (!permission.PermissionExists("outpostrespawn.bandit"))
                permission.RegisterPermission("outpostrespawn.bandit", this);
        }

        #endregion

        #region Sleeping Bags

        private void CreateOrRelocateBagsForPlayer(BasePlayer player)
        {
            if (configuration.Options.EnableOutpost && outpostMonument != null)
            {
                if (configuration.Options.EnablePermissions && configuration.Outpost.UsePermission)
                {
                    if (permission.UserHasPermission(player.UserIDString, "outpostrespawn.outpost"))
                        CreateOrRelocateBag(player, "Outpost");
                }
                else
                {
                    CreateOrRelocateBag(player, "Outpost");
                }
            }
            if (configuration.Options.EnableBandit && banditCampMonument != null)
            {
                if (configuration.Options.EnablePermissions && configuration.BanditCamp.UsePermission)
                {
                    if (permission.UserHasPermission(player.UserIDString, "outpostrespawn.bandit"))
                        CreateOrRelocateBag(player, "BanditCamp");
                }
                else
                {
                    CreateOrRelocateBag(player, "BanditCamp");
                }
            }
        }

        private void RandomizeBagsForPlayer(BasePlayer player)
        {
            foreach (var locationKey in new[] { "Outpost", "BanditCamp" })
            {
                var tupleKey = (player.userID, locationKey);
                if (!invisibleBags.ContainsKey(tupleKey)) continue;

                bool bagLocationRotation = locationKey.Equals("Outpost", StringComparison.OrdinalIgnoreCase)
                    ? configuration.Outpost.OutpostSleepingBagSettings.BagLocationCycle
                    : configuration.BanditCamp.BanditCampSleepingBagSettings.BagLocationCycle;

                bool allowOutpost = (locationKey == "Outpost" && configuration.Options.EnableOutpost);
                bool allowBandit = (locationKey == "BanditCamp" && configuration.Options.EnableBandit);

                if ((allowOutpost || allowBandit) && bagLocationRotation)
                {
                    RelocateBag(invisibleBags[tupleKey], locationKey);
                }
            }
        }

        private void CreateOrRelocateBag(BasePlayer player, string locationKey)
        {
            var tupleKey = (player.userID, locationKey);
            if (!invisibleBags.ContainsKey(tupleKey))
            {
                var newBag = CreateNewBag(player, locationKey);
                if (newBag != null)
                {
                    invisibleBags[tupleKey] = newBag;
                }
            }
            else
            {
                RelocateBag(invisibleBags[tupleKey], locationKey);
            }
        }

        private SleepingBag CreateNewBag(BasePlayer player, string locationKey)
        {
            var data = GetMonumentSetup(locationKey);
            if (data == null) return null;
            MonumentInfo monumentRef = data.Item1;
            List<Vector3> spawnList = data.Item2;
            List<Vector3> rotList = data.Item3;
            if (monumentRef == null || spawnList.Count == 0)
                return null;

            int idx = UnityEngine.Random.Range(0, spawnList.Count);
            Vector3 localPos = spawnList[idx];
            Quaternion localRot = Quaternion.Euler(rotList[idx]);
            Vector3 spawnPos = monumentRef.transform.TransformPoint(localPos);
            spawnPos = GetGroundPosition(spawnPos);
            Quaternion spawnRot = monumentRef.transform.rotation * localRot;

            const string bagPrefab = "assets/prefabs/deployable/sleeping bag/sleepingbag_leather_deployed.prefab";
            var bag = GameManager.server.CreateEntity(bagPrefab, spawnPos, spawnRot) as SleepingBag;
            if (bag == null)
                return null;

            bag.RespawnType = ProtoBuf.RespawnInformation.SpawnOptions.RespawnType.Bed;
            bag.deployerUserID = player.userID;
            bag.OwnerID = player.userID;

            if (locationKey.Equals("Outpost", StringComparison.OrdinalIgnoreCase))
            {
                var outCfg = configuration.Outpost;
                bag.niceName = outCfg.OutpostSleepingBagSettings.SleepingBagName;
                if (!configuration.Options.EnableCooldown)
                {
                    bag.unlockTime = Time.realtimeSinceStartup + 0f;
                    bag.secondsBetweenReuses = 0f;
                }
                else
                {
                    bag.unlockTime = Time.realtimeSinceStartup + outCfg.UnlockTimer;
                    bag.secondsBetweenReuses = outCfg.Cooldown;
                }
            }
            else
            {
                var banditCfg = configuration.BanditCamp;
                bag.niceName = banditCfg.BanditCampSleepingBagSettings.SleepingBagName;
                if (!configuration.Options.EnableCooldown)
                {
                    bag.unlockTime = Time.realtimeSinceStartup + 0f;
                    bag.secondsBetweenReuses = 0f;
                }
                else
                {
                    bag.unlockTime = Time.realtimeSinceStartup + banditCfg.UnlockTimer;
                    bag.secondsBetweenReuses = banditCfg.Cooldown;
                }
            }

            bag.Spawn();
            bag.limitNetworking = true;
            bag.EnableSaving(false);
            bag.SendNetworkUpdateImmediate();

            foreach (var collider in bag.GetComponentsInChildren<Collider>(true))
            {
                collider.enabled = false;
            }

            if (!SleepingBag.sleepingBags.Contains(bag))
            {
                SleepingBag.sleepingBags.Add(bag);
            }

            bagLocations[bag] = locationKey;

            NextTick(() =>
            {
                if (player != null && player.IsConnected)
                {
                    player.SendRespawnOptions();
                }
            });
            return bag;
        }

        private void RelocateBag(SleepingBag bag, string locationKey)
        {
            if (bag == null || bag.net == null) return;
            var data = GetMonumentSetup(locationKey);
            if (data == null) return;
            MonumentInfo monumentRef = data.Item1;
            List<Vector3> spawnList = data.Item2;
            List<Vector3> rotList = data.Item3;
            if (monumentRef == null || spawnList.Count == 0)
                return;

            int idx = UnityEngine.Random.Range(0, spawnList.Count);
            Vector3 localPos = spawnList[idx];
            Quaternion localRot = Quaternion.Euler(rotList[idx]);
            Vector3 spawnPos = monumentRef.transform.TransformPoint(localPos);
            spawnPos = GetGroundPosition(spawnPos);
            Quaternion spawnRot = monumentRef.transform.rotation * localRot;

            bag.transform.position = spawnPos;
            bag.transform.rotation = spawnRot;
        }

        private void RemoveOldBagsForPlayer(BasePlayer player)
        {
            foreach (var locKey in new[] { "Outpost", "BanditCamp" })
            {
                var tupleKey = (player.userID, locKey);
                if (!invisibleBags.ContainsKey(tupleKey)) continue;
                var existingBag = invisibleBags[tupleKey];
                if (existingBag != null && !existingBag.IsDestroyed)
                {
                    if (SleepingBag.sleepingBags.Contains(existingBag))
                        SleepingBag.sleepingBags.Remove(existingBag);
                    if (bagLocations.ContainsKey(existingBag))
                        bagLocations.Remove(existingBag);
                    existingBag.Kill();
                }
                invisibleBags.Remove(tupleKey);
            }
        }

        private Tuple<MonumentInfo, List<Vector3>, List<Vector3>> GetMonumentSetup(string locationKey)
        {
            if (locationKey.Equals("Outpost", StringComparison.OrdinalIgnoreCase))
            {
                return new Tuple<MonumentInfo, List<Vector3>, List<Vector3>>(outpostMonument, outpostO, outpostR);
            }
            else if (locationKey.Equals("BanditCamp", StringComparison.OrdinalIgnoreCase))
            {
                return new Tuple<MonumentInfo, List<Vector3>, List<Vector3>>(banditCampMonument, banditO, banditR);
            }
            return null;
        }

        #endregion

        #region UI Management

        private void HandleRespawn(BasePlayer player, string locationKey)
        {
            var data = GetMonumentSetup(locationKey);
            if (data == null)
            {
                player.ChatMessage($"No in-game Monument found for {locationKey}.Cannot respawn there.");
                return;
            }
            MonumentInfo monumentRef = data.Item1;
            List<Vector3> spawnList = data.Item2;
            List<Vector3> rotList = data.Item3;
            if (monumentRef == null || spawnList.Count == 0) return;

            int idx = UnityEngine.Random.Range(0, spawnList.Count);
            Vector3 localPos = spawnList[idx];
            Quaternion localRot = Quaternion.Euler(rotList[idx]);
            Vector3 globalPos = monumentRef.transform.TransformPoint(localPos);
            globalPos = GetGroundPosition(globalPos);
            Quaternion globalRot = monumentRef.transform.rotation * localRot;

            if (!configuration.Options.EnableSleepingBagsDisablesUI)
            {
                player.RespawnAt(globalPos, globalRot);
            }
            else
            {
                player.RespawnAt(globalPos, Quaternion.identity);
            }
            NextTick(() => ApplyRespawnSettings(player, locationKey));
        }

        private void ApplyRespawnSettings(BasePlayer player, string locationKey)
        {
            bool removeHostile;
            bool autoWakeUp;
            if (locationKey.Equals("Outpost", StringComparison.OrdinalIgnoreCase))
            {
                removeHostile = configuration.Outpost.RemoveHostile;
                autoWakeUp    = configuration.Outpost.UseAutoWakeUp;
            }
            else
            {
                removeHostile = configuration.BanditCamp.RemoveHostile;
                autoWakeUp    = configuration.BanditCamp.UseAutoWakeUp;
            }
            if (configuration.Options.EnableAutoWakeUp && autoWakeUp)
            {
                timer.Once(3f, () => player.EndSleeping());
            }
            if (removeHostile && player.IsHostile())
            {
                player.State.unHostileTimestamp = 0.0f;
                player.DirtyPlayerState();
            }
        }

        private void ShowMonumentUI(BasePlayer player)
        {
            if (configuration.Options.EnableSleepingBagsDisablesUI) return;
            if (!player.IsDead())
            {
                RemoveRespawnButtonUI(player);
                return;
            }

            var validChoices = new List<string>();
            if (configuration.Options.EnableOutpost && outpostMonument != null)
            {
                if (configuration.Options.EnablePermissions && configuration.Outpost.UsePermission)
                {
                    if (permission.UserHasPermission(player.UserIDString, "outpostrespawn.outpost"))
                    {
                        validChoices.Add("Outpost");
                    }
                }
                else
                {
                    validChoices.Add("Outpost");
                }
            }
            if (configuration.Options.EnableBandit && banditCampMonument != null)
            {
                if (configuration.Options.EnablePermissions && configuration.BanditCamp.UsePermission)
                {
                    if (permission.UserHasPermission(player.UserIDString, "outpostrespawn.bandit"))
                    {
                        validChoices.Add("BanditCamp");
                    }
                }
                else
                {
                    validChoices.Add("BanditCamp");
                }
            }
            if (validChoices.Count == 0) return;

            RemoveRespawnButtonUI(player);

            if (validChoices.Count == 1)
            {
                AddRespawnButtonUI(player, validChoices[0], singleButton: true, leftSide: true);
            }
            else
            {
                AddRespawnButtonUI(player, validChoices[0], singleButton: false, leftSide: true);
                AddRespawnButtonUI(player, validChoices[1], singleButton: false, leftSide: false);
            }
        }

        private void AdjustAnchorsForScale(ref string anchorMin, ref string anchorMax, float scale)
        {
            var minParts = anchorMin.Split(' ');
            var maxParts = anchorMax.Split(' ');
            float minX = float.Parse(minParts[0], CultureInfo.InvariantCulture);
            float minY = float.Parse(minParts[1], CultureInfo.InvariantCulture);
            float maxX = float.Parse(maxParts[0], CultureInfo.InvariantCulture);
            float maxY = float.Parse(maxParts[1], CultureInfo.InvariantCulture);

            float centerX = (minX + maxX) * 0.5f;
            float centerY = (minY + maxY) * 0.5f;
            float sizeX = maxX - minX;
            float sizeY = maxY - minY;

            sizeX *= scale;
            sizeY *= scale;

            float halfX = sizeX / 2f;
            float halfY = sizeY / 2f;
            anchorMin = $"{(centerX - halfX).ToString("F4", CultureInfo.InvariantCulture)} {(centerY - halfY).ToString("F4", CultureInfo.InvariantCulture)}";
            anchorMax = $"{(centerX + halfX).ToString("F4", CultureInfo.InvariantCulture)} {(centerY + halfY).ToString("F4", CultureInfo.InvariantCulture)}";
        }

        private void AdjustImageAnchorsRelative(
            ref string imageAnchorMin, ref string imageAnchorMax,
            string origButtonMin, string origButtonMax,
            string newButtonMin, string newButtonMax)
        {
            var obMinParts = origButtonMin.Split(' ');
            var obMaxParts = origButtonMax.Split(' ');
            float obMinX = float.Parse(obMinParts[0], CultureInfo.InvariantCulture);
            float obMinY = float.Parse(obMinParts[1], CultureInfo.InvariantCulture);
            float obMaxX = float.Parse(obMaxParts[0], CultureInfo.InvariantCulture);
            float obMaxY = float.Parse(obMaxParts[1], CultureInfo.InvariantCulture);

            var oiMinParts = imageAnchorMin.Split(' ');
            var oiMaxParts = imageAnchorMax.Split(' ');
            float oiMinX = float.Parse(oiMinParts[0], CultureInfo.InvariantCulture);
            float oiMinY = float.Parse(oiMinParts[1], CultureInfo.InvariantCulture);
            float oiMaxX = float.Parse(oiMaxParts[0], CultureInfo.InvariantCulture);
            float oiMaxY = float.Parse(oiMaxParts[1], CultureInfo.InvariantCulture);

            var nbMinParts = newButtonMin.Split(' ');
            var nbMaxParts = newButtonMax.Split(' ');
            float nbMinX = float.Parse(nbMinParts[0], CultureInfo.InvariantCulture);
            float nbMinY = float.Parse(nbMinParts[1], CultureInfo.InvariantCulture);
            float nbMaxX = float.Parse(nbMaxParts[0], CultureInfo.InvariantCulture);
            float nbMaxY = float.Parse(nbMaxParts[1], CultureInfo.InvariantCulture);

            float obSizeX = obMaxX - obMinX;
            float obSizeY = obMaxY - obMinY;
            float nbSizeX = nbMaxX - nbMinX;
            float nbSizeY = nbMaxY - nbMinY;

            float fracMinX = (oiMinX - obMinX) / obSizeX;
            float fracMinY = (oiMinY - obMinY) / obSizeY;
            float fracMaxX = (oiMaxX - obMinX) / obSizeX;
            float fracMaxY = (oiMaxY - obMinY) / obSizeY;

            float newIMinX = nbMinX + fracMinX * nbSizeX;
            float newIMinY = nbMinY + fracMinY * nbSizeY;
            float newIMaxX = nbMinX + fracMaxX * nbSizeX;
            float newIMaxY = nbMinY + fracMaxY * nbSizeY;

            imageAnchorMin = $"{newIMinX.ToString("F4", CultureInfo.InvariantCulture)} {newIMinY.ToString("F4", CultureInfo.InvariantCulture)}";
            imageAnchorMax = $"{newIMaxX.ToString("F4", CultureInfo.InvariantCulture)} {newIMaxY.ToString("F4", CultureInfo.InvariantCulture)}";
        }

        private void ApplyOffsets(ref string anchorMin, ref string anchorMax, float offsetX, float offsetY)
        {
            float xAnchorOffset = offsetX * OFFSET_FACTOR;
            float yAnchorOffset = offsetY * OFFSET_FACTOR;

            var minParts = anchorMin.Split(' ');
            var maxParts = anchorMax.Split(' ');

            float minX = float.Parse(minParts[0], CultureInfo.InvariantCulture);
            float minY = float.Parse(minParts[1], CultureInfo.InvariantCulture);
            float maxX = float.Parse(maxParts[0], CultureInfo.InvariantCulture);
            float maxY = float.Parse(maxParts[1], CultureInfo.InvariantCulture);

            minX += xAnchorOffset;
            maxX += xAnchorOffset;
            minY += yAnchorOffset;
            maxY += yAnchorOffset;

            anchorMin = $"{minX.ToString("F4", CultureInfo.InvariantCulture)} {minY.ToString("F4", CultureInfo.InvariantCulture)}";
            anchorMax = $"{maxX.ToString("F4", CultureInfo.InvariantCulture)} {maxY.ToString("F4", CultureInfo.InvariantCulture)}";
        }

        private void AddRespawnButtonUI(BasePlayer player, string locationKey, bool singleButton, bool leftSide)
        {
            if (!player.IsDead()) return;

            bool isUILocked = IsUILockActive(player.userID, locationKey);

            bool isOnCooldown = configuration.Options.EnableCooldown && IsCooldownActive(player.userID, locationKey);

            string buttonName = $"monumentrespawnbutton_{locationKey}_{(leftSide ? "left" : "right")}";
            string imageName  = $"monumentrespawnguiimg_{locationKey}_{(leftSide ? "left" : "right")}";
            var container = new CuiElementContainer();

            string command = (isOnCooldown || isUILocked)
                ? ""
                : $"monumentrespawnui2_respawn {player.userID} {locationKey}";

            string closeString = (isOnCooldown || isUILocked) ? "" : buttonName;

            string truncatedName, buttonColor, buttonRespawnText, buttonCooldownText, buttonUIImage;
            float buttonUISize, horizontalOffset, verticalOffset;

            if (locationKey.Equals("Outpost", StringComparison.OrdinalIgnoreCase))
            {
                truncatedName     = configuration.Outpost.OutpostUISettings.ButtonTitleText;
                buttonColor       = configuration.Outpost.OutpostUISettings.ButtonColor;
                buttonRespawnText = configuration.Outpost.OutpostUISettings.ButtonRespawnText;
                buttonCooldownText= configuration.Outpost.OutpostUISettings.ButtonCooldownText;
                buttonUIImage     = configuration.Outpost.OutpostUISettings.ButtonUIImageURL;
                buttonUISize      = configuration.Outpost.OutpostUISettings.ButtonUISize;
                horizontalOffset  = configuration.Outpost.OutpostUISettings.ButtonHorizontalOffset;
                verticalOffset    = configuration.Outpost.OutpostUISettings.ButtonVerticalOffset;
            }
            else
            {
                truncatedName     = configuration.BanditCamp.BanditCampUISettings.ButtonTitleText;
                buttonColor       = configuration.BanditCamp.BanditCampUISettings.ButtonColor;
                buttonRespawnText = configuration.BanditCamp.BanditCampUISettings.ButtonRespawnText;
                buttonCooldownText= configuration.BanditCamp.BanditCampUISettings.ButtonCooldownText;
                buttonUIImage     = configuration.BanditCamp.BanditCampUISettings.ButtonUIImageURL;
                buttonUISize      = configuration.BanditCamp.BanditCampUISettings.ButtonUISize;
                horizontalOffset  = configuration.BanditCamp.BanditCampUISettings.ButtonHorizontalOffset;
                verticalOffset    = configuration.BanditCamp.BanditCampUISettings.ButtonVerticalOffset;
            }

            string origButtonAnchorMin, origButtonAnchorMax;
            string origImageAnchorMin, origImageAnchorMax;
            if (singleButton)
            {
                origButtonAnchorMin = "0.40 0.16";
                origButtonAnchorMax = "0.59 0.26";
                origImageAnchorMin  = "0.41 0.17";
                origImageAnchorMax  = "0.46 0.25";
            }
            else if (leftSide)
            {
                origButtonAnchorMin = "0.25 0.16";
                origButtonAnchorMax = "0.44 0.26";
                origImageAnchorMin  = "0.26 0.17";
                origImageAnchorMax  = "0.31 0.25";
            }
            else
            {
                origButtonAnchorMin = "0.56 0.16";
                origButtonAnchorMax = "0.75 0.26";
                origImageAnchorMin  = "0.57 0.17";
                origImageAnchorMax  = "0.62 0.25";
            }

            string newButtonAnchorMin = origButtonAnchorMin;
            string newButtonAnchorMax = origButtonAnchorMax;
            string newImageAnchorMin  = origImageAnchorMin;
            string newImageAnchorMax  = origImageAnchorMax;

            AdjustAnchorsForScale(ref newButtonAnchorMin, ref newButtonAnchorMax, buttonUISize);
            AdjustImageAnchorsRelative(ref newImageAnchorMin, ref newImageAnchorMax,
                origButtonAnchorMin, origButtonAnchorMax,
                newButtonAnchorMin, newButtonAnchorMax);

            ApplyOffsets(ref newButtonAnchorMin, ref newButtonAnchorMax, horizontalOffset, verticalOffset);
            ApplyOffsets(ref newImageAnchorMin,  ref newImageAnchorMax,  horizontalOffset, verticalOffset);

            int baseFontSize = 20;
            float scaleFactor = buttonUISize;
            int scaledFontSize     = Mathf.RoundToInt(baseFontSize * scaleFactor);
            int scaledHeadlineSize = Mathf.RoundToInt(24 * scaleFactor);

            string colorString = buttonColor;
            string textString;
            if (isUILocked)
            {
                colorString = "0.8 0.34 0.34 0.8";
                textString =
                    $"<size={scaledHeadlineSize}>                 {truncatedName.ToUpper()} \n" +
                    $"                 <color=#FF6347>{buttonCooldownText}</color></size>";
            }
            else if (isOnCooldown)
            {
                colorString = "0.8 0.34 0.34 0.8";
                float remainingTime = GetRemainingCooldown(player.userID, locationKey);
                textString =
                    $"<size={scaledHeadlineSize}>                 {truncatedName.ToUpper()} \n" +
                    $"                 <color=#FF6347>{buttonCooldownText} ({remainingTime:F1}s)</color></size>";
            }
            else
            {
                textString =
                    $"<size={scaledHeadlineSize}>                 {truncatedName.ToUpper()} \n" +
                    $"                 <color=#92BC49>{buttonRespawnText}</color></size>";
            }

            container.Add(new CuiButton
            {
                Button = { Command = command, Color = colorString, Close = closeString },
                RectTransform = { AnchorMin = newButtonAnchorMin, AnchorMax = newButtonAnchorMax },
                Text = { Text = textString, FontSize = scaledFontSize, Align = TextAnchor.MiddleCenter, Color = "1 1 1 1" }
            }, "Overlay", buttonName);

            container.Add(new CuiElement
            {
                Name = imageName,
                Parent = "Overlay",
                Components =
                {
                    new CuiRawImageComponent
                    {
                        Color = "1 1 1 1",
                        Url   = buttonUIImage,
                        Sprite= "assets/content/textures/generic/fulltransparent.tga"
                    },
                    new CuiRectTransformComponent
                    {
                        AnchorMin = newImageAnchorMin,
                        AnchorMax = newImageAnchorMax
                    }
                }
            });

            if (!playerUIState.ContainsKey(player.userID))
                playerUIState[player.userID] = new Dictionary<string, (bool, bool)>();
            playerUIState[player.userID][locationKey] = (singleButton, leftSide);

            CuiHelper.AddUi(player, container);
        }

        private void RemoveSingleButtonUI(BasePlayer player, string locationKey)
        {
            foreach (var side in new[] { "left", "right" })
            {
                string buttonName = $"monumentrespawnbutton_{locationKey}_{side}";
                string imageName  = $"monumentrespawnguiimg_{locationKey}_{side}";
                CuiHelper.DestroyUi(player, buttonName);
                CuiHelper.DestroyUi(player, imageName);
            }
        }

        private void RefreshSingleButtonUI(BasePlayer player, string locationKey)
        {
            if (!player.IsDead()) return;
            if (!playerUIState.TryGetValue(player.userID, out var locationDict))
                return;
            if (!locationDict.TryGetValue(locationKey, out var info))
                return;
            RemoveSingleButtonUI(player, locationKey);
            AddRespawnButtonUI(player, locationKey, info.singleButton, info.leftSide);
        }

        private void RemoveRespawnButtonUI(BasePlayer player)
        {
            CuiHelper.DestroyUi(player, "monumentrespawnbutton");
            CuiHelper.DestroyUi(player, "monumentrespawnguiimg");
            CuiHelper.DestroyUi(player, "monumentrespawncooldownoverlay");
            CuiHelper.DestroyUi(player, "cooldownUI");

            foreach (var locationKey in new[] { "Outpost", "BanditCamp" })
            {
                foreach (var side in new[] { "left", "right" })
                {
                    var buttonName   = $"monumentrespawnbutton_{locationKey}_{side}";
                    var imageName    = $"monumentrespawnguiimg_{locationKey}_{side}";
                    var overlayName  = $"monumentrespawncooldownoverlay_{locationKey}_{side}";
                    var panelName    = $"cooldownUI_{overlayName}";

                    CuiHelper.DestroyUi(player, buttonName);
                    CuiHelper.DestroyUi(player, imageName);
                    CuiHelper.DestroyUi(player, overlayName);
                    CuiHelper.DestroyUi(player, panelName);
                }
            }
        }

        [ConsoleCommand("monumentrespawnui2_respawn")]
        private void CmdRespawn(ConsoleSystem.Arg arg)
        {
            if (arg.Args == null || arg.Args.Length < 2) return;
            var p = BasePlayer.FindByID(Convert.ToUInt64(arg.Args[0]));
            if (p == null || !p.IsDead()) return;

            string locationKey = arg.Args[1];

            if (IsUILockActive(p.userID, locationKey))
            {
                p.ChatMessage("You must wait for the UI unlock timer to finish (no time displayed).");
                return;
            }
            if (configuration.Options.EnableCooldown && IsCooldownActive(p.userID, locationKey))
            {
                if (playerCooldowns.TryGetValue(p.userID, out var locationCooldowns) &&
                    locationCooldowns.TryGetValue(locationKey, out float expiryTime))
                {
                    float remaining = expiryTime - Time.time;
                    p.ChatMessage($"You are still on cooldown for {locationKey} ({remaining:F1}s).");
                }
                else
                {
                    p.ChatMessage($"You are still on cooldown for {locationKey}.");
                }
                return;
            }

            HandleRespawn(p, locationKey);

            if (locationKey.Equals("Outpost", StringComparison.OrdinalIgnoreCase))
            {
                if (configuration.Outpost.Cooldown > 0f && configuration.Options.EnableCooldown)
                {
                    StartCooldown(p.userID, locationKey, configuration.Outpost.Cooldown, p);
                }
            }
            else
            {
                if (configuration.BanditCamp.Cooldown > 0f && configuration.Options.EnableCooldown)
                {
                    StartCooldown(p.userID, locationKey, configuration.BanditCamp.Cooldown, p);
                }
            }

            NextTick(() => RemoveRespawnButtonUI(p));
        }

        #endregion

        #region Cooldown

        private bool IsCooldownActive(ulong playerID, string locationKey)
        {
            if (!configuration.Options.EnableCooldown) return false;
            if (!playerCooldowns.ContainsKey(playerID)) return false;
            if (!playerCooldowns[playerID].ContainsKey(locationKey)) return false;
            float expiryTime = playerCooldowns[playerID][locationKey];
            float currentTime = Time.time;
            return currentTime < expiryTime;
        }

        private float GetRemainingCooldown(ulong playerID, string locationKey)
        {
            if (!playerCooldowns.ContainsKey(playerID) ||
                !playerCooldowns[playerID].ContainsKey(locationKey))
                return 0f;

            return Math.Max(0f, playerCooldowns[playerID][locationKey] - Time.time);
        }

        private void StartCooldown(ulong playerID, string locationKey, float duration, BasePlayer player = null)
        {
            if (!configuration.Options.EnableCooldown) return;

            if (!playerCooldowns.ContainsKey(playerID))
                playerCooldowns[playerID] = new Dictionary<string, float>();

            float exactExpiryTime = Time.time + duration;
            playerCooldowns[playerID][locationKey] = exactExpiryTime;

            if (player != null)
            {
                timer.Once(duration, () =>
                {
                    if (player != null && player.IsConnected)
                    {
                        if (playerCooldowns.ContainsKey(playerID) &&
                            playerCooldowns[playerID].ContainsKey(locationKey) &&
                            Math.Abs(playerCooldowns[playerID][locationKey] - exactExpiryTime) < 0.001f)
                        {
                            playerCooldowns[playerID].Remove(locationKey);
                            if (player.IsDead())
                      
// ... [Code preview truncated due to length. Full source in attached file] ...

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