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

FREE AutomatedSearchlights : 0.1.6 0.1.6

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

namespace Oxide.Plugins
{
    [Info("AutomatedSearchlights", "k1lly0u", "0.1.6", ResourceId = 0)]
    class AutomatedSearchlights : RustPlugin
    {
        #region Fields
        [PluginReference] Plugin Friends;
        [PluginReference] Plugin Clans;

        static AutomatedSearchlights ins;

        StoredData storedData;
        private DynamicConfigFile data;

        private Dictionary<ulong, List<uint>> lightCache = new Dictionary<ulong, List<uint>>();
        private List<Follower> searchLights = new List<Follower>();
        private bool wipeData;
        private bool isNight;

        private static LayerMask layerMask;
        private static FieldInfo secondsRemaining = typeof(SearchLight).GetField("secondsRemaining", (BindingFlags.Instance | BindingFlags.NonPublic));
        private static FieldInfo direction = typeof(SearchLight).GetField("aimDir", (BindingFlags.Instance | BindingFlags.NonPublic));

        const string perm = "automatedsearchlights.use";
        #endregion

        #region Oxide Hooks
        void Loaded()
        {
            lang.RegisterMessages(Messages, this);
            permission.RegisterPermission("automatedsearchlights.use", this);
            data = Interface.Oxide.DataFileSystem.GetFile("searchlight_data");
            ins = this;
        }
        void OnServerInitialized()
        {
            layerMask = (1 << 29);
            layerMask |= (1 << 18);
            layerMask = ~layerMask;

            LoadVariables();
            LoadData();

            if (wipeData)
            {
                PrintWarning("Map wipe detected! Clearing saved autolight data");
                lightCache.Clear();
                SaveData();
            }

            FindAllLights();
        }
        void OnEntityKill(BaseNetworkable networkable)
        {
            var searchLight = networkable.GetComponent<SearchLight>();
            if (searchLight == null) return;

            if (searchLight.GetComponent<Follower>())
            {
                foreach(var list in lightCache)
                {
                    if (list.Value.Contains(searchLight.net.ID))
                    {
                        list.Value.Remove(searchLight.net.ID);
                        UnityEngine.Object.Destroy(searchLight.GetComponent<Follower>());
                        return;
                    }
                }
            }
        }
        void OnNewSave(string filename) => wipeData = true;
        void Unload()
        {
            SaveData();
            var objects = UnityEngine.Object.FindObjectsOfType<Follower>();
            if (objects != null)
            {
                foreach (var obj in objects)
                    UnityEngine.Object.Destroy(obj);
            }            
        }
        void OnServerShutdown()
        {
            SaveData();
            var objects = UnityEngine.Object.FindObjectsOfType<Follower>();
            if (objects != null)
            {
                foreach (var obj in objects)
                    UnityEngine.Object.Destroy(obj);
            }            
        }
        void OnServerSave() => SaveData();
        #endregion

        #region Component
        class Follower : MonoBehaviour
        {
            private SearchLight entity;
            private SphereCollider collider;
            private ConfigData data;

            private List<BaseCombatEntity> inRange = new List<BaseCombatEntity>();
            private BaseCombatEntity target;
            
            private bool resetSearch = true;
            private float nextIdleAimTime;
            private float secondsTaken;

            private Vector3 centerPoint;
            private Vector3 rightPoint;
            private Vector3 leftPoint;

            private Aim lastAim = Aim.Center;

            private Vector3 currentAim = Vector3.zero;
            private Vector3 nextAim;

            private float flickerHealth;

