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

FREE SentryTurrets : 3.0.0 3.0.0

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Reflection;
using HarmonyLib;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using ProtoBuf;
using UnityEngine;
using VLB;
using Color = UnityEngine.Color;
using Debug = UnityEngine.Debug;

namespace Oxide.Plugins
{
    [Info("Sentry Turrets", "Tangerine", "3.0.0")]
    [Description("https://codefling.com/plugins/sentry-turrets")]
    public class SentryTurrets : RustPlugin
    { 
        #region Classes

        private class TurretRadialButton
        {
            public List<ButtonSettings> States;

            public TurretRadialButton(List<ButtonSettings> states)
            {
                States = states;
            }
            
            public TurretRadialButton(string spriteIcon, string command, string text)
            {
                States = new List<ButtonSettings>()
                {
                    new (spriteIcon, command, text)
                };

            }
            
            public ButtonSettings GetState(NPCAutoTurret turret, int state)
            {
                if (States.Count > 1)
                {
                    return States[turret.PeacekeeperMode() ? 1 : 0];
                }
                
                return States[state];
            }
            
            public struct ButtonSettings
            {
                public string SpriteIcon;
                public string Command;
                public string Text;

                public ButtonSettings(string spriteIcon, string command, string text)
                {
                    SpriteIcon = spriteIcon;
                    Command = command;
                    Text = text;
                }
            }
        }
        
        private class PlayerInteraction
        {
            public PlayerInteraction(BasePlayer player)
            {
                Player = player;
            }
                
            public NPCAutoTurret Turret;
            public BasePlayer Player;
            public RealTimeSince LastCheck;
            public bool WasHoldingDown;
            public float HoldDownTime;
            public bool HasInteraction;
            public bool HasRadial;

            public bool IsInteracting() => HasInteraction || HasRadial;

            public void Clear()
            {
                HasRadial = false;
                HasInteraction = false;
                WasHoldingDown = false;
                _plugin.DestroyUI_InteractBtn(Player);
                _plugin.DestroyUI_RadialBtn(Player);
                Turret = null;
            }

            public static PlayerInteraction Get(BasePlayer player)
            {
                var interactions = _plugin._playersInteractions;
                
                if (interactions.TryGetValue(player.userID, out var interaction) == false)
                {
                    interaction = new PlayerInteraction(player);
                    interactions.Add(player.userID, interaction);
                }

                return interaction;
            }
        }

        private class TurretProfile
        {
            [JsonProperty(PropertyName = "Key name, for command")]
            public string KeyName = "default";
            
            [JsonProperty(PropertyName = "Item display name")]
            public string DisplayName = "Sentry Turret";

            [JsonProperty(PropertyName = "Skin Id")]
            public ulong SkinId = 1587601905;
            
            [JsonProperty(PropertyName = "Is weapon required?")]
            public bool needsWeapon = false;
            
            [JsonProperty(PropertyName = "Can get damage")]
            public bool getDamage = true;

            [JsonProperty(PropertyName = "Required power")]
            public int requiredPower = 0; 

            [JsonProperty(PropertyName = "Authorize friends and team members")]
            public bool authorizeOthers = false;

            [JsonProperty(PropertyName = "Authorize tc members")]
            public bool authorizeByTC = false;

            [JsonProperty(PropertyName = "Amount of ammo for one spray (set to 0 for no-ammo mode)")]
            public int spray = 1;
            
            [JsonProperty(PropertyName = "Amount of ammo for one air spray (set to 0 for no-ammo mode)")]
            public int sprayAir = 1;
            
            [JsonProperty(PropertyName = "Range (normal turret - 30)")]
            public int range = 55;
            
            [JsonProperty(PropertyName = "Air Range (set to 0 to disable air mode")]
            public int airRange = 100;
            
            [JsonProperty(PropertyName = "Air Fire Rate Every N seconds (Default every 1 second)")]
            public float airFireRate = 1f;

            [JsonProperty(PropertyName = "Give back on ground missing")]
            public bool itemOnGroundMissing = true;

            [JsonProperty(PropertyName = "Health (normal turret - 1000)")]
            public float health = 1500;

            [JsonProperty(PropertyName = "Aim cone (normal turret - 4)")]
            public float aimCone = 2;
        }
        #endregion
        
        #region Vars

        private const string PrefabSentry = "assets/content/props/sentry_scientists/sentry.scientist.static.prefab";
        private const string PrefabSwitch = "assets/prefabs/deployable/playerioents/simpleswitch/switch.prefab";
        private const string PrefabRocketSam = "assets/prefabs/npc/sam_site_turret/rocket_sam.prefab";
        private const string ItemName = "autoturret";
        private const string SentryLootPanel = "autoturret";
        private const string Command = "sentryturrets.give";
        private const string ItemDisplayName = "Sentry Turret";
        private const string AmmoShortname = "ammo.rifle";
        private const string AirAmmoShortname = "ammo.rocket.sam";
        private static readonly Vector3 SwitchPosition = new Vector3(-0.65f, 0.25f, -0.4f);
        private static readonly Vector3 SwitchRotation = new Vector3(-50f, 220f, 0f);

