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

FREE BetterNpcNames : 1.2.5 1.2.5

Нет прав для скачивания
C#:
using System;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Core.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Facepunch;
using Rust;
using Rust.Ai;
using HarmonyLib;

#region Changelogs and ToDo
/**********************************************************************
* 
* 1.0.0 :       -   Initial release
* 1.0.1 :       -   Added a initialise check to avoid nre when renaming unfinished npc spawns
*               -   Added Update active npc when plugin is loaded
*               -   Added name Buildup to config
* 1.0.2 :       -   Added API : string GiveName(global::HumanNPC npc, string Title,bool UseName,bool UseLetter)
* 
*                   if (BetterNpcNames != null) npc.displayName = (BetterNpcNames.Call<string>("GiveName",npc , configData.NpcTitle, true, true));
* 1.0.3 :       -   Added Corpse loot from npc inventory,belt,wearables
*               -   Added options to clear belt or wearables when populating the corpse
*               -   Fixed nullreference issue
*               -   Added check at serverstartup
*               -   Added API : string GiveName(ScarecrowNPC npc, string Title,bool UseName,bool UseLetter)
* 1.1.0         -   Patched for Rust Changes
* 1.2.0         -   Harmony Patched for Rust Changes
*               -   Added Interface.CallHook("CanBetterNpcNamesRename" , npc);//to add avoid BetterNpcNames to edit the npc names
* 1.2.1         -   Null check added on Letter randomising
* 1.2.2         -   Moved random lettering on init for the harmonypatching
* 1.2.3         -   Added support for GingerbreadNPC
*               -   Other fixes
* 1.2.4         -   Hotfix
* 1.2.5         -   Wrapped console logging under a debug (true/false in cfg)
*               -   Fixed the forced extra spacing before the random letter.
*               -   Removed Linq usage.
*               -   Added individual scientisttype titles with default fallback title
*                              
**********************************************************************/
#endregion

namespace Oxide.Plugins
{
    [Info("Better NPC Names" , "Krungh Crow" , "1.2.5")]
    [Description("Names the unnamed npc and fixes corpse displaynames")]

    class BetterNpcNames : RustPlugin
    {
        #region Variables

        string npcname;
        System.Random Rand;
        bool IsReady;
        int NamingCount = 0;

        public static BetterNpcNames Instance { get; private set; }

        private bool Debug;

        #endregion

        #region Harmony

        private Harmony harmony;

        [HarmonyPatch(typeof(ScientistNPC))]
        [HarmonyPatch("displayName" , MethodType.Getter)]
        public static class ScientistNPC_DisplayName
        {
            static bool Prefix(ref string __result , ScientistNPC __instance)
            {
                if (__instance == null) return true;

                // Skip NPCs other plugins want to control
                if (BetterNpcNames.Instance.NpcList.Contains(__instance.userID))
                    return true;

                var plugin = BetterNpcNames.Instance;

                string dynamicTitle = plugin.GetTitleForNPC(__instance);

                var method = typeof(BetterNpcNames).GetMethod(
                    "GiveName" ,
                    BindingFlags.NonPublic | BindingFlags.Instance ,
                    null ,
                    new[] { typeof(ScientistNPC) , typeof(string) , typeof(bool) , typeof(bool) } ,
                    null
                );

                if (method != null)
                {
                    __result = (string)method.Invoke(plugin , new object[] { __instance , dynamicTitle , true , true });
                    return false;
                }

                return true;
            }
        }

        [HarmonyPatch(typeof(UnderwaterDweller))]
        [HarmonyPatch("displayName" , MethodType.Getter)]
        public static class UnderwaterDweller_DisplayName
        {
            static bool Prefix(ref string __result , UnderwaterDweller __instance)
            {
                string npcname = "Underwater Dweller";
                var _RandomName = RandomUsernames.Get(__instance.userID.Get());
                string RandomName = MakeCap(_RandomName);
                string Title = udTitle;
                string letter = BetterNpcNames.Instance.Letter();
                npcname = sNaming.Replace("{Title}" , Title).Replace("{RandomName}" , RandomName).Replace("{RandomLetter}" , letter);
                __result = npcname;
                return false;
            }
        }