            private void Awake()
            {
                entity = GetComponent<SearchLight>();
                data = ins.configData;

                enabled = false;

                if (!data.DetectionOptions.Animals)
                {
                    collider = entity.gameObject.AddComponent<SphereCollider>();
                    collider.gameObject.layer = (int)Layer.Reserved1;
                    collider.radius = data.DetectionOptions.Radius;
                    collider.isTrigger = true;
                }
                else InvokeRepeating("CheckEntites", 0.1f, 3f);

                if (!data.OtherOptions.ConsumeFuel)                                    
                    secondsRemaining.SetValue(entity, 20);

                if (data.OtherOptions.Flicker)
                    flickerHealth = entity.MaxHealth() * data.OtherOptions.FlickerHealth;

                SetAimPoints();
            }
            private void FixedUpdate()
            {                
                if (IsInUse()) return;
                if (!HasFuel()) return;
                if (target == null && inRange.Count > 0)                
                    FindValidTarget();

                if (!data.OtherOptions.Flicker)
                {
                    if (!entity.IsOn())
                        entity.SetFlag(BaseEntity.Flags.On, true);
                }
                else
                {
                    if (entity.health <= flickerHealth)
                    {
                        if (entity.health <= flickerHealth / 2)
                            entity.SetFlag(BaseEntity.Flags.On, UnityEngine.Random.Range(1, 5) != 2);
                        else entity.SetFlag(BaseEntity.Flags.On, UnityEngine.Random.Range(1, 10) != 2);
                    }
                }

                if (target == null)
                {
                    if (resetSearch || UnityEngine.Time.realtimeSinceStartup > nextIdleAimTime)
                    {
                        resetSearch = false;
                        nextIdleAimTime = UnityEngine.Time.realtimeSinceStartup + data.OtherOptions.SearchSpeed;

                        var currentRot = Quaternion.LookRotation((Vector3)direction.GetValue(entity));

                        RaycastHit rayHit;
                        if (Physics.Raycast(new Ray(entity.transform.position + (Vector3.up * 2), currentRot * Vector3.forward), out rayHit, 1000f, layerMask))
                            currentAim = rayHit.point;

                        nextAim = GetNext();

                        secondsTaken = 0;
                    }
                    secondsTaken = secondsTaken + UnityEngine.Time.deltaTime;
                    var single = Mathf.InverseLerp(0f, data.OtherOptions.SearchSpeed, secondsTaken);
                    entity.SetTargetAimpoint(Vector3.Lerp(currentAim, nextAim, single));

                    entity.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
                    return;                  
                }
                else
                {
                    if (CastRay(target.transform.position) == null)
                    {
                        ClearTarget();
                        return;
                    }
                    entity.SetTargetAimpoint(target.transform.position);
                    entity.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
                }                
            }
            private void OnTriggerEnter(Collider col)
            {
                var player = col.GetComponentInParent<BasePlayer>();
                if (player != null)
                {
                    if (inRange.Contains(player)) return;

                    if (!data.DetectionOptions.Friends && (entity.OwnerID == player.userID || ins.IsClanmate(entity.OwnerID, player.userID) || ins.IsFriend(entity.OwnerID, player.userID))) return;
                    inRange.Add(player);
                }
                var helicopter = col.GetComponentInParent<BaseHelicopter>();
                if (helicopter != null)
                {
                    if (data.DetectionOptions.Helicopters || inRange.Contains(helicopter)) return;
                    inRange.Add(helicopter);
                }
            }
           