        private readonly object _falseObject = false;
        private readonly object _trueObject = true;
        
        private Harmony _harmony;

        private static SentryTurrets _plugin;

        private readonly Dictionary<NPCAutoTurret, TurretComponent> _turrets = new ();
        private readonly Dictionary<ulong, PlayerInteraction> _playersInteractions = new ();

        [PluginReference] private Plugin TurretsExtended;
        
        private readonly List<TurretRadialButton> _turretRadialButtons = new ()
        {
            new TurretRadialButton("assets/icons/open.png", "UI_SentryTurrets open", "OPEN"),
            new TurretRadialButton(new List<TurretRadialButton.ButtonSettings>()
            {
                new ("assets/icons/peace.png", "UI_SentryTurrets mode", "PEACEKEEPER"),
                new ("assets/icons/target.png", "UI_SentryTurrets mode", "ATTACK ALL"),
            }),
            new TurretRadialButton("assets/icons/rotate.png", "UI_SentryTurrets rotate", "ROTATE"),
            new TurretRadialButton("assets/icons/friends_servers.png", "UI_SentryTurrets authorize", "AUTHORIZE\nFRIEND"),
            new TurretRadialButton("assets/icons/clear_list.png", "UI_SentryTurrets authorize_clear", "CLEAR\nAUTHORIZED"),
            new TurretRadialButton("assets/icons/deauthorize.png", "UI_SentryTurrets deauthorize_self", "DEAUTHORIZE"),
            // new TurretRadialButton("assets/icons/broadcast.png", "UI_SentryTurrets broadcast_id", "SET ID"),
        };
        #endregion

        #region Oxide Hooks

        private void Init()
        {
            _plugin = this;
            
            InterfaceManager.Init();
            
            cmd.AddConsoleCommand(Command, this, nameof(cmdGiveConsole));
            
            _harmony = new Harmony("sentryturrets.patch");
            _harmony.Patch(typeof(NPCAutoTurret).GetMethod("Ignore", BindingFlags.Public | BindingFlags.Instance),
                new HarmonyMethod(typeof(SentryTurrets).GetMethod(nameof(Patch_NPCAutoTurret_Ignore))));
            
            _harmony.Patch(typeof(NPCAutoTurret).GetMethod("FireGun", BindingFlags.Public | BindingFlags.Instance),
                new HarmonyMethod(typeof(SentryTurrets).GetMethod(nameof(Patch_NPCAutoTurret_FireGun))));
            
            _harmony.Patch(typeof(AutoTurret).GetMethod("TargetTick", BindingFlags.Public | BindingFlags.Instance),
                new HarmonyMethod(typeof(SentryTurrets).GetMethod(nameof(Patch_NPCAutoTurret_TargetTick))));
            
            //DrawUI_PickUpBar(BasePlayer.activePlayerList[0], 0.5f);
        }

        [HarmonyPrefix]
        public static bool Patch_NPCAutoTurret_TargetTick(AutoTurret __instance)
        {
            if (__instance is NPCAutoTurret npcAutoTurret == false)
                return true;

            var turretComponent = _plugin.GetTurretComponent(npcAutoTurret);
            if (turretComponent == null)
                return true;

            turretComponent.TargetTick();
            return false;
        }
        
        [HarmonyPrefix]
        public static bool Patch_NPCAutoTurret_FireGun(NPCAutoTurret __instance)
        {
            if (__instance.OwnerID == 0)
                return true;
            
            var turretComponent = _plugin.GetTurretComponent(__instance);
            if (turretComponent == null)
                return true;
            
            if (__instance.GetAttachedWeapon() != null)
                return true;

            if (turretComponent.ConfigDef.needsWeapon)
                return false;

            if (turretComponent.IsAirTarget(turretComponent.TurretOwner.target))
            {
                var speedMultiplier = turretComponent.TurretOwner.target is SamSite.ISamSiteTarget samSiteTarget ? samSiteTarget.SAMTargetType.speedMultiplier : 3f;
                if (turretComponent.ConfigDef.sprayAir > 0 && turretComponent.TakeItem("ammo.rocket.sam", turretComponent.ConfigDef.sprayAir) == 0)
                    return false;

                var targetTransform = turretComponent.TurretOwner.target.transform;
                var targetPosition = targetTransform.position + turretComponent.TurretOwner.target.GetWorldVelocity() * 0.1f;
                var turretPosition = turretComponent.TurretOwner.muzzleLeft.position;
                var targetDirection = targetPosition - turretPosition;
                turretComponent.FireProjectile(targetDirection, speedMultiplier);
                return false;
            }
            
            if(turretComponent.ConfigDef.spray == 0)
                return true;

            return turretComponent.TakeItem(AmmoShortname, turretComponent.ConfigDef.spray) != 0;
        }
        