        [HarmonyPatch(typeof(TunnelDweller))]
        [HarmonyPatch("displayName" , MethodType.Getter)]
        public static class TunnelDweller_DisplayName
        {
            static bool Prefix(ref string __result , TunnelDweller __instance)
            {
                string npcname = "Tunnel Dweller";
                var _RandomName = RandomUsernames.Get(__instance.userID.Get());
                string RandomName = MakeCap(_RandomName);
                string Title = tdTitle;
                string letter = BetterNpcNames.Instance.Letter();
                npcname = sNaming.Replace("{Title}" , Title).Replace("{RandomName}" , RandomName).Replace("{RandomLetter}" , letter);
                __result = npcname;
                return false;
            }
        }

        #endregion

        #region Configuration

        void Init()
        {
            Instance = this;
            harmony = new Harmony("krunghcrow.better.npc.names");
            harmony.PatchAll();
            Rand = new System.Random();

            if (!LoadConfigVariables())
            {
                Puts("Config file issue detected. Please delete file, or check syntax and fix.");
                return;
            }
            sTitle = configData.Titles.Sci;
            udTitle = configData.Titles.UDwel;
            tdTitle = configData.Titles.TDwel;
            Debug = configData.Debug;
        }

        void Unload()
        {
            harmony.UnpatchAll(harmony.Id);
        }

        public static string sTitle = "";
        public static string udTitle = "";
        public static string tdTitle = "";
        public static string sNaming = "";

        private ConfigData configData;

        class ConfigData
        {
            [JsonProperty(PropertyName = "Use Debug")]
            public bool Debug = false;
            [JsonProperty(PropertyName = "Name the npcplayertest")]
            public bool UseTest = false;
            [JsonProperty(PropertyName = "Npc Titles")]
            public Titles Titles = new Titles();
            [JsonProperty(PropertyName = "Name Buildup")]
            public string Naming = "{Title} {RandomName} {RandomLetter}";
            [JsonProperty(PropertyName = "Corpse setup")]
            public CorpseData Corpse = new CorpseData();
        }

        class CorpseData
        {
            [JsonProperty(PropertyName = "Clear Deafault loot")]
            public bool ClDefault = false;
            [JsonProperty(PropertyName = "Clear Belt")]
            public bool ClBelt = false;
            [JsonProperty(PropertyName = "Clear Clothes")]
            public bool ClClothes = false;
        }

        class Titles
        {
            [JsonProperty(PropertyName = "Frankenstein")]
            public string Frank = "Frankenstein";
            [JsonProperty(PropertyName = "Scarecrow")]
            public string Crow = "Scarecrow";
            [JsonProperty(PropertyName = "Scientist (Global fallback)")]
            public string Sci = "Dr";
            [JsonProperty(PropertyName = "Scientists individual")]
            public Dictionary<string , string> PrefabOverrides = new Dictionary<string , string>
            {
                { "scientistnpc_arena", "Gladiator"},
                { "scientistnpc_bradley", "Guard"},
                { "scientistnpc_bradley_heavy", "Heavy Guard"},
                { "scientistnpc_cargo", "Cargo Sailor"},
                { "scientistnpc_cargo_turret_any", "Cargo Officer"},
                { "scientistnpc_cargo_turret_lr300", "Cargo Guard"},
                { "scientistnpc_ch47_gunner", "Airman"},
                { "scientistnpc_excavator", "Digger"},
                { "scientistnpc_full_any", "Rougue" },
                { "scientistnpc_full_lr300", "Riflemen" },
                { "scientistnpc_full_mp5", "Trooper" },
                { "scientistnpc_full_pistol", "Gunman" },
                { "scientistnpc_full_shotgun", "Gunner" },
                { "scientistnpc_heavy", "Fatty" },
                { "scientistnpc_junkpile_pistol", "Junker" },
                { "scientistnpc_oilrig", "Oiler" },
                { "scientistnpc_outbreak", "Investigator" },
                { "scientistnpc_patrol", "Patroller" },
                { "scientistnpc_patrol_arctic", "Arctic" },
                { "scientistnpc_peacekeeper", "Peacekeeper" },
                { "scientistnpc_ptboat", "Sailor" },
                { "scientistnpc_rhib", "Frogmen" },
                { "scientistnpc_roam", "Roamer" },
                { "scientistnpc_roam_nvg_variant", "Nightswatch" },
                { "scientistnpc_roamtethered", "Tethered" },
            };
            [JsonProperty(PropertyName = "UnderwaterDweller")]
            public string UDwel = "UnderwaterDweller";
            [JsonProperty(PropertyName = "TunnelDweller")]
            public string TDwel = "TunnelDweller";
            [JsonProperty(PropertyName = "GingerbreadNPC")]
            public string Ginger = "Ginger";
            [JsonProperty(PropertyName = "npcplayertest")]
            public string Test = "playertest";
        }