            private void OnTriggerExit(Collider col)
            {
                var combatEnt = col.GetComponentInParent<BaseCombatEntity>();
                if (combatEnt == null)
                    return;
                if (inRange.Contains(combatEnt))
                    inRange.Remove(combatEnt);
                if (target == combatEnt)
                    ClearTarget();
            }
            private void OnDestroy()
            {
                if (data.DetectionOptions.Animals)
                    InvokeHandler.CancelInvoke(this, CheckEntites);
                if (entity.IsOn())
                    entity.SetFlag(BaseEntity.Flags.On, false);
                Destroy(collider);                
            }
            private void CheckEntites()
            {                
                inRange.Clear();
                List<BaseCombatEntity> entities = Pool.GetList<BaseCombatEntity>();
                Vis.Entities<BaseCombatEntity>(entity.transform.position, data.DetectionOptions.Radius, entities);
                foreach (var ent in entities)
                {
                    if (ent.IsDead() || ent.IsDestroyed) continue;
                    if (ent is BasePlayer)
                    {
                        var player = ent as BasePlayer;
                        if (player != null)
                        {
                            if (!data.DetectionOptions.Friends && (entity.OwnerID == player.userID || ins.IsClanmate(entity.OwnerID, player.userID) || ins.IsFriend(entity.OwnerID, player.userID))) return;
                            inRange.Add(player);
                        }
                    }
                    if (ent is BaseNpc)
                    {
                        var animal = ent as BaseNpc;
                        if (animal != null && data.DetectionOptions.Animals)
                        {
                            inRange.Add(animal);
                        }
                    }
                    if (ent is BaseHelicopter)
                    {
                        var helicopter = ent as BaseHelicopter;
                        if (helicopter != null && data.DetectionOptions.Helicopters)
                        {
                            inRange.Add(helicopter);
                        }
                    }
                }
                Pool.FreeList(ref entities);

                if (target != null && !inRange.Contains(target))
                    target = null;
            }
            public void SetAimPoints()
            {
                centerPoint = entity.transform.position + ((entity.transform.forward * 75) + (-entity.transform.up * 50));
                rightPoint = entity.transform.position + ((entity.transform.forward * 100) + (-entity.transform.up * 50) + (entity.transform.right * 100));
                leftPoint = entity.transform.position + ((entity.transform.forward * 100) + (-entity.transform.up * 50) + (-entity.transform.right * 100));
            }
            private void FindValidTarget()
            {               
                for (int i = 0; i < inRange.Count; i++)
                {
                    var combatEnt = inRange[i];  
                    if (combatEnt == null || combatEnt.IsDead() || combatEnt.IsDestroyed)
                    {
                        inRange.RemoveAt(i);
                        continue;
                    }
                   
                    BaseCombatEntity hitEntity = CastRay(combatEnt.transform.position);
                    if (hitEntity != null)
                    {   
                        target = hitEntity;
                        return;
                    }
                }
                target = null;
            }          
            private void ClearTarget()
            {
                target = null;
                if (data.OtherOptions.InactiveSearch)
                {
                    resetSearch = true;
                }
                else
                {
                    if (entity.IsOn())
                        entity.SetFlag(BaseEntity.Flags.On, false);
                }
            }
            private bool HasFuel()
            {
                if (data.OtherOptions.ConsumeFuel)
                {
                    Item slot = entity.inventory.GetSlot(0);
                    if (slot == null || slot.info != entity.fuelType)
                        return false;
                }
                else
                {
                    float remaining = (float)secondsRemaining.GetValue(entity);
                    secondsRemaining.SetValue(entity, remaining + Time.deltaTime);
                }
                return true;
            }
            private bool IsInUse()
            {
                if (entity.IsMounted() || entity.HasFlag(BaseEntity.Flags.Reserved5))
                {
                    if (target != null)
                        ClearTarget();
                    resetSearch = true;
                    return true;
                }
                return false;
            }
           
            private BaseCombatEntity CastRay(Vector3 targetPos)
            {
                RaycastHit rayHit;
                if (Physics.SphereCast(new Ray(entity.transform.position + (Vector3.up * 2), targetPos - entity.transform.position), 1f, out rayHit, 500, layerMask))
                {
                    var hitPlayer = rayHit.collider?.GetComponentInParent<BaseCombatEntity>();
                    if (hitPlayer != null)
                    {
                        return hitPlayer;                        
                    }
                }
                return null;
            }
            public void Toggle(bool active)
            {
                if (!active)
                {
                    if (data.DetectionOptions.Animals && IsInvoking("CheckEntities"))
                        CancelInvoke("CheckEntites");

                    this.enabled = false;
                    target = null;

                    if (entity != null && entity.IsOn())
                        entity.SetFlag(BaseEntity.Flags.On, false);             
                }
                else
                {
                    this.enabled = true;
                    target = null;

                    if (entity != null && !entity.IsOn())
                        entity.SetFlag(BaseEntity.Flags.On, true);

                    if (data.DetectionOptions.Animals && !IsInvoking("CheckEntities"))
                        InvokeRepeating("CheckEntites", 0.1f, 3f);
                }
            }
            enum Aim { Left, Center, Right };
            private Vector3 GetNext()
            {
                switch (lastAim)
                {
                    case Aim.Left:
                        lastAim = Aim.Right;
                        return rightPoint;
                    case Aim.Center:
                        lastAim = Aim.Right;
                        return rightPoint;
                    case Aim.Right:
                        lastAim = Aim.Left;
                        return leftPoint;
                    default:
                        return centerPoint;
                }
            }
        }
        #endregion