        [HarmonyPrefix]
        public static bool Patch_NPCAutoTurret_Ignore(NPCAutoTurret __instance, ref bool __result)
        {
            if (__instance.OwnerID == 0)
                return true;
            
            __result = false;
            return false;
        }

        private void OnServerInitialized()
        {
            CheckExistingTurrets();
            
            if(TurretsExtended != null)
                Unsubscribe(nameof(OnSwitchToggle)); 
            
            StartPluginLoad(); 
        }

        private void Unload()
        {
            _plugin = null;
            _harmony.UnpatchAll(_harmony.Id);
        }

        private void OnEntityBuilt(Planner plan, GameObject go)
        {
            CheckPlacement(plan, go);
        }

        private object CanPickupEntity(BasePlayer player, NPCAutoTurret entity)
        {
            CheckPickup(player, entity);
            return _falseObject;
        }
        
        private object CanPickupEntity(BasePlayer player, ElectricSwitch entity)
        {
            var npcTurret = entity.GetParentEntity() as NPCAutoTurret;
            if (npcTurret == null)
                return null;
            
            CheckPickup(player, npcTurret);
            return _falseObject;
        }

        private object OnEntityGroundMissing(NPCAutoTurret turret)
        {
            if (turret.OwnerID == 0)
                return null;
            
            GroundMissing(turret);
            return _trueObject;
        }

        // private object OnBookmarkControl(ComputerStation station, BasePlayer player, string id, NPCAutoTurret turret)
        // {
        //     return _trueObject;
        // }

        private void OnSwitchToggle(ElectricSwitch entity, BasePlayer player)
        {
            var turret = entity.GetComponentInParent<NPCAutoTurret>();
            if (turret == null)
            {
                return;
            }

            var turretComponent = GetTurretComponent(turret);
            if (turretComponent == null)
                return;
            
            if (turret.authorizedPlayers.Any(x => x.userid == player.userID) == false)
            {
                player.ChatMessage("No permission");
                entity.SetSwitch(!entity.IsOn());
                return;
            }

            if (entity.GetCurrentEnergy() < turretComponent.ConfigDef.requiredPower)
            {
                player.ChatMessage("No power");
                entity.SetSwitch(!entity.IsOn());
                return;
            }

            var enabled = turret.IsOn();
            turret.RCEyes = turret.muzzlePos;
            turret.SetIsOnline(!enabled);
            turret.SetFlag(BaseEntity.Flags.Reserved8, !enabled);
            turret.SendNetworkUpdate();
        }
        
        #endregion
        
        #region Commands

        private void cmdGiveConsole(ConsoleSystem.Arg arg)
        {
            if (arg.IsAdmin == false)
            {
                SendReply(arg, "You don't have access to that command!");
                return;
            }

            var args = arg.Args;
            if (args == null || args?.Length == 0)
            {
                SendReply(arg, "Usage: sentryturrets.give {steamID / Name} {amount} {profile key}");
                return;
            }
            
            var player = FindPlayer(args[0]);
            if (player == null)
                return;

            var amount = arg.GetInt(1, 1);
            
            var profileName = arg.GetString(2, "default");
            if (string.IsNullOrEmpty(profileName))
                return;

            var profile = _config.Profiles.Find(x => x.KeyName == profileName);
            if (profile == null)
                return;
            
            GiveItem(player, amount, profile.SkinId);
        }

        [ConsoleCommand("UI_SentryTurrets")]
        private void Console_UISentryTurrets(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player == null)
                return;

            var interaction = PlayerInteraction.Get(player);
            var turret = interaction.Turret;
            
            DestroyUI_RadialBtn(player, interaction);
            
