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

FREE BradleyGuards : 1.6.6 1.6.6

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6

/*
 * Copyright (c) 2023 Bazz3l
 * 
 * Bradley Guards cannot be copied, edited and/or (re)distributed without the express permission of Bazz3l.* 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.* 
 */
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System;
using Oxide.Plugins.BradleyGuardsExtensionMethods;
using Oxide.Core.Plugins;
using Oxide.Core;
using Rust;
using UnityEngine;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Facepunch;
using HarmonyLib;
using Network;
using Action = System.Action;
namespace Oxide.Plugins {
    [Info("Bradley Guards", "Bazz3l", "1.6.6")]
    [Description("Spawn reinforcements for bradley when destroyed at configured monuments.")]
    internal class BradleyGuards : RustPlugin {
        [PluginReference]
        private Plugin NpcSpawn, GUIAnnouncements;
#region Fields
        private const string PERM_USE = "bradleyguards.use";
        private const float INITIALIZE_DELAY = 10f;
        private StoredData _storedData;
        private ConfigData _configData;
        private Coroutine _setupRoutine;
        private static BradleyGuards Instance;
#endregion
#region Local
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                {
                    MessageKeys.NoPermission, "Sorry you don't have permission to do that."
                }
                , {
                    MessageKeys.Prefix, "<color=#8a916f>Bradley Guards</color>:\n"
                }
                , {
                    MessageKeys.EventStart, "Armed reinforcements en route to <color=#e7cf85>{0}</color> eliminate the guards to gain access to high-value loot."
                }
                , {
                    MessageKeys.EventEnded, "Armed reinforcements have been eliminated at <color=#e7cf85>{0}</color>."
                }
                , {
                    MessageKeys.EventUpdated, "Event updated, please reload the plugin to take effect."
                }
                , {
                    MessageKeys.EventNotFound, "Event not found, please make sure you have typed the correct name."
                }
                , {
                    MessageKeys.DisplayNameEmpty, "Invalid event name provided."
                }
                , {
                    MessageKeys.InvalidGuardAmount, "Invalid guard amount must be between <color=#e7cf85>{0}</color> - <color=#e7cf85>{1}</color>."
                }
                , {
                    MessageKeys.InvalidBooleanValue, "Invalid boolean value provided, must be true or false."
                }
                , {
                    MessageKeys.HelpEventEnable, "<color=#e7cf85>/{0}</color> \"<color=#e7cf85><monument-path></color>\" enable <color=#e7cf85><true|false></color>\n"
                }
                , {
                    MessageKeys.HelpEventName, "<color=#e7cf85>/{0}</color> \"<color=#e7cf85><monument-path></color>\" display \"<color=#e7cf85><name-here></color>\"\n"
                }
                , {
                    MessageKeys.HelpGuardAmount, "<color=#e7cf85>/{0}</color> \"<color=#e7cf85><monument-path></color>\" amount <color=#e7cf85><number></color>\n"
                }
                , {
                    MessageKeys.HelpGuardLoadout, "<color=#e7cf85>/{0}</color> \"<color=#e7cf85><monument-path></color>\" loadout"
                }
                ,
            }
            , this);
        }
        private class MessageKeys {
            public static readonly string Prefix = "Prefix";
            public static readonly string NoPermission = "NoPermission";
            public static readonly string EventStart = "EventStart";
            public static readonly string EventEnded = "EventEnded";
            public static readonly string EventNotFound = "EventNotFound";
            public static readonly string EventUpdated = "EventUpdated";
            public static readonly string DisplayNameEmpty = "InvalidDisplayName";
            public static readonly string InvalidGuardAmount = "InvalidGuardAmount";
            public static readonly string InvalidBooleanValue = "InvalidBooleanValue";
            public static readonly string HelpEventEnable = "HelpEventEnable";
            public static readonly string HelpEventName = "HelpEventName";
            public static readonly string HelpGuardAmount = "HelpGuardAmount";
            public static readonly string HelpGuardLoadout = "HelpGuardLoadout";
        }
        private void MessagePlayer(BasePlayer player, string langKey, params object[] args) {
            if (player == null || !player.IsConnected) return;
            string message = lang.GetMessage(langKey, this);
            player.ChatMessage(args?.Length > 0 ? string.Format(message, args) : message);
        }
        private void MessagePlayers(string langKey, params object[] args) {
            string message = lang.GetMessage(langKey, this);
            message = args?.Length > 0 ? string.Format(message, args) : message;
            if (_configData.MessageSettings.EnableChat) ConsoleNetwork.BroadcastToAllClients("chat.add", 2, _configData.MessageSettings.ChatIcon, _configData.MessageSettings.EnableChatPrefix ? (lang.GetMessage(MessageKeys.Prefix, this) + message) : message);
            if (_configData.MessageSettings.EnableToast) ConsoleNetwork.BroadcastToAllClients("gametip.showtoast_translated", 2, null, message);
            if (_configData.MessageSettings.EnableGuiAnnouncements && GUIAnnouncements.IsReady()) GUIAnnouncements?.Call("CreateAnnouncement", message, _configData.MessageSettings.GuiAnnouncementsBgColor, _configData.MessageSettings.GuiAnnouncementsTextColor, null, 0.03f);
        }