        private bool LoadConfigVariables()
        {
            try { configData = Config.ReadObject<ConfigData>(); }
            catch { return false; }
            SaveConf();
            return true;
        }

        protected override void LoadDefaultConfig()
        {
            Puts("Fresh install detected Creating a new config file.");
            configData = new ConfigData();
            SaveConf();
        }

        void SaveConf() => Config.WriteObject(configData , true);

        #endregion

        #region external Hooks

        List<ulong> NpcList = new List<ulong>();
        void OnBotReSpawnNPCSpawned(ScientistNPC npc , string profilename , string group) => NpcList.Add(npc.userID);
        void OnHuntsmanSpawn(ScientistNPC npc) => NpcList.Add(npc.userID);
        void CanBetterNpcNamesRename(ScientistNPC npc) => NpcList.Add(npc.userID);

        void OnEntityKill(ScientistNPC npc)
        {
            if (npc == null)
                return;
            if (NpcList.Contains(npc.userID))
                NpcList.Remove(npc.userID);
        }

        #endregion

        #region Oxide Hooks

        void OnServerInitialized(bool initial)
        {
            Rand = new System.Random();

            if (initial)
            {
                IsReady = false;
                CheckInit();
                return;
            }

            IsReady = true;
            if (IsReady) Debugmsg("Server is Ready for NPC Naming");
            NamingCount = 0;
            sNaming = configData.Naming;

            foreach (var baseNetworkable in BaseNetworkable.serverEntities)
            {
                var npc = baseNetworkable as global::NPCPlayer;
                if (npc == null) continue;

                string originalNaming = npc.displayName;

                UpdateName(npc);

                if (originalNaming != npc.displayName) { NamingCount++; }
            }

            if (NamingCount != 0) Debugmsg($"{NamingCount} NPC's where renamed");
        }

        void OnEntitySpawned(global::BaseEntity entity)
        {
            var npc = entity as NPCPlayer;
            if (npc != null && IsReady)
            {
                try
                {
                    UpdateName(npc);
                }
                catch (Exception ex)
                {
                }
            }
            return;
        }

        void OnEntityDeath(global::NPCPlayer npc , HitInfo info)
        {
            if (npc == null || info == null)
                return;

            ItemContainer[] source =
            {
                npc.inventory?.containerMain,
                npc.inventory?.containerWear,
                npc.inventory?.containerBelt
            };

            var npcInv = new Inv
            {
                name = npc.displayName
            };

            NpcContents[npc.userID] = npcInv;

            for (int i = 0; i < source.Length; i++)
            {
                var container = source[i];
                if (container == null)
                    continue;

                foreach (var item in container.itemList)
                {
                    npcInv.inventory[i].Add(new NpcInventory
                    {
                        ID = item.info.itemid ,
                        amount = item.amount ,
                        skinID = item.skin
                    });
                }
            }
        }