            switch (arg.GetString(0))
            {
                case "radial_close":
                {
                    break;
                }
                
                case "open":
                {
                    turret.PlayerOpenLoot(player);
                    break;
                }
                
                case "mode":
                {
                    turret.SetPeacekeepermode(!turret.PeacekeeperMode());
                    break;
                }
                
                case "rotate":
                {
                    var turretTransform = turret.transform;
                    turretTransform.rotation = Quaternion.LookRotation(-turretTransform.forward, turretTransform.up);
                    turret.SendNetworkUpdate();
                    break;
                }
                
                case "authorize":
                {
                    if (arg.Args.Length < 2)
                    {
                        DrawUI_AuthFriend(player);
                        break;
                    }

                    var input = string.Join(" ", arg.Args.Skip(1));
                    DrawUI_AuthPlayersList(player, input);
                    
                    break;
                }
                
                case "authorizeid":
                {
                    var userId = arg.GetUInt64(1);
                    if (userId.IsSteamId() == false)
                        break;

                    turret.AddSelfAuthorize(BasePlayer.FindAwakeOrSleepingByID(userId));  
                    break;
                }
                
                case "authorize_clear":
                {
                    turret.authorizedPlayers.Clear();
                    turret.authDirty = true;
                    turret.UpdateMaxAuthCapacity();
                    turret.SendNetworkUpdate();
                    break;
                }
                
                case "deauthorize_self":
                {
                    turret.authorizedPlayers.RemoveWhere(x => x.userid == player.userID);
                    turret.authDirty = true;
                    turret.UpdateMaxAuthCapacity();
                    turret.SendNetworkUpdate();
                    break;
                }
                
                // case "broadcast_id":
                // {
                //     CuiHelper.DestroyUi(player, InterfaceManager.UI_LayerWindow);
                //     
                //     if (arg.Args.Length < 2)
                //     {
                //         DrawUI_SetRemoteId(player, turret.rcIdentifier);
                //         break;
                //     }
                //
                //     var id = arg.GetString(1);
                //     if (string.IsNullOrEmpty(id))
                //         break;
                //
                //     Puts($"ID: {id} {RemoteControlEntity.allControllables.Contains(turret)}");
                //     turret.UpdateIdentifier(id);
                //     break;
                // }
            }
        }
        #endregion

        #region Core
        
        private void GroundMissing(NPCAutoTurret turret)
        {
            var turretComp = GetTurretComponent(turret);
            if (turretComp == null)
                return;
            
            var position = turret.transform.position;
            
            turret.Kill();
            
            Effect.server.Run("assets/bundled/prefabs/fx/item_break.prefab", position);
            
            if (turretComp.ConfigDef.itemOnGroundMissing)
            {
                _plugin.DropItem(turretComp.ConfigDef.SkinId, position, turret.healthFraction);
            }
        }
        
        private void CheckExistingTurrets()
        {
            foreach (var entity in BaseNetworkable.serverEntities)
            {
                if (entity is NPCAutoTurret turret == false)
                    continue;

                if (turret.OwnerID == 0)
                    continue;
                
                SetupTurret(turret);
            }
        }

        private void CheckPickup(BasePlayer player, NPCAutoTurret entity)
        {
            var component = GetTurretComponent(entity);
            if (component == null)
                return;
            
            var items = entity.inventory?.itemList.ToArray() ?? new Item[]{};
            
            foreach (var item in items)
            {
                player.GiveItem(item);
            }

            var healthFrac = entity.healthFraction;
            entity.Kill();
            GiveItem(player, 1, component.ConfigDef.SkinId, healthFrac);
        }

        private void CheckPlacement(Planner plan, GameObject go)
        {
            var entity = go.ToBaseEntity() as AutoTurret;
            if (entity == null)
                return;
            
            if (entity.skinID == 0)
                return;

            var turretProfile = _config.Profiles.Find(x => x.SkinId == entity.skinID);
            if (turretProfile == null)
                return;

            var player = plan.GetOwnerPlayer();
            if (player == null)
                return;

            var item = plan.GetItem();

            var transform = entity.transform;
            var position = transform.position;
            var rotation = transform.rotation;
            var owner = entity.OwnerID;
            NextTick(()=> { entity.Kill();});
            var turret = GameManager.server.CreateEntity(PrefabSentry, position, rotation)?.GetComponent<NPCAutoTurret>();
            if (turret == null)
            {
                GiveItem(player, 1, entity.skinID);
                return;
            }
            
            turret.rcIdentifier = turretProfile.KeyName; 
            turret.OwnerID = owner;
            turret.Spawn();
            turret.SetIsOnline(false);
            turret.SetPeacekeepermode(false);
            turret.AttachToBuilding(entity.buildingID);
            turret.AddSelfAuthorize(player);
            SetupTurret(turret);
            turret.SetHealth(turret.MaxHealth() * item.conditionNormalized);
        }

        private void SetupTurret(NPCAutoTurret turret)
        {
            var turretCfg = _config.Profiles.Find(x => x.KeyName == turret.rcIdentifier);
            if (turretCfg == null)
            {
                turret.Kill();
                return;
            }
            
            turret.sightRange = turretCfg.range;
            turret.targetTrigger.GetComponent<SphereCollider>().radius = turret.sightRange;
            turret.aimCone = turretCfg.aimCone;
            AuthorizeOthers(turret.OwnerID, turret);
            
            if (turret.socketTransform == null)
                turret.socketTransform = turret.muzzlePos;
            
            timer.Once(0.5f, () =>
            {
                CheckSwitch(turret); 
                var component = new GameObject().AddComponent<TurretComponent>();
                component.gameObject.transform.SetParent(turret.transform, false);
                component.ConfigDef = turretCfg;
                _turrets.Add(turret, component);
            });
            
            turret.SendNetworkUpdate();
        }