        #region Functions
        void FindAllLights()
        {
            var lightList = new List<uint>();
            foreach (var lightSet in lightCache)
                lightList.AddRange(lightSet.Value);

            var lights = UnityEngine.Object.FindObjectsOfType<SearchLight>().Distinct();
            if (lights != null)
            {
                foreach(var light in lights)
                {
                    if (lightList.Contains(light.net.ID))
                    {
                        if (light.GetComponent<Follower>())
                            UnityEngine.Object.DestroyImmediate(light.GetComponent<Follower>());
                        var sLight = light.gameObject.AddComponent<Follower>();
                        searchLights.Add(sLight);
                    }
                }
            }
                      
            MonitorTime();
        }
        SearchLight FindLightFromRay(BasePlayer player)
        {
            Ray ray = new Ray(player.eyes.position, Quaternion.Euler(player.serverInput.current.aimAngles) * Vector3.forward);
            RaycastHit hit;
            if (!Physics.Raycast(ray, out hit, 20))
                return null;

            var hitEnt = hit.collider.GetComponentInParent<SearchLight>();
            if (hitEnt != null) 
                return hitEnt;            
            return null;
        }
        void MonitorTime()
        {
            if (!configData.OtherOptions.NightActive)
            {
                isNight = true;
                return;
            }
            var time = TOD_Sky.Instance.Cycle.Hour;
            var nightCheck = time >= configData.OtherOptions.NightStart || (time > 0 && time < configData.OtherOptions.NightEnd);

            if (nightCheck != isNight)
            {
                isNight = nightCheck;
                foreach (var light in searchLights)
                {
                    if (light != null)
                        light.Toggle(isNight);
                }
            }
           
            timer.In(5, MonitorTime);
        }
        #endregion

        #region Hooks
        private bool IsClanmate(ulong playerId, ulong friendId)
        {
            if (!Clans) return false;
            object playerTag = Clans?.Call("GetClanOf", playerId);
            object friendTag = Clans?.Call("GetClanOf", friendId);
            if ((playerTag is string && !string.IsNullOrEmpty((string)playerTag)) && (friendTag is string && !string.IsNullOrEmpty((string)friendTag)))
                if (playerTag == friendTag) return true;
            return false;
        }
        private bool IsFriend(ulong playerID, ulong friendID)
        {
            if (!Friends) return false;
            bool isFriend = (bool)Friends?.Call("IsFriend", playerID, friendID);
            return isFriend;
        }
        #endregion