#endregion
#region Config
        protected override void LoadDefaultConfig() {
            _configData = ConfigData.DefaultConfig();
            PrintWarning("Loaded default config.");
        }
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _configData = Config.ReadObject<ConfigData>();
                if (_configData == null) throw new JsonException();
                if (_configData.CommandName == null || _configData.MessageSettings == null) {
                    PrintWarning("Updated config.");
                    LoadDefaultConfig();
                    SaveConfig();
                }
            }
            catch(Exception e) {
                PrintWarning(e.Message);
                LoadDefaultConfig();
            }
        }
        protected override void SaveConfig() => Config.WriteObject(_configData, true);
        private class ConfigData {
            [JsonProperty("command name")]
            public string CommandName = "bguard";
            [JsonProperty("enable auto unlock crates when guards are eliminated")]
            public bool EnableAutoUnlock;
            [JsonProperty("enable auto extinguish crates when guards are eliminated")]
            public bool EnableAutoExtinguish;
            [JsonProperty("bradley starting health")]
            public float BradleyHealth;
            [JsonProperty("crate spawn amount")]
            public int CrateSpawnAmount;
            [JsonProperty("message notification settings")]
            public MessageSettings MessageSettings;
            public static ConfigData DefaultConfig() {
                return new ConfigData {
                    CommandName = "bguard", EnableAutoUnlock = true, EnableAutoExtinguish = true, BradleyHealth = 1000f, CrateSpawnAmount = 4, MessageSettings = new MessageSettings() {
                        EnableToast = false, EnableChat = true, EnableChatPrefix = true, ChatIcon = 76561199542550973, EnableGuiAnnouncements = false, GuiAnnouncementsBgColor = "Purple", GuiAnnouncementsTextColor = "White"
                    }
                }
                ;
            }
        }
        private class MessageSettings {
            [JsonProperty("enable toast message")]
            public bool EnableToast;
            [JsonProperty("enable chat message")]
            public bool EnableChat;
            [JsonProperty("enable chat prefix")]
            public bool EnableChatPrefix;
            [JsonProperty("custom chat message icon (steam64)")]
            public ulong ChatIcon;
            [JsonProperty("enable gui announcements plugin from umod.org")]
            public bool EnableGuiAnnouncements;
            [JsonProperty("gui announcements text color")]
            public string GuiAnnouncementsTextColor;
            [JsonProperty("gui announcements background color")]
            public string GuiAnnouncementsBgColor;
        }
