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

FREE Pets : 0.5.5 0.5.5

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

using System.Collections.Generic;
using System;
using System.Reflection;

using Oxide.Core;

using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Pets", "Bombardir", "0.5.5", ResourceId = 851)]
    class Pets : RustPlugin
    {
        static Pets PluginInstance;
        static BUTTON MainButton;
        static BUTTON SecondButton;
        static Dictionary<ulong, PetInfo> SaveNpcList;
        public enum Act { Move, Attack, Eat, Follow, Sleep, None }

        #region NPC Controller Class

        public class NpcControl : MonoBehaviour
        {
            private readonly FieldInfo serverinput = typeof(BasePlayer).GetField("serverInput", (BindingFlags.Instance | BindingFlags.NonPublic));
            private float ButtonReload = 0.2f;
            private float DrawReload = 0.05f;
            internal static float LootDistance = 1f;
            internal static float ReloadControl = 60f;
            internal static float MaxControlDistance = 10f;

            internal bool DrawEnabled;
            InputState input;
            float NextTimeToPress;
            float NextTimeToControl;
            float NextTimeToDraw;

            public NpcAI npc;
            public BasePlayer owner;

            void Awake()
            {
                owner = GetComponent<BasePlayer>();
                input = serverinput.GetValue(owner) as InputState;
                enabled = false;
                NextTimeToPress = 0f;
                NextTimeToControl = 0f;
                NextTimeToDraw = 0f;
                DrawEnabled = GlobalDraw;
            }

            void OnAttacked(HitInfo info)
            {
                if (npc && info.Initiator && npc.action != Act.Attack)
                    npc.Attack(info.Initiator.GetComponent<BaseCombatEntity>());
            }

            void FixedUpdate()
            {
                var time = Time.realtimeSinceStartup;
                if (input.WasJustPressed(MainButton) && NextTimeToPress < time)
                {
                    NextTimeToPress = time + ButtonReload;
                    UpdateAction();
                }
                if (DrawEnabled && npc != null && npc.action < Act.Follow && NextTimeToDraw < time)
                {
                    NextTimeToDraw = time + DrawReload;
                    UpdateDraw();
                }
            }

            void UpdateDraw()
            {
                var drawpos = (npc.action == Act.Move ? npc.targetpoint : (npc.targetentity == null ? Vector3.zero : transform.position));
                if (drawpos != Vector3.zero)
                    owner.SendConsoleCommand("ddraw.arrow", DrawReload + 0.02f, npc.action == Act.Move ? Color.cyan : npc.action == Act.Attack ? Color.red : Color.yellow, drawpos + new Vector3(0, 5f, 0), drawpos, 1.5f);
            }

            void UpdateAction()
            {
                if (npc != null && input.IsDown(SecondButton))
                {
                    ChangeFollowAction();
                    return;
                }

                RaycastHit hit;
                if (!Physics.SphereCast(owner.eyes.position, 0.5f, Quaternion.Euler(input.current.aimAngles) * Vector3.forward, out hit) || hit.transform == transform)
                    return;

                if (npc == null)
                {
                    BaseNPC npcPet = hit.transform.GetComponent<BaseNPC>();
                    if (npcPet == null)
                        return;

                    if (hit.distance >= MaxControlDistance)
                    {
                        owner.ChatMessage(CloserMsg);
                        return;
                    }

                    TryGetNewPet(npcPet);
                    return;
                }

                BaseCombatEntity targetentity = hit.transform.GetComponent<BaseCombatEntity>();
                if (targetentity == null)
                {
                    npc.targetpoint = hit.point;
                    npc.action = Act.Move;
                    return;
                }

                if (targetentity == npc.Base)
                {
                    if (hit.distance <= LootDistance)
                        OpenPetInventory();
                }
                else if (targetentity is BaseCorpse)
                {
                    owner.ChatMessage(EatMsg);
                    npc.Attack(targetentity, Act.Eat);
                }
                else
                {
                    owner.ChatMessage(AttackMsg);
                    npc.Attack(targetentity);
                }
            }

            void OpenPetInventory()
            {
                var loot = owner.inventory.loot;
                loot.StartLootingEntity(npc.Base, true);
                loot.AddContainer(npc.inventory);
                loot.SendImmediate();
                owner.ClientRPCPlayer(owner.net.connection, owner, "RPC_OpenLootPanel", "smallwoodbox");
                owner.ChatMessage(OpenInvMsg);
            }

            void ChangeFollowAction()
            {
                if (npc.action == Act.Follow)
                {
                    owner.ChatMessage(UnFollowMsg);
                    npc.action = Act.None;
                }
                else
                {
                    owner.ChatMessage(FollowMsg);
                    npc.Attack(owner.GetComponent<BaseCombatEntity>(), Act.Follow);
                }
            }

            void TryGetNewPet(BaseNPC npcPet)
            {
                var OwnedNpc = npcPet.GetComponent<NpcAI>();
                if (OwnedNpc != null && OwnedNpc.owner != this)
                {
                    owner.ChatMessage(NoOwn);
                    return;
                }

                if (NextTimeToControl >= Time.realtimeSinceStartup)
                {
                    owner.ChatMessage(ReloadMsg);
                    return;
                }

                if (UsePermission && !PluginInstance.HasPermission(owner, "can" + npcPet.mdlPrefab.Get().name.Replace("_skin", "")))
                {
                    owner.ChatMessage(NoPermPetMsg);
                    return;
                }

                NextTimeToControl = Time.realtimeSinceStartup + ReloadControl;

                npc = npcPet.gameObject.AddComponent<NpcAI>();
                npc.owner = this;

                owner.ChatMessage(NewPetMsg);
            }
        }

        #endregion
        #region NPC AI Class

        public class NpcAI : MonoBehaviour
        {
            private readonly MethodInfo SetDeltaTimeMethod = typeof(NPCAI).GetProperty("deltaTime", (BindingFlags.Public | BindingFlags.Instance)).GetSetMethod(true);
            internal static float IgnoreTargetDistance = 70f;
            internal static float HealthModificator = 1.5f;
            internal static float AttackModificator = 2f;
            internal static float SpeedModificator = 1f;

            private float PointMoveDistance = 1f;
            private float TargetMoveDistance = 3f;

            float lastTick;
            float hungerLose;
            float thristyLose;
            float sleepLose;
            double attackrange;

            internal Act action;
            internal Vector3 targetpoint;
            internal BaseCombatEntity targetentity;

            public NpcControl owner;
            public ItemContainer inventory;
            public BaseNPC Base;
            public NPCAI RustAI;
            public NPCMetabolism RustMetabolism;

            void Awake()
            {
               RustAI = GetComponent<NPCAI>();
               RustAI.ServerDestroy();
               RustMetabolism = GetComponent<NPCMetabolism>();
               Base = GetComponent<BaseNPC>();

               lastTick = Time.time;
               targetpoint = Vector3.zero;
               action = Act.None;

               hungerLose = RustMetabolism.calories.max*2 / 12000;
               thristyLose = RustMetabolism.hydration.max*3 / 12000;
               sleepLose = RustMetabolism.sleep.max / 12000;

               inventory = new ItemContainer();
               inventory.ServerInitialize(null, 6);

               Base.enableSaving = false;
               BaseEntity.saveList.Remove(Base);
               Base.InitializeHealth(Base.health * HealthModificator, Base.MaxHealth() * HealthModificator);
               Base.locomotion.gallopSpeed *= SpeedModificator;
               Base.locomotion.trotSpeed *= SpeedModificator;
               Base.locomotion.acceleration *= SpeedModificator;
            }

            void OnDestroy()
            {
                DropUtil.DropItems(inventory, transform.position);
                SaveNpcList.Remove(owner.owner.userID);
                RustAI.ServerInit();

                if (Base.health <= 0)
                    return;

                Base.enableSaving = true;
                BaseEntity.saveList.Add(Base);

                Base.InitializeHealth(Base.health / HealthModificator, Base.MaxHealth() / HealthModificator);
                Base.locomotion.gallopSpeed /= SpeedModificator;
                Base.locomotion.trotSpeed /= SpeedModificator;
                Base.locomotion.acceleration /= SpeedModificator;
            }

            internal void OnAttacked(HitInfo info)
            {
                if (info.Initiator && info.Initiator != owner.owner && action != Act.Attack)
                    Attack(info.Initiator.GetComponent<BaseCombatEntity>());
            }

            void FixedUpdate()
            {
                SetDeltaTimeMethod.Invoke( RustAI, new object[] { Time.time - lastTick });
                if (RustAI.deltaTime < ConVar.Server.TickDelta()) return;
                lastTick = Time.time;
                if (Base.IsStunned()) return;
                Base.Tick();

                if (action != Act.Sleep)
                {
                    RustMetabolism.sleep.MoveTowards(0.0f, RustAI.deltaTime * sleepLose);
                    RustMetabolism.hydration.MoveTowards(0.0f, RustAI.deltaTime * thristyLose);
                    RustMetabolism.calories.MoveTowards(0.0f, RustAI.deltaTime * hungerLose);
                }

                if (action == Act.None)
                    return;

                if (action == Act.Move)
                    if (Vector3.Distance(transform.position, targetpoint) < PointMoveDistance)
                        action = Act.None;
                    else
                        Move(targetpoint);
                else if (action == Act.Sleep)
                    Sleep();
                else if (targetentity == null)
                {
                    action = Act.None;
                    Base.state = BaseNPC.State.Normal;
                }
                else
                {
                    var distance = Vector3.Distance(transform.position, targetentity.transform.position);
                    if (distance >= IgnoreTargetDistance)
                    {
                        action = Act.None;
                        return;
                    }

                    if (action != Act.Follow && distance <= attackrange)
                    {
                        var normalized = (targetentity.transform.position - transform.position).XZ3D().normalized;
                        if (action == Act.Eat)
                        {
                            if (Base.diet.Eat(targetentity))
                            {
                                Base.Heal(Base.MaxHealth() * 0.01f);
                                RustMetabolism.calories.Add(RustMetabolism.calories.max * 0.03f);
                                RustMetabolism.hydration.Add(RustMetabolism.hydration.max * 0.03f);
                            }
                        }
                        else if (Base.attack.Hit(targetentity, AttackModificator, false))
                            transform.rotation = Quaternion.LookRotation(normalized);
                        Base.steering.Face(normalized);
                    }
                    else if (action != Act.Follow || distance > TargetMoveDistance && distance > attackrange)
                        Move(targetentity.transform.position);
                }
            }

            void Sleep()
            {
                Base.state = BaseNPC.State.Sleeping;
                Base.sleep.Recover(2f);
                RustMetabolism.stamina.Run(4f);
                Base.StartCooldown(2f, true);
            }

            void Move(Vector3 point)
            {
                Base.state = BaseNPC.State.Normal;
                RustAI.sense.Think();
                Base.steering.Move((point - transform.position).XZ3D().normalized, point, (int) BLRust.ContextType.Gallop);
            }

            internal void Attack(BaseCombatEntity ent, Act act = Act.Attack)
            {
                targetentity = ent;
                action = act;
                attackrange = Math.Pow(Base._collider.bounds.XZ3D().extents.Max() + Base.attack.range + ent._collider.bounds.XZ3D().extents.Max(), 2);
            }
        }
        #endregion
        #region PetInfo Object to Save
        public class PetInfo
        {
            public uint prefabID;
            public float x, y, z;
            public byte[] inventory;
            internal bool NeedToSpawn;

            public PetInfo()
            {
                NeedToSpawn = true;
            }

            public PetInfo(NpcAI pet)
            {
                x = pet.transform.position.x;
                y = pet.transform.position.y;
                z = pet.transform.position.z;
                prefabID = pet.Base.prefabID;
                inventory = pet.inventory.Save().ToProtoBytes();
                NeedToSpawn = false;
            }
        }
        #endregion

        #region Config & Initialisation

        static bool UsePermission = true;
        static bool GlobalDraw = true;
        static string CfgButton = "USE";
        static string CfgSecButton = "RELOAD";
        static string OpenInvMsg = "Now open your inventory if you want loot pet!";
        static string ReloadMsg = "You can not tame so often! Wait!";
        static string NewPetMsg = "Now you have a new pet!";
        static string CloserMsg = "You need to get closer!";
        static string NoPermPetMsg = "You don't have permission to take this NPC!";
        static string FollowMsg = "Follow command!";
        static string UnFollowMsg = "UnFollow command!";
        static string SleepMsg = "Sleep command!";
        static string AttackMsg = "Attack!";
        static string NoPermMsg = "No Permission!";
        static string ActivatedMsg = "NPC Mode activated!";
        static string DeactivatedMsg = "NPC Mode deactivated!";
        static string NotNpc = "You don't have a pet!";
        static string NpcFree = "Now your per is free!";
        static string NoOwn = "This Npc is already tamed by other player!";
        static string EatMsg = "Time to eat!";
        static string DrawEn = "Draw enabled!";
        static string DrawDis = "Draw disabled!";
        static string DrawSysDis = "Draw system was disabled by administrator!";
        static string InfoMsg = "<color=red>Health: {health}%</color>, <color=orange>Hunger: {hunger}%</color>, <color=cyan>Thirst: {thirst}%</color>, <color=teal>Sleepiness: {sleep}%</color>, <color=lightblue>Stamina: {stamina}%</color>";

        protected override void LoadDefaultConfig() { }

        void Init()
        {
            CheckCfg("Use permissions", ref UsePermission);
            CheckCfg("Enable draw system", ref GlobalDraw);
            CheckCfg("Main button to controll pet", ref CfgButton);
            CheckCfg("Second button to use follow|unfollow", ref CfgSecButton);
            CheckCfg("Reload time to take new Npc", ref NpcControl.ReloadControl);
            CheckCfg("Max distance to take Npc", ref NpcControl.MaxControlDistance);
            CheckCfg("Distance to loot Npc", ref NpcControl.LootDistance);
            CheckCfg("Distance when target will be ignored by NPC", ref NpcAI.IgnoreTargetDistance);
            CheckCfg("Pet's Health Modificator", ref NpcAI.HealthModificator);
            CheckCfg("Pet's Attack Modificator", ref NpcAI.AttackModificator);
            CheckCfg("Pet's Speed Modificator", ref NpcAI.SpeedModificator);
            CheckCfg("New pet msg", ref NewPetMsg);
            CheckCfg("Closer msg", ref CloserMsg);
            CheckCfg("No take perm msg", ref NoPermPetMsg);
            CheckCfg("Follow msg", ref FollowMsg);
            CheckCfg("UnFollow msg", ref UnFollowMsg);
            CheckCfg("Sleep msg", ref SleepMsg);
            CheckCfg("Attack msg", ref AttackMsg);
            CheckCfg("No command perm msg", ref NoPermMsg);
            CheckCfg("Activated msg", ref ActivatedMsg);
            CheckCfg("Deactivated msg", ref DeactivatedMsg);
            CheckCfg("Reload msg", ref ReloadMsg);
            CheckCfg("No pet msg", ref NotNpc);
            CheckCfg("Free pet msg", ref NpcFree);
            CheckCfg("Already tamed msg", ref NoOwn);
            CheckCfg("Eat msg", ref EatMsg);
            CheckCfg("Draw enabled msg", ref DrawEn);
            CheckCfg("Draw disabled msg", ref DrawDis);
            CheckCfg("Draw system disabled msg", ref DrawSysDis);
            CheckCfg("Info msg", ref InfoMsg);
            CheckCfg("Open Inventory msg", ref OpenInvMsg);
            SaveConfig();

            InfoMsg= InfoMsg.Replace("{health}", "{0}").Replace("{hunger}", "{1}").Replace("{thirst}", "{2}").Replace("{sleep}", "{3}").Replace("{stamina}", "{4}");

            MainButton = ConvertStringToButton(CfgButton);
            SecondButton = ConvertStringToButton(CfgSecButton);
            PluginInstance = this;

            if (UsePermission)
            {
                permission.RegisterPermission("cannpc", this);
                permission.RegisterPermission("canstag", this);
                permission.RegisterPermission("canbear", this);
                permission.RegisterPermission("canwolf", this);
                permission.RegisterPermission("canchicken", this);
                permission.RegisterPermission("canboar", this);
                permission.RegisterPermission("canhorse", this);
            }

            try { SaveNpcList = Interface.GetMod().DataFileSystem.ReadObject<Dictionary<ulong, PetInfo>>("Pets"); } catch { }
            if (SaveNpcList == null) SaveNpcList = new Dictionary<ulong, PetInfo>();
        }

        #endregion

        #region Unload Hook (destroy all plugin's objects)

        void Unload()
        {
            OnServerSave();
            DestroyAll<NpcControl>();
            DestroyAll<NpcAI>();
            PluginInstance = null;
        }

        #endregion

        #region Hook OnAttacked for NpcAI

        void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo)
        {
            if (entity is BaseNPC)
                entity.GetComponent<NpcAI>()?.OnAttacked(hitInfo);
        }

        #endregion

        #region Hook OnPlayerInit (load player's pet)

        void OnPlayerInit(BasePlayer player)
        {
            if (player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot))
            {
                timer.Once(2, () => OnPlayerInit(player));
                return;
            }
            PetInfo info;
            if (!SaveNpcList.TryGetValue(player.userID, out info) || !info.NeedToSpawn) return;
            Puts("Loading pet...");
            var pet = GameManager.server.CreateEntity(StringPool.Get(info.prefabID), new Vector3(info.x, info.y, info.z));
            if (pet == null) return;
            var comp = player.gameObject.AddComponent<NpcControl>();
            pet.Spawn();
            comp.npc = pet.gameObject.AddComponent<NpcAI>();
            comp.npc.owner = comp;
            comp.npc.inventory.Load(ProtoBuf.ItemContainer.Deserialize(info.inventory));
            info.NeedToSpawn = false;
        }

        #endregion

        #region Hook OnServerSave (save all pets)

        void OnServerSave()
        {
            var pets = UnityEngine.Object.FindObjectsOfType<NpcAI>();
            if (pets == null) return;
            foreach (var pet in pets)
                SaveNpcList[pet.owner.owner.userID] = new PetInfo(pet);
            Interface.Oxide.DataFileSystem.WriteObject("Pets", SaveNpcList);
        }

        #endregion

        #region PET Command (activate/deactivate Npc mode)

        [ChatCommand("pet")]
        void pet(BasePlayer player, string command, string[] args)
        {
            var comp = player.GetComponent<NpcControl>() ?? player.gameObject.AddComponent<NpcControl>();
            if (args.Length == 0)
            {
                player.ChatMessage(comp.enabled ? DeactivatedMsg : ActivatedMsg);
                comp.enabled = !comp.enabled;
                return;
            }

            if (args[0] == "draw")
            {
                if (GlobalDraw)
                    if (comp.DrawEnabled)
                    {
                        comp.DrawEnabled = false;
                        player.ChatMessage(DrawDis);
                    }
                    else
                    {
                        comp.DrawEnabled = true;
                        player.ChatMessage(DrawEn);
                    }
                else
                    player.ChatMessage(DrawSysDis);
                return;
            }

            if (comp.npc)
            {
                switch (args[0])
                {
                    case "free":
                        UnityEngine.Object.Destroy(comp.npc);
                        player.ChatMessage(NpcFree);
                        break;
                    case "sleep":
                        player.ChatMessage(SleepMsg);
                        comp.npc.action = Act.Sleep;
                        break;
                    case "info":
                        var meta = comp.npc.RustMetabolism;
                        player.ChatMessage(string.Format(InfoMsg,
                            Math.Round(comp.npc.Base.health*100/comp.npc.Base.MaxHealth()),
                            Math.Round(meta.hydration.value*100/meta.hydration.max),
                            Math.Round(meta.calories.value*100/meta.calories.max),
                            Math.Round(meta.sleep.value*100/meta.sleep.max),
                            Math.Round(meta.stamina.value*100/meta.stamina.max)));
                        break;
                }
            }
            else
                player.ChatMessage(NotNpc);
        }

        #endregion

        #region Some other plugin methods

        bool HasPermission(BasePlayer player, string perm) => permission.UserHasPermission(player.UserIDString, perm);

        static void DestroyAll<T>()
        {
            var objects = UnityEngine.Object.FindObjectsOfType(typeof(T));
            if (objects == null) return;
            foreach (var gameObj in objects)
                UnityEngine.Object.Destroy(gameObj);
        }

        void CheckCfg<T>(string Key, ref T var)
        {
            if (Config[Key] == null)
                Config[Key] = var;
            else
                try { var = (T) Convert.ChangeType(Config[Key], typeof(T)); }
                catch { Config[Key] = var; }
        }

        static BUTTON ConvertStringToButton(string button)
        {
            try
            {
                return (BUTTON) Enum.Parse(typeof (BUTTON), button);
            }
            catch (Exception)
            {
                return BUTTON.USE;
            }
        }

        #endregion
    }
}

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