        #region Commands
        [ChatCommand("sl")]
        void cmdSL(BasePlayer player, string command, string[] args)
        {
            if (!permission.UserHasPermission(player.UserIDString, perm)) return;
            if (args.Length == 0)
            {
                SendReply(player, $"<color=#ce422b>{Title}</color><color=#939393>  v{Version}  -</color> <color=#ce422b>{Author} @ www.chaoscode.io</color>");
                SendReply(player, msg("help1", player.UserIDString));
                SendReply(player, msg("help2", player.UserIDString));
                SendReply(player, msg("help3", player.UserIDString));
                SendReply(player, msg("help4", player.UserIDString));
                return;
            }
            SearchLight entity = FindLightFromRay(player);
            if (entity == null)
            {
                SendReply(player, msg("noLight", player.UserIDString));
                return;
            }
            switch (args[0].ToLower())
            {
                case "add":

                    if (entity.OwnerID != player.userID && !ins.IsClanmate(entity.OwnerID, player.userID) && !ins.IsFriend(entity.OwnerID, player.userID))
                    {
                        SendReply(player, msg("noOwner", player.UserIDString));
                        return;
                    }

                    if (!lightCache.ContainsKey(player.userID))
                        lightCache[player.userID] = new List<uint>();

                    if (lightCache[player.userID].Count >= configData.ManagementOptions.MaxSet)
                    {
                        SendReply(player, msg("maxLights", player.UserIDString));
                        return;
                    }                    
                    if (entity.GetComponent<Follower>())
                    {
                        SendReply(player, msg("alreadyLight", player.UserIDString));
                        return;
                    }

                    lightCache[player.userID].Add(entity.net.ID);
                    var light = entity.gameObject.AddComponent<Follower>();
                    searchLights.Add(light);
                    light.Toggle(isNight);
                    SendReply(player, msg("enabled", player.UserIDString));
                    SaveData();
                    return;
                case "remove":                    
                    if (entity.OwnerID != player.userID && !ins.IsClanmate(entity.OwnerID, player.userID) && !ins.IsFriend(entity.OwnerID, player.userID))
                    {
                        SendReply(player, msg("noOwner", player.UserIDString));
                        return;
                    }
                    if (!entity.GetComponent<Follower>())
                    {
                        SendReply(player, msg("notLight", player.UserIDString));
                        return;
                    }
                    if (!lightCache.ContainsKey(player.userID) || !lightCache[player.userID].Contains(entity.net.ID))
                    {
                        SendReply(player, msg("notAdded", player.UserIDString));
                        return;
                    }
                    UnityEngine.Object.Destroy(entity.GetComponent<Follower>());
                    lightCache[player.userID].Remove(entity.net.ID);                    
                    SendReply(player, msg("disabled", player.UserIDString));
                    SaveData();
                    return;
                case "rotate":
                    if (entity.OwnerID != player.userID && !ins.IsClanmate(entity.OwnerID, player.userID) && !ins.IsFriend(entity.OwnerID, player.userID))
                    {
                        SendReply(player, msg("noOwner", player.UserIDString));
                        return;
                    }
                    if (!entity.GetComponent<Follower>())
                    {
                        SendReply(player, msg("notLight", player.UserIDString));
                        return;
                    }
                    if (!lightCache.ContainsKey(player.userID) || !lightCache[player.userID].Contains(entity.net.ID))
                    {
                        SendReply(player, msg("notYours", player.UserIDString));
                        return;
                    }
                    var searchLight = entity.GetComponent<Follower>();
                    searchLight.Toggle(false);
                    searchLight.enabled = false;

                    var yRot = player?.eyes?.rotation.eulerAngles.y ?? 0;
                    entity.transform.eulerAngles = new Vector3(0, yRot, 0);

                    searchLight.SetAimPoints();
                    searchLight.Toggle(isNight);
                    SendReply(player, msg("rotSet", player.UserIDString));
                    return;
                default:
                    break;
            }
        }
        #endregion