#endregion
#region Storage
        private void LoadDefaultData() {
            _storedData = new StoredData {
                BradleyEventEntries = new Dictionary<string, EventEntry> {
                    ["assets/bundled/prefabs/autospawn/monument/xlarge/launch_site_1.prefab"]
                    = new EventEntry {
                        DisplayName = "Launch Site", EnabledEvent = true, BoundsPosition = new Vector3(0f, 0f, 0f), BoundsSize = new Vector3(580f, 280f, 300f), LandingPosition = new Vector3(152.3f, 3f, 0f), LandingRotation = new Vector3(0f, 90f, 0f), ChinookPosition = new Vector3(-195f, 150f, 25f), GuardAmount = 10, GuardConfig = new GuardConfig {
                            Name = "Launch Site Guard", WearItems = new List<GuardConfig.WearEntry> {
                                new GuardConfig.WearEntry {
                                    ShortName = "hazmatsuit_scientist_peacekeeper", SkinID = 0UL
                                }
                            }
                            , BeltItems = new List<GuardConfig.BeltEntry> {
                                new GuardConfig.BeltEntry {
                                    ShortName = "smg.mp5", Amount = 1, SkinID = 0UL, Mods = new List<string>()
                                }
                                , new GuardConfig.BeltEntry {
                                    ShortName = "syringe.medical", Amount = 10, SkinID = 0UL, Mods = new List<string>()
                                }
                                ,
                            }
                            , Kit = "", Health = 250f, RoamRange = 25f, ChaseRange = 40f, SenseRange = 150f, AttackRangeMultiplier = 8f, CheckVisionCone = false, VisionCone = 180f, DamageScale = 1f, TurretDamageScale = 0.25f, AimConeScale = 0.35f, DisableRadio = false, CanRunAwayWater = true, CanSleep = false, Speed = 8.5f, AreaMask = 1, AgentTypeID = -1372625422, MemoryDuration = 30f
                        }
                    }
                    , ["assets/bundled/prefabs/autospawn/monument/large/airfield_1.prefab"] = new EventEntry {
                        DisplayName = "Airfield Guard", EnabledEvent = false, BoundsPosition = new Vector3(0f, 0f, 0f), BoundsSize = new Vector3(340f, 260f, 300f), LandingPosition = new Vector3(0f, 0f, -28f), LandingRotation = new Vector3(0f, 0f, 0f), ChinookPosition = new Vector3(-195f, 150f, 25f), GuardAmount = 10, GuardConfig = new GuardConfig {
                            Name = "Guarded Crate", WearItems = new List<GuardConfig.WearEntry> {
                                new GuardConfig.WearEntry {
                                    ShortName = "hazmatsuit_scientist_peacekeeper", SkinID = 0UL
                                }
                            }
                            , BeltItems = new List<GuardConfig.BeltEntry> {
                                new GuardConfig.BeltEntry {
                                    ShortName = "smg.mp5", Amount = 1, SkinID = 0UL, Mods = new List<string>()
                                }
                                , new GuardConfig.BeltEntry {
                                    ShortName = "syringe.medical", Amount = 10, SkinID = 0UL, Mods = new List<string>()
                                }
                                ,
                            }
                            , Kit = "", Health = 250f, RoamRange = 25f, ChaseRange = 40f, SenseRange = 150f, AttackRangeMultiplier = 8f, CheckVisionCone = false, VisionCone = 180f, DamageScale = 1f, TurretDamageScale = 0.25f, AimConeScale = 0.35f, DisableRadio = false, CanRunAwayWater = true, CanSleep = false, Speed = 8.5f, AreaMask = 1, AgentTypeID = -1372625422, MemoryDuration = 30f
                        }
                    }
                }
            }
            ;
            SaveData();
        }
        private void LoadData() {
            try {
                _storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
                if (_storedData == null || !_storedData.IsValid) throw new Exception();
            }
            catch {
                PrintWarning("Loaded default data.");
                LoadDefaultData();
            }
        }
        private void SaveData() {
            if (_storedData == null || !_storedData.IsValid) return;
            Interface.Oxide.DataFileSystem.WriteObject(Name, _storedData);
        }
        private class StoredData {
            public Dictionary<string, EventEntry> BradleyEventEntries = new(StringComparer.OrdinalIgnoreCase);
            [JsonIgnore]
            public bool IsValid => BradleyEventEntries != null && BradleyEventEntries.Count > 0;
            public EventEntry FindEntryByName(string monumentName) {
                return BradleyEventEntries.TryGetValue(monumentName, out EventEntry eventEntry) ? eventEntry : null;
            }
        }
        private class EventEntry {
            [JsonProperty("display name")]
            public string DisplayName;
            [JsonProperty("enabled")]
            public bool EnabledEvent;
            [JsonProperty("bounds center")]
            public Vector3 BoundsPosition;
            [JsonProperty("bounds size")]
            public Vector3 BoundsSize;
            [JsonProperty("landing position")]
            public Vector3 LandingPosition;
            [JsonProperty("landing rotation")]
            public Vector3 LandingRotation;
            [JsonProperty("chinook position")]
            public Vector3 ChinookPosition;
            [JsonProperty("guard spawn amount")]
            public int GuardAmount;
            [JsonProperty("guard spawn profile")]
            public GuardConfig GuardConfig;
            public IEnumerator Create(Transform transform, bool enableAutoExtinguish, bool enableAutoUnlock) {
                Vector3 landingRotation = transform.TransformDirection(transform.rotation.eulerAngles - LandingRotation);
                Vector3 landingPosition = transform.TransformPoint(LandingPosition);
                Vector3 chinookPosition = transform.TransformPoint(ChinookPosition);
                if (GuardConfig.Parsed == null) GuardConfig.CacheConfig();
                BradleyGuardsEvent component = Utils.CreateObjectWithComponent<BradleyGuardsEvent>(landingPosition, Quaternion.Euler(landingRotation), "Bradley_Guards_Event");
                component.bounds = new OBB(transform.position, transform.rotation, new Bounds(BoundsPosition, BoundsSize));
                component.chinookPosition = chinookPosition;
                component.guardConfig = GuardConfig;
                component.guardAmount = GuardAmount;
                component.displayName = DisplayName;
                component.enableAutoExtinguish = enableAutoExtinguish;
                component.enableAutoUnlock = enableAutoUnlock;
                component.CreateLandingZone();
                component.DisplayInfo();
                yield return CoroutineEx.waitForEndOfFrame;
            }
        }
        private class GuardConfig {
            public string Name;
            public string Kit;
            public float Health;
            public float RoamRange;
            public float ChaseRange;
            public float SenseRange;
            public float AttackRangeMultiplier;
            public bool CheckVisionCone;
            public float VisionCone;
            public float DamageScale;
            public float TurretDamageScale;
            public float AimConeScale;
            public bool DisableRadio;
            public bool CanRunAwayWater;
            public bool CanSleep;
            public float Speed;
            public int AreaMask;
            public int AgentTypeID;
            public float MemoryDuration;
            public List<WearEntry> WearItems;
            public List<BeltEntry> BeltItems;
            [JsonIgnore]
            public JObject Parsed;
            public class BeltEntry {
                public string ShortName;
                public ulong SkinID;
                public int Amount;
                public string Ammo;
                public List<string> Mods;
                public static List<BeltEntry> SaveItems(ItemContainer container) {
                    List<BeltEntry> items = new List<BeltEntry>();
                    foreach (Item item in container.itemList) {
                        BeltEntry beltEntry = new BeltEntry {
                            ShortName = item.info.shortname, SkinID = item.skin, Amount = item.amount, Mods = new List<string>()
                        }
                        ;
                        if (item.GetHeldEntity() is BaseProjectile projectile && projectile?.primaryMagazine != null && projectile.primaryMagazine.ammoType != null) beltEntry.Ammo = projectile.primaryMagazine.ammoType.shortname;
                        if (item?.contents?.itemList != null) {
                            foreach (Item itemContent in item.contents.itemList) beltEntry.Mods.Add(itemContent.info.shortname);
                        }
                        items.Add(beltEntry);
                    }
                    return items;
                }
            }
            public class WearEntry {
                public string ShortName;
                public ulong SkinID;
                public static List<WearEntry> SaveItems(ItemContainer container) {
                    List<WearEntry> items = new List<WearEntry>();
                    foreach (Item item in container.itemList) {
                        WearEntry wearEntry = new WearEntry {
                            ShortName = item.info.shortname, SkinID = item.skin
                        }
                        ;
                        items.Add(wearEntry);
                    }
                    return items;
                }
            }
            public void CacheConfig() {
                Parsed = new JObject {
                    ["Name"]
                    = Name, ["WearItems"] = new JArray {
                        WearItems.Select(x => new JObject {
                            ["ShortName"]
                            = x.ShortName, ["SkinID"] = x.SkinID
                        }
                        )
                    }
                    , ["BeltItems"] = new JArray {
                        BeltItems.Select(x => new JObject {
                            ["ShortName"]
                            = x.ShortName, ["SkinID"] = x.SkinID, ["Amount"] = x.Amount, ["Ammo"] = x.Ammo, ["Mods"] = new JArray(x.Mods)
                        }
                        )
                    }
                    , ["Kit"] = Kit, ["Health"] = Health, ["RoamRange"] = RoamRange, ["ChaseRange"] = ChaseRange, ["SenseRange"] = SenseRange, ["ListenRange"] = SenseRange / 2, ["AttackRangeMultiplier"] = AttackRangeMultiplier, ["CheckVisionCone"] = CheckVisionCone, ["VisionCone"] = VisionCone, ["DamageScale"] = DamageScale, ["TurretDamageScale"] = TurretDamageScale, ["AimConeScale"] = AimConeScale, ["DisableRadio"] = DisableRadio, ["CanRunAwayWater"] = CanRunAwayWater, ["CanSleep"] = CanSleep, ["Speed"] = Speed, ["AreaMask"] = AreaMask, ["AgentTypeID"] = AgentTypeID, ["MemoryDuration"] = MemoryDuration, ["States"] = new JArray {
                        new HashSet<string> {
                            "RoamState", "ChaseState", "CombatState", "RaidState"
                        }
                    }
                }
                ;
            }
        }