        void OnEntitySpawned(NPCPlayerCorpse corpse)
        {
            if (corpse == null || corpse.IsDestroyed || !IsReady)
                return;

            try
            {
                ulong id = corpse.playerSteamID;

                if (!NpcContents.TryGetValue(id , out var npcInv))
                    return;

                corpse.playerName = OverrideCorpseName(npcInv.name);

                if (corpse.ShortPrefabName.Contains("ginger" , StringComparison.OrdinalIgnoreCase))
                    return;

                timer.Once(0.1f , () =>
                {
                    if (corpse == null || corpse.IsDestroyed || !IsReady)
                        return;

                    try
                    {
                        var dispenser = corpse.GetComponent<ResourceDispenser>();
                        if (dispenser != null)
                        {
                            dispenser.containedItems.Add(new ItemAmount
                            {
                                itemDef = ItemManager.FindItemDefinition("skull.human") ,
                                amount = 1 ,
                                startAmount = 1
                            });

                            dispenser.containedItems.Add(new ItemAmount
                            {
                                itemDef = ItemManager.FindItemDefinition("humanmeat.raw") ,
                                amount = 6 ,
                                startAmount = 1
                            });

                            dispenser.containedItems.Add(new ItemAmount
                            {
                                itemDef = ItemManager.FindItemDefinition("fat.animal") ,
                                amount = 2 ,
                                startAmount = 1
                            });

                            dispenser.Initialize();
                        }

                        for (int i = 0; i < npcInv.inventory.Length && i < corpse.containers.Length; i++)
                        {
                            var container = corpse.containers[i];
                            if (container == null)
                                continue;

                            foreach (var item in npcInv.inventory[i])
                            {
                                var giveItem = ItemManager.CreateByItemID(item.ID , item.amount , item.skinID);
                                if (!giveItem.MoveToContainer(container , -1 , true))
                                    giveItem.Remove();
                            }
                        }

                        if (configData.Corpse.ClDefault && corpse.containers.Length > 0)
                            corpse.containers[0].Clear();

                        if (configData.Corpse.ClClothes && corpse.containers.Length > 1)
                            corpse.containers[1].Clear();

                        if (configData.Corpse.ClBelt && corpse.containers.Length > 2)
                            corpse.containers[2].Clear();

                        timer.Once(5f , () => NpcContents.Remove(id));
                    }
                    catch
                    {
                    }
                });
            }
            catch
            {
            }
        }

        protected virtual string OverrideCorpseName(string _playerName) { return _playerName; }

        #endregion

        #region API

        private string GiveName(global::HumanNPC npc , string Title , bool UseName , bool UseLetter)
        {
            string RandomName = string.Empty;
            string RLetter = string.Empty;
            if (UseName)
            {
                string _RandomName = RandomUsernames.Get(npc.userID.Get());
                RandomName = MakeCap(_RandomName);
            }
            if (UseLetter) RLetter = Letter();
            npcname = (configData.Naming).Replace("{Title}" , Title).Replace("{RandomName}" , RandomName).Replace("{RandomLetter}" , RLetter);
            return npc.displayName = npcname;
        }

        private string GiveName(ScarecrowNPC npc , string Title , bool UseName , bool UseLetter)
        {
            string RandomName = string.Empty;
            string RLetter = string.Empty;
            if (UseName)
            {
                string _RandomName = RandomUsernames.Get(npc.userID.Get()); RandomName = MakeCap(_RandomName);
            }
            if (UseLetter) RLetter = Letter();
            npcname = (configData.Naming).Replace("{Title}" , Title).Replace("{RandomName}" , RandomName).Replace("{RandomLetter}" , RLetter);
            return npc.displayName = npcname;
        }

        #endregion

        #region Helpers Corpse

        public Dictionary<ulong , Inv> NpcContents = new Dictionary<ulong , Inv>();

        public class Inv
        {
            public string name;
            public List<NpcInventory>[] inventory = { new List<NpcInventory>() , new List<NpcInventory>() , new List<NpcInventory>() };
        }

        public class NpcInventory
        {
            public int ID;
            public int amount;
            public ulong skinID;
        }

        #endregion

        #region Helpers Naming