        #region Config        
        private ConfigData configData;
        class Detection
        {
            [JsonProperty(PropertyName = "Search Radius")]
            public float Radius { get; set; }
            [JsonProperty(PropertyName = "Detect Animals")]
            public bool Animals { get; set; }
            [JsonProperty(PropertyName = "Detect Enemies")]
            public bool Enemies { get; set; }
            [JsonProperty(PropertyName = "Detect Friends")]
            public bool Friends { get; set; }
            [JsonProperty(PropertyName = "Detect Helicopters")]
            public bool Helicopters { get; set; }
        }
        class Management
        {
            [JsonProperty(PropertyName = "Maximum autolights per user")]
            public int MaxSet { get; set; }
            [JsonProperty(PropertyName = "Allow friends to set lights")]
            public bool AllowFriends { get; set; }
            [JsonProperty(PropertyName = "Allow clan mates to set lights")]
            public bool AllowClans { get; set; }
        }
        class Options
        {
            [JsonProperty(PropertyName = "Lights consume fuel")]
            public bool ConsumeFuel { get; set; }
            [JsonProperty(PropertyName = "Flicker - Flicker when damaged")]
            public bool Flicker { get; set; }
            [JsonProperty(PropertyName = "Flicker - Light health to cause flicker")]
            public float FlickerHealth { get; set; }
            [JsonProperty(PropertyName = "Search mode - Activate when nothing detected")]
            public bool InactiveSearch { get; set; }
            [JsonProperty(PropertyName = "Search mode - Rotation speed")]
            public float SearchSpeed { get; set; }
            [JsonProperty(PropertyName = "Automated at night time only")]
            public bool NightActive { get; set; }
            [JsonProperty(PropertyName = "Night start time")]
            public float NightStart { get; set; }
            [JsonProperty(PropertyName = "Night end time")]
            public float NightEnd { get; set; }
        }
        class ConfigData
        {
            public Detection DetectionOptions { get; set; }
            public Management ManagementOptions { get; set; }
            public Options OtherOptions { get; set; }            
        }
        private void LoadVariables()
        {
            LoadConfigVariables();
            SaveConfig();
        }
        protected override void LoadDefaultConfig()
        {
            var config = new ConfigData
            {
                DetectionOptions = new Detection
                {
                    Animals = true,
                    Enemies = true,
                    Friends = false,
                    Helicopters = true,
                    Radius = 25f
                },
                ManagementOptions = new Management
                {
                    AllowClans = true,
                    AllowFriends = true,
                    MaxSet = 3
                },
                OtherOptions = new Options
                {
                    ConsumeFuel = false,
                    Flicker = true,
                    FlickerHealth = 0.5f,
                    InactiveSearch = true,
                    SearchSpeed = 15f,
                    NightActive = true,
                    NightEnd = 8f,
                    NightStart = 19f
                }               
            };
            SaveConfig(config);
        }
        private void LoadConfigVariables() => configData = Config.ReadObject<ConfigData>();
        void SaveConfig(ConfigData config) => Config.WriteObject(config, true);
        #endregion

        #region Data Management
        void SaveData()
        {
            storedData.data = lightCache;
            data.WriteObject(storedData);
        }
        void LoadData()
        {
            try
            {
                storedData = data.ReadObject<StoredData>();
                lightCache = storedData.data;
            }
            catch
            {
                storedData = new StoredData();
            }
        }
        class StoredData
        {
            public Dictionary<ulong, List<uint>> data = new Dictionary<ulong, List<uint>>();
        }
        #endregion

        #region Localization
        string msg(string key, string playerId = "") => lang.GetMessage(key, this, playerId);
        Dictionary<string, string> Messages = new Dictionary<string, string>
        {
            {"help1", "<color=white>Все команды должны вводится при просмотре на прожектор!</color>" },
            {"help2", "<color=#ffd479>/sl add</color><color=white> - Включает прожектор в автоматическое состояние</color>" },
            {"help3", "<color=#ffd479>/sl remove</color><color=white> - Удалить автоматизацию с прожектора</color>" },
            {"help4", "<color=#ffd479>/sl rotate</color><color=white> - Переход прожектора на ручное управление</color>" },
            {"noLight", "<color=white>Не удалось найти прожектор!</color>"},
            {"noOwner", "<color=white>Этот прожектор не принадлежит вам!</color>"},
            {"maxLights", "<color=white>У вас уже достигнуто максимальное количество автоматизированных прожекторов!</color>"},
            {"alreadyLight", "<color=white>Этот прожектор уже автоматизирован!</color>"},
            {"enabled", "<color=white>Вы </color><color=green>включили</color><color=white> автоматизацию на прожекторе!</color>"},
            {"notLight", "<color=white>Этот прожектор не автоматизирован!</color>"},
            {"notAdded", "<color=white>Вы можете удалить тольке те прожекторы, которые установлены вами!</color>"},
            {"disabled", "<color=white>Вы </color><color=red>выключили</color><color=white> автоматизацию на прожекторе!</color>"},
            {"notYours", "<color=white>Вы можете регулировать тольке те прожекторы, которые установлены вами!</color>"},
            {"rotSet", "<color=white>Вращение настроено!</color>" }
        };
        #endregion
    }
}

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