#endregion
#region Oxide Hooks
        private void OnServerInitialized() {
            CustomProtection.Initialize();
            EntitiesLookup.Initialize();
            PerformSetupRoutine();
            if (string.IsNullOrEmpty(_configData.CommandName)) return;
            cmd.AddChatCommand(_configData.CommandName, this, nameof(EventCommands));
        }
        private void Init() {
            permission.RegisterPermission(PERM_USE, this);
            Instance = this;
            LoadData();
        }
        private void Unload() {
            try {
                DestroySetupRoutine();
                BradleyGuardsEvent.OnUnload();
            }
            finally {
                CustomProtection.OnUnload();
                EntitiesLookup.OnUnload();
                Instance = null;
            }
        }
        private void OnEntityKill(ScientistNPC npc) {
            EntitiesLookup.FindEventByEntity(npc) ?.OnGuardDeath(npc, null);
        }
        private void OnEntitySpawned(BradleyAPC bradley) {
            if (bradley == null || bradley.IsDestroyed) return;
            Vector3 position = bradley.transform.position;
            if (position == Vector3.zero) return;
            BradleyGuardsEvent component = BradleyGuardsEvent.GetClosest(position);
            if (component == null) return;
            component.ResetEvent();
            bradley.maxCratesToSpawn = _configData.CrateSpawnAmount;
            bradley._maxHealth = _configData.BradleyHealth;
            bradley.InitializeHealth(_configData.BradleyHealth, _configData.BradleyHealth);
        }
        private void OnEntityDeath(BradleyAPC bradley, HitInfo info) {
            if (bradley == null || bradley.IsDestroyed || info?.InitiatorPlayer == null) return;
            Vector3 position = bradley.transform.position;
            if (position == Vector3.zero) return;
            BradleyGuardsEvent component = BradleyGuardsEvent.GetClosest(position);
            if (component == null || component.IsStarted()) return;
            if (!NpcSpawn.IsReady()) {
                PrintWarning("Missing dependency [NpcSpawn v2.4.8] this can be found over at codefling.com thanks to KpucTaJl");
                return;
            }
            component.StartEvent(position);
        }
        private void OnEntityDeath(ScientistNPC npc, HitInfo hitInfo) {
            EntitiesLookup.FindEventByEntity(npc) ?.OnGuardDeath(npc, hitInfo?.InitiatorPlayer);
        }
        private void OnEntityDismounted(BaseMountable mountable, ScientistNPC scientist) {
            CH47HelicopterAIController chinook = mountable.GetParentEntity() as CH47HelicopterAIController;
            if (chinook == null || chinook.OwnerID != 111999 || chinook.IsDestroyed) return;
            scientist.Brain.Navigator.ForceToGround();
            scientist.Brain.Navigator.SetDestination(scientist.finalDestination);
            if (chinook.AnyMounted()) return;
            ForceChinookLeave(chinook);
        }