        private string GetTitleForNPC(NPCPlayer npc)
        {
            string fallback = configData?.Titles?.Sci ?? "Scientist";
            if (npc == null) return fallback;

            string prefab = npc.ShortPrefabName;
            if (string.IsNullOrEmpty(prefab)) return fallback;

            var overrides = configData?.Titles?.PrefabOverrides;
            if (overrides == null || overrides.Count == 0) return fallback;

            // Exact match only
            foreach (var kvp in overrides)
            {
                if (string.Equals(prefab , kvp.Key , StringComparison.OrdinalIgnoreCase))
                {
                    if (!string.IsNullOrWhiteSpace(kvp.Value))
                        return kvp.Value;

                    return fallback;
                }
            }

            return fallback;
        }
        string Letter()//Generates random letter
        {
            if (Rand == null)
            {
                Rand = new System.Random();
            }
            int num = Rand.Next(0 , 26);
            char x = (char)('a' + num);
            return x.ToString().ToUpper();
        }

        public static string MakeCap(string name) //makes first letter of npc name Uppercase
        {
            if (string.IsNullOrEmpty(name)) return string.Empty;
            char[] a = name.ToCharArray();
            a[0] = char.ToUpper(a[0]);
            return new string(a);
        }

        void UpdateName(global::NPCPlayer npc) //Names the Unnamed npc
        {
            if (Interface.CallHook("OnNpcNaming" , npc.userID) != null || Interface.CallHook("OnNpcNaming" , npc) != null)
            {
                Debugmsg("Test trigger for OnNpcNaming");
            }
            if (NpcList.Contains(npc.userID))
            {
                Debugmsg($"Skipping BotResSpawn npc {npc.userID}"); //example
                return;
            }

            try
            {
                npcname = npc.displayName.ToString();
                if (npcname == npc.userID.ToString() || npc.ShortPrefabName.Contains("ginger"))
                {
                    var _RandomName = RandomUsernames.Get(npc.userID.Get());
                    string RandomName = MakeCap(_RandomName);
                    string Title = string.Empty;

                    switch (npc)
                    {
                        case ScientistNPC:
                            {
                                string prefab = npc.ShortPrefabName;

                                if (prefab != null && prefab.Contains("scientistnpc_heavy" , StringComparison.OrdinalIgnoreCase))
                                    Title = "Fatty";
                                else
                                    Title = configData.Titles.Sci;

                                break;
                            }
                        case ScarecrowNPC: Title = configData.Titles.Crow; break;
                        case FrankensteinPet: Title = configData.Titles.Frank;  break;
                        case UnderwaterDweller: Title = configData.Titles.UDwel; break;
                        case TunnelDweller: Title = configData.Titles.TDwel; break;
                        case GingerbreadNPC: Title = configData.Titles.Ginger;   break;

                        default:
                            if (npc.ShortPrefabName.Contains("playertest"))
                            {
                                if (!configData.UseTest) return;
                                Title = configData.Titles.Test;
                            }
                            else
                            {
                                Debugmsg($"Skipping unlisted NPC type: {npc.ShortPrefabName} ({npc.userID})");
                                return;
                            }
                            break;
                    }

                    npcname = configData.Naming
                        .Replace("{Title}" , Title)
                        .Replace("{RandomName}" , RandomName)
                        .Replace("{RandomLetter}" , Letter());

                    npc.displayName = npcname;
                }
            }
            catch (Exception ex)
            {
                Debugmsg($"[BetterNpcNames] Exception caught during NPC name update for {npc?.ShortPrefabName ?? "Unknown"}: {ex.Message}");
            }
        }

        #endregion

        #region Helpers Various

        void CheckInit()//checks if server is fully initialised
        {
            timer.Once(10f , () =>
            {
                if (Rust.Application.isLoading)
                {
                    Debugmsg($"Server still loading....");
                    CheckInit();
                    return;
                }
                IsReady = true;
                Debugmsg($"Server is Ready for NPC Naming....");
            });
        }

        void Debugmsg(string key)
        {
            if (Debug) Puts($"[Debug] {key}");
        }

        #endregion

    }
}

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