        private void CheckSwitch(BaseEntity turret)
        {
            var entity = turret.GetComponentInChildren<ElectricSwitch>();
            if (entity == null)
            {
                entity = GameManager.server.CreateEntity(PrefabSwitch, turret.transform.position, Quaternion.identity) as ElectricSwitch;
                if (entity == null)
                {
                    PrintError("Failed to spawn turret switch");   
                    return;
                }
                
                entity.Spawn();
                entity.SetParent(turret, true);
                entity.transform.localPosition = SwitchPosition;
                entity.transform.localRotation = Quaternion.Euler(SwitchRotation);
                entity.SendNetworkUpdate();
            }
            
            entity.InitializeHealth(100 * 1000, 100 * 1000);
            entity.pickup.enabled = false;
        }

        private TurretComponent GetTurretComponent(NPCAutoTurret turret)
        {
            return _turrets.GetValueOrDefault(turret);
        }

        private Item CreateItem(ulong skinId, int amount = 1)
        {
            var item = ItemManager.CreateByName(ItemName, Math.Max(amount, 1), skinId);
            if (item == null)
            {
                return null;
            }
            
            item.name = ItemDisplayName;
            return item;
        }
        
        private void DropItem(ulong skinId, Vector3 position, float healthFraction)
        {
            var item = CreateItem(skinId);
            if (item == null)
            {
                return;
            }

            item.condition = item.maxCondition * healthFraction;
            
            item.Drop(position, Vector3.down);  
        } 

        private void GiveItem(BasePlayer player, int amount, ulong skinId, float healthFraction = 1f)
        {
            var item = CreateItem(skinId, amount);
            if (item == null)
            {
                return;
            }
            
            item.condition = item.maxCondition * healthFraction;
            
            player.GiveItem(item);
            Puts($"Turret was gave successfully to {player.displayName}");
        }

        private BasePlayer FindPlayer(string nameOrID)
        {
            var targets = BasePlayer.activePlayerList.Where(x => x.UserIDString == nameOrID || x.displayName.ToLower().Contains(nameOrID.ToLower())).ToList();
            
            if (targets.Count == 0)
            {
                Puts("There are no players with that Name or steamID!");
                return null;
            }

            if (targets.Count > 1)
            {
                Puts($"There are many players with that Name:\n{targets.Select(x => x.displayName).ToSentence()}");
                return null;
            }

            return targets[0];
        }
        
        private void AuthorizeOthers(ulong userID, NPCAutoTurret entity)
        {
            var turretComponent = GetTurretComponent(entity);
            if (turretComponent == null)
                return;
            
            if (turretComponent.ConfigDef.authorizeOthers == true)
            {
                var team = RelationshipManager.ServerInstance.teams.FirstOrDefault(x => x.Value.members.Contains(userID)).Value;
                if (team?.members != null)
                {
                    foreach (var member in team.members)
                    {
                        entity.authorizedPlayers.Add(new PlayerNameID
                        {
                            userid = member,
                            username = "Player"
                        });
                    }
                }
            
                var friends = GetFriends(userID.ToString());
                if (friends != null)
                {
                    foreach (var friend in friends)
                    {
                        var friendID = (ulong) 0;
                        if (ulong.TryParse(friend, out friendID) == true)
                        {
                            entity.authorizedPlayers.Add(new PlayerNameID
                            {
                                userid = friendID,
                                username = "Player"
                            });
                        }
                    }
                }
            }

            if (turretComponent.ConfigDef.authorizeByTC == true)
            {
                var tc = entity.GetBuildingPrivilege();
                if (tc != null)
                {
                    foreach (var value in tc.authorizedPlayers)
                    {
                        entity.authorizedPlayers.Add(value);
                    }
                }
            }

            entity.authorizedPlayers = entity.authorizedPlayers.Distinct().ToHashSet();
        }
        
        private static string GetColor(string hex, float alpha = 1f)
        {
            if (hex.Length != 7) hex = "#FFFFFF";
            if (alpha < 0 || alpha > 1f) alpha = 1f;

            var color = ColorTranslator.FromHtml(hex);
            var r = Convert.ToInt16(color.R) / 255f;
            var g = Convert.ToInt16(color.G) / 255f;
            var b = Convert.ToInt16(color.B) / 255f;

            return $"{r} {g} {b} {alpha}";
        }
        #endregion
        
        #region Configuration 2.0.0

        private static ConfigData _config = new ConfigData();