#endregion
#region Event
        private void PerformSetupRoutine() {
            DestroySetupRoutine();
            _setupRoutine = ServerMgr.Instance.StartCoroutine(SetupEventsRoutine());
        }
        private void DestroySetupRoutine() {
            if (_setupRoutine != null) ServerMgr.Instance.StopCoroutine(_setupRoutine);
            _setupRoutine = null;
        }
        private IEnumerator SetupEventsRoutine() {
            yield return null;
            Interface.Oxide.LogDebug("Initializing (Bradley Guard Events) in ({0})s.", INITIALIZE_DELAY);
            yield return CoroutineEx.waitForSeconds(INITIALIZE_DELAY);
            using (new DebugStopwatch("Finished initializing (Bradley Guard Events) in ({0})ms.")) {
                foreach (MonumentInfo monumentInfo in TerrainMeta.Path.Monuments) {
                    if (monumentInfo.name.IsNullOrEmpty()) continue;
                    EventEntry monumentEntry = _storedData.FindEntryByName(monumentInfo.name);
                    if (monumentEntry == null || !monumentEntry.EnabledEvent) continue;
                    yield return monumentEntry.Create(monumentInfo.transform, _configData.EnableAutoExtinguish, _configData.EnableAutoUnlock);
                }
            }
            _setupRoutine = null;
            yield break;
        }
        private class BradleyGuardsEvent : FacepunchBehaviour {
            public static readonly List<BradleyGuardsEvent> EventComponents = new();
            private List<BaseEntity> _spawnInstances = new();
            private CH47LandingZone _eventLandingZone;
            private CurrentState _eventState;
            private Vector3 _eventPosition;
            private GameObject _go;
            public GuardConfig guardConfig;
            public Vector3 chinookPosition;
            public string displayName;
            public int guardAmount;
            public bool enableAutoExtinguish;
            public bool enableAutoUnlock;
            public OBB bounds;
            public BasePlayer winningPlayer;
            public static BradleyGuardsEvent GetClosest(Vector3 position) {
                for (int i = 0; i < EventComponents.Count; i++) {
                    BradleyGuardsEvent component = EventComponents[i];
                    if (component.bounds.Contains(position)) return component;
                }
                return (BradleyGuardsEvent)null;
            }
            public static void OnUnload() {
                if (Rust.Application.isQuitting) return;
                for (int i = EventComponents.Count - 1; i >= 0; i--) EventComponents[i]?.DestroyMe();
                EventComponents.Clear();
            }
#region Unity
            public void Awake() {
                _go = gameObject;
                BradleyGuardsEvent.EventComponents.Add(this);
            }
            public void OnDestroy() {
                BradleyGuardsEvent.EventComponents.Remove(this);
            }
            public void DestroyMe() {
                ClearGuards();
                UnityEngine.GameObject.Destroy(_go);
            }
#endregion
#region Event Management
            public bool IsStarted() => _eventState == CurrentState.Started;
            public void StartEvent(Vector3 deathPosition) {
                if (IsStarted()) return;
                winningPlayer = null;
                _eventPosition = deathPosition;
                _eventState = CurrentState.Started;
                SpawnChinook();
                RemoveDamage();
                Instance?.HookResubscribe();
                Instance?.MessagePlayers(MessageKeys.EventStart, displayName);
            }
            private void StopEvent() {
                _eventState = CurrentState.Waiting;
                Instance?.HookUnsubscribe();
                Instance?.MessagePlayers(MessageKeys.EventEnded, displayName);
            }
            public void ResetEvent() {
                ClearGuards();
                _eventState = CurrentState.Waiting;
            }
            public void CheckEvent() {
                if (enableAutoExtinguish) RemoveFlames();
                if (enableAutoUnlock) UnlockCrates();
                if (winningPlayer != null) Interface.CallHook("OnBradleyGuardsEventEnded", winningPlayer);
                StopEvent();
            }
            private bool HasGuards() => _spawnInstances.Count > 0;
            private void UnlockCrates() {
                List<LockedByEntCrate> entities = Facepunch.Pool.Get<List<LockedByEntCrate>>();
                try {
                    Vis.Entities(_eventPosition, 25f, entities);
                    foreach (LockedByEntCrate entCrate in entities) {
                        if (!entCrate.IsValid() || entCrate.IsDestroyed) continue;
                        entCrate.SetLocked(false);
                        if (entCrate.lockingEnt == null) continue;
                        BaseEntity entity = entCrate.lockingEnt.GetComponent<BaseEntity>();
                        if (entity != null && !entity.IsDestroyed) entity.Kill();
                    }
                }
                catch (Exception e) {
                    //
                }
                Facepunch.Pool.FreeUnmanaged<LockedByEntCrate>(ref entities);
            }
            private void RemoveFlames() {
                List<FireBall> entities = Facepunch.Pool.Get<List<FireBall>>();
                try {
                    Vis.Entities<FireBall>(_eventPosition, 25f, entities);
                    foreach (FireBall fireball in entities) {
                        if (fireball.IsValid() && !fireball.IsDestroyed) fireball.Extinguish();
                    }
                }
                catch (Exception e) {
                    //
                }
                Facepunch.Pool.FreeUnmanaged<FireBall>(ref entities);
            }
            private void RemoveDamage() {
                List<FireBall> entities = Facepunch.Pool.Get<List<FireBall>>();
                try {
                    Vis.Entities<FireBall>(_eventPosition, 25f, entities);
                    foreach (FireBall fireball in entities) {
                        if (fireball.IsValid() && !fireball.IsDestroyed) fireball.ignoreNPC = true;
                    }
                }
                catch (Exception e) {
                    //
                }
                Facepunch.Pool.FreeUnmanaged<FireBall>(ref entities);
            }
#endregion
#region Chinook
            private void SpawnChinook() {
                CH47HelicopterAIController component = GameManager.server.CreateEntity("assets/prefabs/npc/ch47/ch47scientists.entity.prefab")?.GetComponent<CH47HelicopterAIController>();
                component.transform.position = chinookPosition;
                component.SetLandingTarget(_eventLandingZone.transform.position);
                component.OwnerID = 111999;
                component.Spawn();
                component.SetMinHoverHeight(0.0f);
                component.Invoke(new Action(() => SpawnGuards(component, guardAmount)), 0.25f);
                component.Invoke(new Action(() => DropSmokeGrenade(_eventLandingZone.transform.position)), 1f);
                CustomProtection.ModifyProtection(component);
            }
            private void DropSmokeGrenade(Vector3 position) {
                SmokeGrenade component = GameManager.server.CreateEntity("assets/prefabs/tools/smoke grenade/grenade.smoke.deployed.prefab", position, Quaternion.identity).GetComponent<SmokeGrenade>();
                component.smokeDuration = 45f;
                component.Spawn();
            }
#endregion
#region Landing
            public void CreateLandingZone() {
                _eventLandingZone = gameObject.AddComponent<CH47LandingZone>();
                _eventLandingZone.enabled = true;
            }
#endregion
#region Guard
            private void SpawnGuards(CH47HelicopterAIController chinook, int numToSpawn) {
                int num = Mathf.Clamp(numToSpawn, 1, chinook.mountPoints.Count);
                for (int i = 0; i < 2; i++) SpawnGuard(chinook, chinook.transform.position + chinook.transform.forward * 10f);
                num -= 2;
                if (num <= 0) return;
                for (int i = 0; i < num; i++) SpawnGuard(chinook, chinook.transform.position - chinook.transform.forward * 15f);
            }
            private void SpawnGuard(CH47HelicopterAIController chinook, Vector3 position) {
                Vector3 destination = _eventPosition.GetPointAround(2f);
                guardConfig.Parsed["HomePosition"] = destination.ToString();
                ScientistNPC scientist = (ScientistNPC)Instance?.NpcSpawn.Call("SpawnNpc", position, guardConfig.Parsed);
                if (scientist == null || scientist.IsDestroyed) return;
                scientist.finalDestination = destination;
                CachedGuardAdd(scientist);
                chinook.AttemptMount((BasePlayer) scientist, false);
            }
            public void ClearGuards() {
                for (int i = _spawnInstances.Count - 1; i >= 0; i--) {
                    BaseEntity entity = _spawnInstances[i];
                    if (entity != null && !entity.IsDestroyed) entity.Kill();
                }
                _spawnInstances.Clear();
            }
#endregion
#region Oxide Hooks
            public void OnGuardDeath(ScientistNPC npc, BasePlayer player) {
                CachedGuardRemove(npc);
                if (HasGuards()) return;
                winningPlayer = player;
                CheckEvent();
            }
#endregion
#region Cache Guard Entity
            private void CachedGuardAdd(BaseEntity entity) {
                _spawnInstances.Add(entity);
                EntitiesLookup.CreateEntity(entity, this);
            }
            private void CachedGuardRemove(BaseEntity entity) {
                _spawnInstances.Remove(entity);
                EntitiesLookup.RemoveEntity(entity);
            }
#endregion
#region Debug Info
            public void DisplayInfo() {
                List<Connection> connections = Facepunch.Pool.Get<List<Connection>>();
                try {
                    connections.AddRange(Net.sv.connections.Where(x => x.connected && x.authLevel == 2));
                    Utils.DText(connections, transform.position, "Landing Position", Color.magenta, 30f);
                    Utils.DText(connections, chinookPosition, "Chinook Position", Color.green, 30f);
                    Utils.DLine(connections, chinookPosition, _eventLandingZone.transform.position, Color.yellow, 30f);
                    Utils.DText(connections, bounds.position, "Bounds Position", Color.cyan, 30f);
                    Utils.DCube(connections, bounds.position, bounds.rotation, bounds.extents, Color.blue, 30f);
                }
                catch (Exception e) {
                    //
                }
                Facepunch.Pool.FreeUnmanaged<Connection>(ref connections);
            }
#endregion
        }
        private void ForceChinookLeave(CH47HelicopterAIController chinook) {
            chinook.ClearLandingTarget();
            chinook.Invoke(() => {
                chinook.EnableFacingOverride(true);
                chinook.SetMinHoverHeight(60f);
                chinook.SetMoveTarget(Vector3.right * 6000f);
                chinook.Invoke(new Action(chinook.KillMessage), 60f);
                if (chinook.TryGetComponent<CH47AIBrain>(out CH47AIBrain aiBrain)) aiBrain.SwitchToState(AIState.Egress, aiBrain.currentStateContainerID);
            }
            , 5f);
        }
        private enum CurrentState {
            Waiting, Started
        }
#endregion
#region Rust Edit
        private object OnNpcRustEdit(ScientistNPC npc) {
            return EntitiesLookup.FindEventByEntity(npc) != null ? (object)true : null;
        }
#endregion
#region Hook Subscribe
        private void HookUnsubscribe() => Unsubscribe(nameof(OnEntityDismounted));
        private void HookResubscribe() => Subscribe(nameof(OnEntityDismounted));
#endregion
#region Custom Protection
        private static class CustomProtection {
            private static ProtectionProperties ProtectionInstance;
            public static void Initialize() {
                ProtectionInstance = ScriptableObject.CreateInstance<ProtectionProperties>();
                ProtectionInstance.name = "Bradley_Guards_Protection";
                ProtectionInstance.Add(1);
            }
            public static void OnUnload() {
                if (ProtectionInstance != null) UnityEngine.ScriptableObject.Destroy(ProtectionInstance);
                ProtectionInstance = null;
            }
            public static void ModifyProtection(BaseCombatEntity combatEntity) {
                if (combatEntity != null && !combatEntity.IsDestroyed) combatEntity.baseProtection = ProtectionInstance;
            }
        }
#endregion
#region Entities Lookup
        private static class EntitiesLookup {
            public static Dictionary<BaseEntity, BradleyGuardsEvent> Entities;
            public static BradleyGuardsEvent FindEventByEntity(BaseEntity entity) {
                return entity != null && Entities.TryGetValue(entity, out BradleyGuardsEvent component) ? component : null;
            }
            public static void Initialize() {
                Entities = new Dictionary<BaseEntity, BradleyGuardsEvent>();
            }
            public static void OnUnload() {
                Entities.Clear();
                Entities = null;
            }
            public static void CreateEntity(BaseEntity entity, BradleyGuardsEvent component) {
                if (Entities != null) Entities.Add(entity, component);
            }
            public static void RemoveEntity(BaseEntity entity) {
                if (Entities != null) Entities.Remove(entity);
            }
        }