        private class ConfigData
        {
            [JsonProperty("Turrets profiles", ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public List<TurretProfile> Profiles = new List<TurretProfile>()
            {
                new TurretProfile() 
            };
        }

        protected override void LoadConfig() 
        {
            base.LoadConfig();

            try
            {
                _config = Config.ReadObject<ConfigData>();   
                if (_config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                for (var i = 0; i < 3; i++)
                {
                    PrintError("Configuration file is corrupt! Check your config file at https://jsonlint.com/");
                }
                
                LoadDefaultConfig(); 
                return;
            }

            ValidateConfig();
            SaveConfig(); 
        }

        private void ValidateConfig()
        {
            if (Interface.Oxide.CallHook("OnConfigValidate") != null)
            {
                PrintWarning("Using default configuration...");
                LoadDefaultConfig();
            }
        }

        protected override void LoadDefaultConfig()
        {
            _config = new ConfigData();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(_config);
        }

        #endregion
        
        #region Ddraw

        internal static class DDraw
        {
            public static void Line(BasePlayer player, float duration = 0.5f, Color? color = null,
                Vector3? from = null, Vector3? to = null)
            {
                player.SendConsoleCommand("ddraw.line", duration, Format(color), Format(from), Format(to));
            }

            public static void Arrow(BasePlayer player, float duration = 0.5f, Color? color = null,
                Vector3? from = null, Vector3? to = null, float headSize = 0f)
            {
                player.SendConsoleCommand("ddraw.arrow", duration, Format(color), Format(from), Format(to), headSize);
            }

            public static void Sphere(BasePlayer player, float duration = 0.5f, Color? color = null,
                Vector3? from = null, string text = "")
            {
                player.SendConsoleCommand("ddraw.sphere", duration, Format(color), Format(from), text);
            }

            public static void Text(BasePlayer player, float duration = 0.5f, Color? color = null,
                Vector3? from = null, string text = "")
            {
                player.SendConsoleCommand("ddraw.text", duration, Format(color), Format(from), text);
            }

            public static void Box(BasePlayer player, float duration = 0.5f, Color? color = null,
                Vector3? from = null, float size = 0.1f)
            {
                player.SendConsoleCommand("ddraw.box", duration, Format(color), Format(from), size);
            }

            private static string Format(Color? color) => ReferenceEquals(color, null)
                ? string.Empty
                : $"{color.Value.r},{color.Value.g},{color.Value.b},{color.Value.a}";

            private static string Format(Vector3? pos) => ReferenceEquals(pos, null)
                ? string.Empty
                : $"{pos.Value.x} {pos.Value.y} {pos.Value.z}";
        }

        #endregion
        
        #region Scripts
        
        private class TurretInput : MonoBehaviour
        {
            private NPCAutoTurret _turret;
            private readonly HashSet<PlayerInteraction> _players = new ();

            #region Events

            private void Start()
            {
                _turret = GetComponentInParent<NPCAutoTurret>();
                SetupBoxCollider();
            }

            private void OnTriggerStay(Collider other)
            {
                try
                {
                    var player = other.ToBaseEntity() as BasePlayer;
                    if (player == null)
                        return;

                    TriggerTick(player);
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }
            }
            
            private void OnTriggerExit(Collider other)
            {
                var player = other.ToBaseEntity() as BasePlayer;
                if (player == null)
                    return;

                _plugin.DestroyUI_InteractBtn(player);
                var interaction = PlayerInteraction.Get(player);
                if(interaction.Turret == _turret)
                    interaction.Clear();
                
                _players.Remove(interaction);
            }

            #endregion
            
            #region Utils

            private void SetupBoxCollider()
            {
                var collider = this.gameObject.AddComponent<BoxCollider>();
                var pos = collider.transform.position;
                collider.transform.position = pos.WithY(pos.y + 1f); 
                collider.size = new Vector3(4f, 4f, 4f);
                collider.gameObject.layer = (int)Rust.Layer.Reserved1;
                collider.isTrigger = true;
            } 
            
            private void TriggerTick(BasePlayer player)
            {
                var interaction = PlayerInteraction.Get(player);

                _players.Add(interaction);

                if (interaction.Turret != _turret)
                {
                    interaction.Clear();
                    interaction.Turret = _turret;
                }
                
                InputCheck(interaction);
                
                if (interaction.LastCheck < 0.5f)
                    return;

                interaction.LastCheck = 0f;

                if (CanSeeInteraction(player) == false)
                {
                    if (interaction.HasInteraction == false) 
                        return;
                    
                    _plugin.DestroyUI_InteractBtn(player);                
                    _plugin.DestroyUI_RadialBtn(player);
                    return;
                }
                
                if (interaction.IsInteracting()) 
                    return;
                
                _plugin.DrawUI_InteractionBtn(player, _turret.IsAuthed(player));
            }

            private void InputCheck(PlayerInteraction interaction)
            {
                var player = interaction.Player;
                
                if (interaction.HasInteraction == false)
                    return;
                
                var playerInput = player.serverInput;
                
                if(interaction.WasHoldingDown == false && playerInput.WasJustReleased(BUTTON.USE))
                {
                    if (AuthorizeAttempt(player))
                        return;
                    
                    if (interaction.HasRadial)
                    {
                        interaction.HasInteraction = false;
                        _plugin.DestroyUI_RadialBtn(player);
                        return;
                    }
                    
                    _turret.PlayerOpenLoot(player);
                }

                if (interaction.WasHoldingDown)
                {
                    CuiHelper.DestroyUi(player, InterfaceManager.UI_LayerBtn);
                }
                
                interaction.WasHoldingDown = false;

                
                if (playerInput.WasDown(BUTTON.USE) && playerInput.IsDown(BUTTON.USE))
                {
                    if (AuthorizeAttempt(player))
                        return;
                    
                    interaction.HoldDownTime += Time.deltaTime;
                    if (interaction.HoldDownTime < 0.2f) 
                        return;
                    
                    interaction.WasHoldingDown = true;
                    OnHoldDown(player, interaction);

                    return;
                }
                
                interaction.HoldDownTime = 0;
            }

            private bool AuthorizeAttempt(BasePlayer player)
            {
                if (_turret.IsAuthed(player) != false) 
                    return false;
                
                _turret.AddSelfAuthorize(player);
                _plugin.DrawUI_InteractionBtn(player, _turret.IsAuthed(player));
                return true;
            }

            private void OnHoldDown(BasePlayer player, PlayerInteraction interaction)
            {
                if (player.GetActiveItem()?.info.shortname == "hammer")
                {
                    _plugin.DrawUI_PickUpBar(player, interaction.HoldDownTime / 1f);
                    if (interaction.HoldDownTime > 1)
                    {
                        CuiHelper.DestroyUi(player, InterfaceManager.UI_LayerBtn);
                        _plugin.GiveItem(player, 1, _plugin.GetTurretComponent(_turret).ConfigDef.SkinId);
                        _turret.Kill();
                    }
                    
                    return;
                }
                
                if (interaction.HasRadial)
                    return;
            
                _plugin.DrawUI_RadialBtn(player);
                _plugin.DestroyUI_InteractBtn(player);
            }

            private bool CanSeeInteraction(BasePlayer player)
            {
                if (_turret.IsOn())
                    return false;
                
                if (Physics.Raycast(player.eyes.HeadRay(), out var hit, 4f) == false)
                    return false;

                if (hit.GetEntity() != _turret)
                    return false;

                return true;
            }

            #endregion
        }
        
        private class TurretComponent : MonoBehaviour
        {
            public NPCAutoTurret TurretOwner;
            private ElectricSwitch eSwitch;
            private TurretInput _turretInput;
            public TurretProfile ConfigDef;
            public TargetTrigger AirTrigger;
            
            private readonly int TurretVisibilityMask = LayerMask.GetMask("Construction", "World", "Terrain");

            #region Events

            private void Start()
            {
                TurretOwner = GetComponentInParent<NPCAutoTurret>();
                if (TurretOwner == null)
                {
                    Destroy(gameObject);
                    return;
                }
                
                eSwitch = TurretOwner.GetComponentInChildren<ElectricSwitch>(); 
                
                TurretOwner.GetOrAddComponent<GroundWatch>();
                TurretOwner.GetOrAddComponent<DestroyOnGroundMissing>();
                
                InvokeRepeating(nameof(DoChecks), 2f, 2f);

                _turretInput = new GameObject().AddComponent<TurretInput>();
                _turretInput.transform.SetParent(transform, false);
                
                TurretOwner.SetFlag(BaseEntity.Flags.Busy, true);

                SetupProtection();
                SetupContainer();
                SetupAirTriggerCollider(); 
            }

            #endregion


            #region Ticks

            private void DoChecks()
            {
                try
                {
                    if (_plugin == null || _plugin.IsLoaded == false)
                    {
                        Kill();
                        return;
                    }
                
                    CheckPower();
                    CheckTarget();
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }
            }
            
            #endregion

            #region Utils

            private void CheckTarget()
            {
                if (ConfigDef.airRange == 0)
                    return;

                if (TurretOwner.IsOn() == false)
                    return;

                if (TurretOwner.HasTarget() && IsAirTarget(TurretOwner.target) && IsValidAirTarget(TurretOwner.target) == false)
                {
                    TurretOwner.SetTarget(null);
                }
                
                if ((AirTrigger.entityContents?.Count ?? 0) == 0) 
                    return;  
                
                foreach (var airTriggerEntityContent in AirTrigger.entityContents)
                {
                    OnEntityEnterTrigger(airTriggerEntityContent);
                }
            }
            
            private void CheckPower()
            {
                if (HasPower())
                {
                    return;
                }
                
                TurretOwner.SetIsOnline(false);
            }

            private bool HasPower()
            {
                return eSwitch != null && eSwitch.GetCurrentEnergy() >= ConfigDef.requiredPower;
            }
            
            private void SetupAirTriggerCollider()
            {
                if (ConfigDef.airRange == 0)
                    return;
                
                var collider = gameObject.AddComponent<SphereCollider>();
                var turretCollider = TurretOwner.targetTrigger.GetComponent<SphereCollider>();

                collider.excludeLayers = turretCollider.excludeLayers;
                collider.isTrigger = true;
                collider.radius = ConfigDef.airRange;
                collider.gameObject.layer = TurretOwner.targetTrigger.gameObject.layer;
                
                AirTrigger = collider.gameObject.AddComponent<TargetTrigger>();
                AirTrigger.interestLayers = LayerMask.GetMask("Vehicle World");
                AirTrigger.OnEntityEnterTrigger += OnEntityEnterTrigger;
            }

            private void OnEntityEnterTrigger(BaseNetworkable obj)
            {
                if (TurretOwner.HasTarget() || TurretOwner.IsOn() == false)
                    return;

                if (obj is BaseCombatEntity combatEntity == false)
                    return;

                if (IsValidAirTarget(combatEntity) == false)
                    return;
                
                TurretOwner.SetTarget(combatEntity); 
            }

            public bool IsAirTarget(BaseCombatEntity target)
            {
                switch (target)
                {
                    case PatrolHelicopter:
                        return true;
                    
                    case SamSite.ISamSiteTarget samSiteTarget:
                        return true;
                }

                return false;
            }
            
            private bool IsValidAirTarget(BaseCombatEntity target)
            {
                switch (target)
                {
                    case PatrolHelicopter:
                        return true;
                    
                    case SamSite.ISamSiteTarget samSiteTarget:
                        if (samSiteTarget.IsValidSAMTarget(false) == false)
                            break;

                        if (IsVisible(target, TurretOwner.muzzleLeft.position, target.transform.position, ConfigDef.airRange)) 
                            break;

                        return true;
                }

                return false;
            }
            
            private bool IsVisible(BaseEntity entity, Vector3 position, Vector3 target, float maxDistance = float.PositiveInfinity)
            {
                var targetDirection = target - position;
                var magnitude = targetDirection.magnitude;
                if (magnitude < Mathf.Epsilon)
                    return true;
                
                var direction = targetDirection / magnitude;
                var directionMagnitude = direction * Mathf.Min(magnitude, 0.01f);
                maxDistance = Mathf.Min(maxDistance, magnitude + 0.2f);
                return entity.IsVisible(new Ray(position + directionMagnitude, direction), TurretVisibilityMask, maxDistance);
            }
            
            public void Kill()
            {
                Destroy(gameObject);
            }

            private void SetupContainer()
            {
                TurretOwner.inventory.entityOwner = TurretOwner;
                TurretOwner.inventory.capacity = 7;
                TurretOwner.inventory.canAcceptItem = CanAcceptItem;
                TurretOwner.inventory.onItemAddedRemoved = TurretOwner.OnItemAddedOrRemoved;
                TurretOwner.dropsLoot = false;
                TurretOwner.lootPanelName = SentryLootPanel;
            }

            private bool CanAcceptItem(Item item, int targetSlot)
            {
                if (ConfigDef.airRange > 0 && targetSlot > 0 && item.info.shortname == "ammo.rocket.sam")
                {
                    return true;
                }
                
                if(ConfigDef.needsWeapon)
                    return TurretOwner.CanAcceptItem(item, targetSlot);
                
                if (targetSlot > 0 && TurretOwner.GetAttachedWeapon() == null)
                {
                    if (item.info.shortname == "ammo.rifle")
                        return true;

                    return false;
                }
                
                return TurretOwner.CanAcceptItem(item, targetSlot);
            }
            
            
            private void SetupProtection()
            {
                var health = ConfigDef.health;
                TurretOwner._maxHealth = health;
                TurretOwner.health = health;
            
                if (ConfigDef.getDamage == true)
                {
                    TurretOwner.baseProtection = ScriptableObject.CreateInstance<ProtectionProperties>();
                    TurretOwner.baseProtection.amounts = new float[]
                    {
                        1,1,1,1,1,0.8f,1,1,1,0.9f,0.5f,
                        0.5f,1,1,0,0.5f,0,1,1,0,1,0.9f
                    };
                }
            }

            private RealTimeSince _lastAirFire;
            
            public void FireProjectile(Vector3 direction, float speedMultiplier)
            {
                if (_lastAirFire < ConfigDef.airFireRate)
                    return;

                _lastAirFire = 0;
                
                var entity = GameManager.server.CreateEntity(PrefabRocketSam, TurretOwner.muzzleLeft.position + TurretOwner.aimDir * 2.5f, Quaternion.LookRotation(direction, Vector3.up));
                if (entity == null)
                    return;
                
                entit
// ... [Code preview truncated due to length. Full source in attached file] ...

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