#endregion
#region Chat Command
        private void EventCommands(BasePlayer player, string command, string[] args) {
            if (!permission.UserHasPermission(player.UserIDString, PERM_USE)) {
                MessagePlayer(player, MessageKeys.NoPermission);
                return;
            }
            if (args.Length < 2) {
                EventHelpText(player);
                return;
            }
            if (!_storedData.BradleyEventEntries.TryGetValue(args[0], out EventEntry eventEntry)) {
                MessagePlayer(player, MessageKeys.EventNotFound);
                return;
            }
            string option = args[1];
            if (option.Equals("enable")) {
                if (args.Length != 3) {
                    EventHelpText(player);
                    return;
                }
                bool enabled;
                if (bool.TryParse(args[2], out enabled)) {
                    MessagePlayer(player, MessageKeys.InvalidBooleanValue);
                    return;
                }
                eventEntry.EnabledEvent = enabled;
                SaveData();
                MessagePlayer(player, MessageKeys.EventUpdated);
                return;
            }
            if (option.Equals("display")) {
                if (args.Length != 3) {
                    EventHelpText(player);
                    return;
                }
                string displayName = string.Join(" ", args.Skip(2));
                if (displayName.IsNullOrEmpty()) {
                    MessagePlayer(player, MessageKeys.DisplayNameEmpty);
                    return;
                }
                eventEntry.DisplayName = displayName;
                SaveData();
                MessagePlayer(player, MessageKeys.EventUpdated);
                return;
            }
            if (option.Equals("amount")) {
                if (args.Length != 3) {
                    EventHelpText(player);
                    return;
                }
                int amount;
                if (!int.TryParse(args[2], out amount) || (amount < 2 || amount > 10)) {
                    MessagePlayer(player, MessageKeys.InvalidGuardAmount);
                    return;
                }
                eventEntry.GuardAmount = amount;
                SaveData();
                MessagePlayer(player, MessageKeys.EventUpdated);
                return;
            }
            if (option.Equals("loadout")) {
                if (player.inventory == null) return;
                eventEntry.GuardConfig.BeltItems = GuardConfig.BeltEntry.SaveItems(player.inventory.containerBelt);
                eventEntry.GuardConfig.WearItems = GuardConfig.WearEntry.SaveItems(player.inventory.containerWear);
                eventEntry.GuardConfig.CacheConfig();
                SaveData();
                MessagePlayer(player, MessageKeys.EventUpdated);
                return;
            }
            EventHelpText(player);
        }
        private void EventHelpText(BasePlayer player) {
            StringBuilder sb = Facepunch.Pool.Get<StringBuilder>();
            try {
                sb.Clear();
                sb.AppendFormat(lang.GetMessage(MessageKeys.Prefix, this, player.UserIDString)).AppendFormat(lang.GetMessage(MessageKeys.HelpEventEnable, this, player.UserIDString), _configData.CommandName).AppendFormat(lang.GetMessage(MessageKeys.HelpEventName, this, player.UserIDString), _configData.CommandName).AppendFormat(lang.GetMessage(MessageKeys.HelpGuardAmount, this, player.UserIDString), _configData.CommandName).AppendFormat(lang.GetMessage(MessageKeys.HelpGuardLoadout, this, player.UserIDString), _configData.CommandName);
                player.ChatMessage(sb.ToString());
            }
            finally {
                sb.Clear();
                Facepunch.Pool.FreeUnmanaged(ref sb);
            }
        }
#endregion
#region Debug Stopwatch
        private class DebugStopwatch : IDisposable {
            private Stopwatch _stopwatch;
            private string _format;
            public DebugStopwatch(string format) {
                _format = format;
                _stopwatch = new Stopwatch();
                _stopwatch.Start();
            }
            public void Dispose() {
                _stopwatch.Stop();
                Interface.Oxide.LogDebug(_format, _stopwatch.ElapsedMilliseconds);
                _stopwatch = null;
            }
        }
#endregion
#region Harmony Patches
        [AutoPatch]
        [HarmonyPatch(typeof(CH47HelicopterAIController), "CheckSpawnScientists")]
        public static class Prevent_CH47_Scientists_Spawning_Patch {
            public static bool Prefix(CH47HelicopterAIController __instance) {
                return !(__instance != null && __instance.OwnerID == 111999);
            }
        }
#endregion
    }
}
namespace Oxide.Plugins.BradleyGuardsExtensionMethods {
    public static class Utils {
        public static T CreateObjectWithComponent<T>(Vector3 position, Quaternion rotation, string name) where T : MonoBehaviour {
            return new GameObject(name) {
                layer = (int)Layer.Reserved1, transform = {
                    position = position, rotation = rotation
                }
            }
            .AddComponent<T>();
        }
        public static void Segments(List<Connection> connections, Vector3 origin, Vector3 target, Color color, float duration) {
            Vector3 delta = target - origin;
            float distance = delta.magnitude;
            Vector3 direction = delta.normalized;
            float segmentLength = 10f;
            int numSegments = Mathf.CeilToInt(distance / segmentLength);
            for (int i = 0; i < numSegments; i++) {
                float length = segmentLength;
                if (i == numSegments - 1 && distance % segmentLength != 0) length = distance % segmentLength;
                Vector3 start = origin + i * segmentLength * direction;
                Vector3 end = start + length * direction;
                Utils.DLine(connections, start, end, color, duration);
            }
        }
        public static void DLine(List<Connection> connections, Vector3 start, Vector3 end, Color color, float duration) {
            if (connections?.Count > 0) ConsoleNetwork.SendClientCommand(connections, "ddraw.line", duration, color, start, end);
        }
        public static void DText(List<Connection> connections, Vector3 origin, string text, Color color, float duration) {
            if (connections?.Count > 0) ConsoleNetwork.SendClientCommand(connections, "ddraw.text", duration, color, origin, text);
        }
        public static void DCube(List<Connection> connections, Vector3 center, Quaternion rotation, Vector3 extents, Color color, float duration) {
            Vector3 forwardUpperLeft = center + rotation * extents.WithX(-extents.x);
            Vector3 forwardUpperRight = center + rotation * extents;
            Vector3 forwardLowerLeft = center + rotation * extents.WithX(-extents.x).WithY(-extents.y);
            Vector3 forwardLowerRight = center + rotation * extents.WithY(-extents.y);
            Vector3 backLowerRight = center + rotation * -extents.WithX(-extents.x);
            Vector3 backLowerLeft = center + rotation * -extents;
            Vector3 backUpperRight = center + rotation * -extents.WithX(-extents.x).WithY(-extents.y);
            Vector3 backUpperLeft = center + rotation * -extents.WithY(-extents.y);
            Utils.Segments(connections, forwardUpperLeft, forwardUpperRight, color, duration);
            Utils.Segments(connections, forwardLowerLeft, forwardLowerRight, color, duration);
            Utils.Segments(connections, forwardUpperLeft, forwardLowerLeft, color, duration);
            Utils.Segments(connections, forwardUpperRight, forwardLowerRight, color, duration);
            Utils.Segments(connections, backUpperLeft, backUpperRight, color, duration);
            Utils.Segments(connections, backLowerLeft, backLowerRight, color, duration);
            Utils.Segments(connections, backUpperLeft, backLowerLeft, color, duration);
            Utils.Segments(connections, backUpperRight, backLowerRight, color, duration);
            Utils.Segments(connections, forwardUpperLeft, backUpperLeft, color, duration);
            Utils.Segments(connections, forwardLowerLeft, backLowerLeft, color, duration);
            Utils.Segments(connections, forwardUpperRight, backUpperRight, color, duration);
            Utils.Segments(connections, forwardLowerRight, backLowerRight, color, duration);
        }
    }
    public static class ExtensionMethods {
        public static bool IsNullOrEmpty(this string value) => string.IsNullOrEmpty(value);
        public static bool IsReady(this Plugin plugin) => plugin != null && plugin.IsLoaded;
        public static Vector3 GetPointAround(this Vector3 position, float radius) {
            float angle = UnityEngine.Random.value * 360f;
            Vector3 pointAround = position;
            pointAround.x = position.x + radius * Mathf.Sin(angle * Mathf.Deg2Rad);
            pointAround.z = position.z + radius * Mathf.Cos(angle * Mathf.Deg2Rad);
            pointAround.y = position.y;
            pointAround.y = TerrainMeta.HeightMap.GetHeight(pointAround);
            return pointAround;
        }
    }
}

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