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

FREE Humanoids : 1.3.7 1.3.7

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
#region License (GPL v2)
/*
    Humanoids - NPC Players that can walk, fight, navigate, etc.Copyright (c) 2023 RFC1920 <desolationoutpostpve@gmail.com>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License v2.0.This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
    GNU General Public License for more details.You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.Optionally you can also view the license at <http://www.gnu.org/licenses/>.*/
#endregion License (GPL v2)
// Requires: PathFinding
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("Humanoids", "RFC1920", "1.3.7")]
    [Description("Adds interactive NPCs which can be modded by other plugins")]
    internal class Humanoids : RustPlugin {
#region vars
        [PluginReference]
        private readonly Plugin Kits, RoadFinder, GUIShop, NPCShop, ChatBot;
        private static readonly PathFinding PathFinding;
        private DynamicConfigFile data;
        private ConfigData configData;
        public static Dictionary<string, AmmoTypes> ammoTypes = new();
        private List<ulong> isopen = new();
        private const string permNPCGuiUse = "humanoid.use";
        private const string NPCGUI = "npc.editor";
        private const string NPCGUK = "npc.kitselect";
        private const string NPCGUL = "npc.locoselect";
        private const string NPCGUM = "npc.monselect";
        private const string NPCGUN = "npc.kitsetnum";
        private const string NPCGUR = "npc.roadselect";
        private const string NPCGUS = "npc.select";
        private const string NPCGUV = "npc.setval";
        private readonly List<string> guis = new() {
            NPCGUI, NPCGUK, NPCGUL, NPCGUM, NPCGUN, NPCGUR, NPCGUS, NPCGUV
        }
        ;
        private bool newsave;
        public static Humanoids Instance;
        private static Dictionary<ulong, HumanoidInfo> npcs = new();
        // This is critical to the speed of operations on FindHumanoidByID/Name
        private Dictionary<ulong, HumanoidPlayer> hpcacheid = new();
        private Dictionary<string, HumanoidPlayer> hpcachenm = new();
        private static Dictionary<string, Road> roads = new();
        private static SortedDictionary<string, Vector3> monPos = new();
        private static SortedDictionary<string, Vector3> monSize = new();
        private static SortedDictionary<string, Vector3> cavePos = new();
        private static Vector3 Vector3Down;
        private readonly static int playerMask = LayerMask.GetMask("Player (Server)");
        private readonly static int groundLayer = LayerMask.GetMask("Construction", "Terrain", "World");
        private readonly static int obstructionMask = LayerMask.GetMask(new[] {
            "Construction", "Deployed", "Clutter"
        }
        );
        //private readonly static int gatherMask = LayerMask.GetMask(new[] { "Construction", "Deployed", "World" });
        private readonly static int constructionMask = LayerMask.GetMask(new[] {
            "Construction", "Deployed"
        }
        );
        //private readonly static int terrainMask = LayerMask.GetMask(new[] { "Terrain", "Tree" });
        private static int targetLayer;
#endregion
#region Message
        private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
        private void Message(IPlayer player, string key, params object[] args) => player.Reply(Lang(key, player.Id, args));
        private void DoLog(string message) {
            if (configData.Options.debug) Interface.GetMod().LogInfo(message);
        }
#endregion
#region global
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                ["npcgui"]
                = "Humanoid GUI", ["npcguisel"] = "HumanoidGUI NPC Select ", ["npcguikit"] = "HumanoidGUI Kit Select", ["npcguimon"] = "HumanoidGUI Monument Select", ["npcguiroad"] = "HumanoidGUI Road Select", ["npcguiloco"] = "HumanoidGUI LocoMode Select", ["close"] = "Close", ["none"] = "None", ["noid"] = "noid", ["start"] = "Start", ["end"] = "End", ["debug"] = "Debug set to {0}", ["humanoids"] = "Humanoids", ["needselect"] = "Select NPC", ["select"] = "Select", ["editing"] = "Editing", ["mustselect"] = "Please press 'Select' to choose an NPC.", ["guihelp1"] = "For blue buttons, click to toggle true/false.", ["guihelp2"] = "For all values above in gray, you may type a new value and press enter.", ["guihelp3"] = "For kit, press the button to select a kit.", ["add"] = "Add", ["new"] = "Create New", ["remove"] = "Remove", ["spawnhere"] = "Spawn Here", ["spawnedat"] = "New NPC Spawned at {0} ({1})", ["tpto"] = "Teleport to NPC", ["name"] = "Name", ["online"] = "Online", ["offline"] = "Offline", ["deauthall"] = "DeAuthAll", ["remove"] = "Remove"
            }
            , this);
        }
        private void OnServerInitialized() {
            LoadConfigVariables();
            AddCovalenceCommand("noid", "cmdNPC");
            targetLayer = LayerMask.GetMask("Player (Server)", "AI", "Deployed", "Construction");
            Instance = this;
            LoadData();
            foreach (HumanoidPlayer obj in Resources.FindObjectsOfTypeAll<HumanoidPlayer>()) {
                if (configData.Options.zeroOnWipe && newsave) {
                    obj.info.loc = Vector3.zero;
                }
                UnityEngine.Object.Destroy(obj);
            }
            newsave = false;
            foreach (HumanoidMovement obj in Resources.FindObjectsOfTypeAll<HumanoidMovement>()) {
                UnityEngine.Object.Destroy(obj);
            }
            Dictionary<ulong, HumanoidInfo> tmpnpcs = new(npcs);
            foreach (KeyValuePair<ulong, HumanoidInfo> npc in tmpnpcs) {
                if (npc.Value.userid == 0) continue;
                DoLog($"Spawning npc {npc.Value.userid}");
                ulong nid = 0;
                SpawnNPC(npc.Value, out nid);
            }
            tmpnpcs.Clear();
            SaveData();
            FindMonuments();
            if (RoadFinder) {
                object x = RoadFinder.CallHook("GetRoads");
                string json = JsonConvert.SerializeObject(x);
                roads = JsonConvert.DeserializeObject<Dictionary<string, Road>>(json);
            }
            foreach (BasePlayer player in BasePlayer.activePlayerList) {
                foreach (string gui in guis) {
                    CuiHelper.DestroyUi(player, gui);
                }
                if (isopen.Contains(player.userID)) isopen.Remove(player.userID);
            }
        }
        // 07 Jan 2023: Currently only called by Teleportication 1.3.8 and above
        private void OnTownSet(Vector3 location) {
            configData.Options.townLocation = location;
            SaveConfig(configData);
            if (GUIShop || NPCShop) {
                DoLog("OnTownSet called!");
                BuildingPrivlidge bp = null;
                List<BaseEntity> entities = new();
                List<BaseEntity> frames = new();
                List<ulong> processedNPCs = new();
                Vis.Entities(location, 100f, entities);
                foreach (BaseEntity entity in entities.OrderBy(x => Vector3.Distance(location, x.transform.position))) {
                    if (entity.ShortPrefabName == configData.Options.townPrefab) {
                        DoLog($"Found a {configData.Options.townPrefab} at {entity.transform.position}");
                        frames.Add(entity);
                    }
                    if (entity is BuildingPrivlidge && bp == null) {
                        // Only get the first TC we find, which should be closest to the town set point
                        DoLog($"Found a TC at {entity.transform.position}");
                        bp = entity as BuildingPrivlidge;
                    }
                }
                DoLog($"Found {frames.Count} of {configData.Options.townPrefab}");
                foreach (KeyValuePair<ulong, HumanoidInfo> npc in new Dictionary<ulong, HumanoidInfo>(npcs)) {
                    if (npc.Value.shopnpc && !processedNPCs.Contains(npc.Key)) {
                        foreach (BaseEntity frame in new List<BaseEntity>(frames)) {
                            if (bp != null && frame.GetBuildingPrivilege() != bp) {
                                continue;
                            }
                            // Place/move NPC here
                            SetHumanoidInfo(npc.Key, "spawn", GetPrefabPos(frame));
                            SetHumanoidInfo(npc.Key, "rot", frame.transform.rotation.ToString());
                            SetHumanoidInfo(npc.Key, "townrel", (location - frame.transform.position).ToString());
                            DoLog("Moved NPC to town");
                            frames.Remove(frame);
                            break;
                        }
                        RespawnNPC(npc.Key);
                        processedNPCs.Add(npc.Key);
                    }
                }
            }
        }
        private string GetPrefabPos(BaseEntity frame) {
            Vector3 rear = -frame.transform.right;
            // Yes, right is in front...Vector3 newPos = frame.transform.position + new Vector3(rear.x, rear.y, rear.z + 0.5f);
            DoLog($"{configData.Options.townPrefab} located at {frame.transform.position}.NPC will be at {newPos}");
            return newPos.ToString();
        }
        private void OnNewSave() {
            newsave = true;
        }
        private void Unload() {
            foreach (BasePlayer player in BasePlayer.activePlayerList.Where(x => x.IsAdmin)) {
                foreach (string gui in guis) {
                    CuiHelper.DestroyUi(player, gui);
                }
                if (isopen.Contains(player.userID)) isopen.Remove(player.userID);
            }
            foreach (HumanoidPlayer obj in Resources.FindObjectsOfTypeAll<HumanoidPlayer>()) {
                DoLog($"Killing player object {obj.player.userID}");
                obj.movement.Stand();
                obj.GetComponent<BasePlayer>().Kill();
            }
        }
        private void LoadData() {
            DoLog("LoadData called");
            data = Interface.GetMod().DataFileSystem.GetFile(Name + "/humanoids");
            data.Settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            data.Settings.Converters = new JsonConverter[] {
                new UnityQuaternionConverter(), new UnityVector3Converter()
            }
            ;
            npcs = data.ReadObject<Dictionary<ulong, HumanoidInfo>>();
            data.Clear();
            foreach (KeyValuePair<ulong, HumanoidInfo> pls in npcs) {
                DoLog($"{pls.Value.userid}");
            }
        }
        private void SaveData() {
            Dictionary<ulong, HumanoidInfo> tmpnpcs = new();
            foreach (KeyValuePair<ulong, HumanoidInfo> x in npcs) {
                if (!x.Value.ephemeral) {
                    tmpnpcs.Add(x.Key, x.Value);
                }
            }
            Interface.GetMod().DataFileSystem.WriteObject(Name + "/humanoids", tmpnpcs);
            tmpnpcs.Clear();
        }
#endregion
#region Oxide Hooks
        private void OnPlayerInput(BasePlayer player, InputState input) {
            if (player == null || input == null) return;
            if (!player.userID.IsSteamId()) return;
            //if (input.current.buttons > 0)
            //    Puts($"OnPlayerInput: {input.current.buttons}");
            if (!input.WasJustPressed(BUTTON.USE)) return;
            RaycastHit hit;
            if (Physics.Raycast(player.eyes.HeadRay(), out hit, 3f, playerMask)) {
                BasePlayer pl = hit.GetEntity().ToPlayer();
                HumanoidPlayer hp = pl.GetComponent<HumanoidPlayer>();
                if (hp == null) return;
                if (hp.movement.sitting) {
                    DoLog($"Trying to stand {hp.info.displayName}");
                    hp.movement.Stand();
                }
                hp.LookToward(player.transform.position, true);
                if (hp.info.entrypause) {
                    DoLog($"Trying to pause {hp.info.displayName}");
                    hp.movement.Stop(true);
                }
                hp.movement.Jump();
                Interface.GetMod().CallHook("OnUseNPC", hp.player, player);
                SaveData();
            }
        }
        private object CanHelicopterTarget(PatrolHelicopterAI heli, BasePlayer player) {
            if (player == null) return null;
            if (player.userID.IsSteamId()) return null;
            if (IsHumanoid(player)) return true;
            return null;
        }
        private object CanHelicopterStrafeTarget(PatrolHelicopterAI heli, BasePlayer player) {
            if (player == null) return null;
            if (player.userID.IsSteamId()) return null;
            if (IsHumanoid(player)) return true;
            return null;
        }
        private object OnHelicopterTarget(HelicopterTurret turret, BaseCombatEntity entity) {
            BasePlayer player = entity.ToPlayer();
            if (player == null) return null;
            if (player.userID.IsSteamId()) return null;
            if (IsHumanoid(player)) return true;
            return null;
        }
        private void OnEntityDeath(BaseCombatEntity entity, HitInfo hitinfo) {
            if (entity == null) return;
            HumanoidPlayer hp = entity.GetComponent<HumanoidPlayer>();
            if (hp == null) return;
            if (!hp.info.lootable) {
                hp.player.inventory?.Strip();
            }
            else if (!hp.info.dropWeapon) {
                hp.movement.firstWeapon?.Kill();
            }
            else {
                BaseProjectile weapon = hp.movement.firstWeapon as BaseProjectile;
                if (weapon != null) {
                    weapon.primaryMagazine.contents = 0;
                }
            }
            if (hp?.info.respawn == true) {
                timer.Once(hp.info.respawnTimer, () => RespawnNPC(hp.info.userid));
            }
        }
        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitinfo) {
            if (hitinfo == null) return null;
            if (entity == null) return null;
            //if (hitinfo?.damageTypes?.GetMajorityDamageType() == DamageType.Decay) return null;
            HumanoidPlayer hp = entity?.GetComponent<HumanoidPlayer>();
            if (hp != null) {
                DoLog("Checking in");
                BasePlayer atpl = hitinfo?.Initiator as BasePlayer;
                if (atpl == hp?.player) {
                    //DoLog($"Humanoid {hp.info.displayName} self damage, skipping...");
                    return true;
                }
                DoLog($"Humanoid {hp?.info?.displayName} majority damage type == {hitinfo?.damageTypes?.GetMajorityDamageType().ToString()}");
                if (atpl != null) {
                    DoLog($"Player {atpl?.displayName} attacking Humanoid {hp?.info?.displayName}");
                }
                else {
                    DoLog($"{hitinfo?.Initiator?.ShortPrefabName} attacking Humanoid {hp?.info?.displayName}");
                }
                if (hitinfo?.InitiatorPlayer != null && hitinfo?.Initiator is BaseProjectile && hp.info.defend) {
                    DoLog("Setting attacked to true.");
                    hp.movement.attacked = true;
                    hp.movement.attackEntity = hitinfo.InitiatorPlayer as BaseCombatEntity;
                }
                else if (hitinfo?.Initiator is BaseCombatEntity && !(hitinfo?.Initiator is Barricade) && hp.info.defend) {
                    DoLog("Setting attacked to true.");
                    hp.movement.attacked = true;
                    hp.movement.attackEntity = hitinfo.Initiator as BaseCombatEntity;
                }
                //if (hp.info.message_hurt != null && hp.info.message_hurt.Count != 0)
                //{
                //    if (hitinfo.InitiatorPlayer != null))
                //    {
                //        SendMessage(hp, hitinfo.InitiatorPlayer, GetRandomMessage(hp.info.message_hurt));
                //    }
                //}
                Interface.GetMod().CallHook("OnHitNPC", entity.GetComponent<BaseCombatEntity>(), hitinfo);
                if (hp.info.invulnerable) {
                    hitinfo.damageTypes = new DamageTypeList();
                    hitinfo.DoHitEffects = false;
                    hitinfo.HitMaterial = 0;
                    if (hp.movement.sitting && !hp.movement.riding) {
                        hp.movement.Stand();
                    }
                    return true;
                }
                else {
                    hp.protection.Scale(hitinfo.damageTypes);
                }
                if (hp.movement.sitting && !hp.movement.riding) {
                    hp.movement.Stand();
                }
                hp.movement.Evade();
            }
            return null;
        }
        private object CanLootPlayer(BasePlayer target, BasePlayer player) {
            if (player == null || target == null) return null;
            HumanoidPlayer hp = target.GetComponentInParent<HumanoidPlayer>();
            if (hp?.info.lootable == false) {
                DoLog($"Player {player.displayName}:{player.UserIDString} looting Humanoid {hp.info.displayName}");
                NextTick(player.EndLooting);
                return true;
            }
            return null;
        }
        private object CanLootEntity(BasePlayer player, LootableCorpse corpse) {
            if (player == null || corpse == null) return null;
            if (hpcacheid.ContainsKey(corpse.playerSteamID)) {
                HumanoidPlayer hp = hpcacheid[corpse.playerSteamID];
                if (hp == null) return null;
                DoLog($"Player {player.displayName}:{player.UserIDString} looting Humanoid {corpse.name}:{corpse.playerSteamID}");
                if (!hp.info.lootable) {
                    NextTick(player.EndLooting);
                    return true;
                }
            }
            return null;
        }
        private void OnLootPlayer(BasePlayer looter, BasePlayer target) {
            if (npcs.ContainsKey(target.userID)) {
                Interface.GetMod().CallHook("OnLootNPC", looter.inventory.loot, target, target.userID);
            }
        }
        private void OnLootEntity(BasePlayer looter, BaseEntity entity) {
            if (looter == null || !(entity is PlayerCorpse)) return;
            ulong userId = ((PlayerCorpse)entity).playerSteamID;
            HumanoidInfo hi;
            npcs.TryGetValue(userId, out hi);
            if (hi != null) {
                Interface.GetMod().CallHook("OnLootNPC", looter.inventory.loot, entity, userId);
            }
        }
        private object OnUserCommand(IPlayer player, string command, string[] args) {
            if (command != "noid" && isopen.Contains(ulong.Parse(player.Id))) return true;
            return null;
        }
        private object OnPlayerCommand(BasePlayer player, string command, string[] args) {
            if (command != "noid" && isopen.Contains(player.userID)) return true;
            return null;
        }
#endregion
#region commands
        [Command("noid")]
        private void cmdNPC(IPlayer iplayer, string command, string[] args) {
            BasePlayer player = iplayer.Object as BasePlayer;
            if (args.Length > 0) {
                DoLog(string.Join(",", args));
                switch (args[0]) {
                    case "show" : foreach (KeyValuePair<ulong, HumanoidInfo> pls in npcs) {
                        BasePlayer tmpl = iplayer.Object as BasePlayer;
                        tmpl?.SendConsoleCommand("ddraw.text", 30, Color.green, pls.Value.loc + new Vector3(0, 1.55f, 0), $"<size=20>{pls.Value.displayName}</size>");
                        tmpl?.SendConsoleCommand("ddraw.text", 30, Color.green, pls.Value.loc + new Vector3(0, 1.5f, 0), $"<size=20>{pls.Value.loc}</size>");
                    }
                    break;
                    case "gui" : case "select" : CuiHelper.DestroyUi(player, NPCGUI);
                    CuiHelper.DestroyUi(player, NPCGUS);
                    NPCSelectGUI(player);
                    break;
                    case "debug" : configData.Options.debug = !configData.Options.debug;
                    //SaveConfig();
                    Message(iplayer, "debug", configData.Options.debug.ToString());
                    break;
                    case "selclose" : CuiHelper.DestroyUi(player, NPCGUS);
                    IsOpen(player.userID, false);
                    break;
                    case "list" : foreach (KeyValuePair<ulong, HumanoidInfo> pls in npcs) {
                        string ns = pls.Value.displayName + "(" + pls.Key.ToString() + ")";
                        Message(iplayer, ns);
                    }
                    break;
                    case "spawn" : case "create" : case "new" : if (player?.transform != null) {
                        HumanoidInfo npc = new(0, player.transform.position, player.transform.rotation);
                        ulong x;
                        SpawnNPC(npc, out x);
                        Message(iplayer, "spawnedat", player.transform.position.ToString(), x.ToString());
                        NPCSelectGUI(player);
                    }
                    else {
                        HumanoidInfo npc = new(0, Vector3.zero, new Quaternion());
                        ulong x;
                        SpawnNPC(npc, out x);
                        Message(iplayer, "spawnedat", Vector3.zero.ToString(), x.ToString());
                    }
                    break;
                    case "edit" : {
                        if (args.Length > 1) {
                            ulong npcid;
                            ulong.TryParse(args[1], out npcid);
                            if (npcid > 0) {
                                NpcEditGUI(player, npcid);
                                break;
                            }
                            else {
                                List<string> newarg = new(args);
                                newarg.RemoveAt(0);
                                string nom = string.Join(" ", newarg);
                                foreach (KeyValuePair<ulong, HumanoidInfo> pls in npcs) {
                                    DoLog($"Checking match of {nom} to {pls.Value.displayName}");
                                    if (string.Equals(pls.Value.displayName, nom, StringComparison.OrdinalIgnoreCase)) {
                                        NpcEditGUI(player, pls.Value.userid);
                                        break;
                                    }
                                }
                            }
                        }
                        else {
                            DoLog("Looking for npc...");
                            RaycastHit hit;
                            if (Physics.Raycast(player.eyes.HeadRay(), out hit, 3f, playerMask)) {
                                BasePlayer pl = hit.GetEntity().ToPlayer();
                                foreach (KeyValuePair<ulong, HumanoidInfo> Npc in npcs) {
                                    if (Npc.Value.userid == pl.userID) {
                                        NpcEditGUI(player, Npc.Key);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    break;
                    case "delete" : case "remove" : {
                        if (args.Length > 1) {
                            CuiHelper.DestroyUi(player, NPCGUI);
                            ulong npcid = ulong.Parse(args[1]);
                            foreach (KeyValuePair<ulong, HumanoidInfo> pls in npcs) {
                                if (pls.Value.displayName == args[1]) {
                                    RemoveNPC(pls.Value);
                                    break;
                                }
                                else if (npcid == pls.Value.userid) {
                                    RemoveNPC(pls.Value);
                                    break;
                                }
                            }
                            if (isopen.Contains(player.userID)) NPCSelectGUI(player);
                        }
                        else {
                            RaycastHit hit;
                            if (Physics.Raycast(player.eyes.HeadRay(), out hit, 3f, playerMask)) {
                                BasePlayer pl = hit.GetEntity().ToPlayer();
                                if (pl.userID > 0) {
                                    HumanoidInfo isnpc = npcs[pl.userID];
                                    if (isnpc != null) {
                                        RemoveNPC(isnpc);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                    break;
                    case "npcselkit" : if (args.Length > 2) {
                        NPCKitGUI(player, ulong.Parse(args[1]), args[2]);
                    }
                    break;
                    case "npcselmonstart" : if (args.Length > 2) {
                        NPCMonGUI(player, ulong.Parse(args[1]), args[2], "start");
                    }
                    break;
                    case "npcselmonend" : if (args.Length > 2) {
                        NPCMonGUI(player, ulong.Parse(args[1]), args[2], "end");
                    }
                    break;
                    case "npcselroad" : if (args.Length > 2) {
                        if (args.Length > 3) {
                            NPCRoadGUI(player, ulong.Parse(args[1]), args[2] + " " + args[3]);
                        }
                        else {
                            NPCRoadGUI(player, ulong.Parse(args[1]), args[2]);
                        }
                    }
                    break;
                    case "npcselloco" : if (args.Length > 1) {
                        NPCLocoGUI(player, ulong.Parse(args[1]));
                    }
                    break;
                    case "kitsel" : if (args.Length > 2) {
                        CuiHelper.DestroyUi(player, NPCGUK);
                        ulong userid = ulong.Parse(args[1]);
                        HumanoidInfo npc = npcs[userid];
                        npc.kit = args[2];
                        HumanoidPlayer hp = FindHumanoidByID(userid);
                        SaveData();
                        RespawnNPC(hp.player);
                        NpcEditGUI(player, userid);
                    }
                    break;
                    case "monsel" : if (args.Length > 2) {
                        CuiHelper.DestroyUi(player, NPCGUM);
                        ulong userid = ulong.Parse(args[1]);
                        HumanoidInfo npc = npcs[userid];
                        switch (args[3]) {
                            case "end" : npc.monend = args[2];
                            break;
                            default : npc.monstart = args[2];
                            break;
                        }
                        HumanoidPlayer hp = FindHumanoidByID(userid);
                        SaveData();
                        RespawnNPC(hp.player);
                        NpcEditGUI(player, userid);
                    }
                    break;
                    case "roadsel" : if (args.Length > 2) {
                        CuiHelper.DestroyUi(player, NPCGUR);
                        ulong userid = ulong.Parse(args[1]);
                        HumanoidInfo npc = npcs[userid];
                        if (args[2] == "none") {
                            npc.roadname = null;
                        }
                        else {
                            npc.roadname = args[2] + " " + args[3];
                        }
                        HumanoidPlayer hp = FindHumanoidByID(userid);
                        SaveData();
                        RespawnNPC(hp.player);
                        NpcEditGUI(player, userid);
                    }
                    break;
                    case "locomode" : if (args.Length > 2) {
                        CuiHelper.DestroyUi(player, NPCGUL);
                        ulong userid = ulong.Parse(args[1]);
                        HumanoidInfo npc = npcs[userid];
                        LocoMode locomode;
                        Enum.TryParse(args[2], out locomode);
                        npc.locomode = locomode;
                        npc.defaultLoco = locomode;
                        HumanoidPlayer hp = FindHumanoidByID(userid);
                        SaveData();
                        RespawnNPC(hp.player);
                        NpcEditGUI(player, userid);
                    }
                    break;
                    case "spawnhere" : if (args.Length > 1) {
                        ulong npcid = ulong.Parse(args[1]);
                        string newSpawn = player.transform.position.x.ToString() + "," + player.transform.position.y + "," + player.transform.position.z.ToString();
                        Vector3 ns = player.transform.position;
                        Quaternion newRot;
                        TryGetPlayerView(player, out newRot);
                        HumanoidPlayer hp = FindHumanoidByID(npcid);
                        SetHumanoidInfo(npcid, "spawn", newSpawn);
                        //Teleport(hp.player, ns);
                        //hp.player.EndSleeping();
                        //npcs[npcid].loc = ns;
                        npcs[npcid].rot = newRot;
                        SaveData();
                        //RespawnNPC(hp.player); // Already done by SetHumanoidInfo above
                        if (configData.Options.closeGUIOnSpawnHere) {
                            CuiHelper.DestroyUi(player, NPCGUI);
                            CuiHelper.DestroyUi(player, NPCGUK);
                            CuiHelper.DestroyUi(player, NPCGUL);
                            CuiHelper.DestroyUi(player, NPCGUN);
                            CuiHelper.DestroyUi(player, NPCGUR);
                            CuiHelper.DestroyUi(player, NPCGUS);
                            CuiHelper.DestroyUi(player, NPCGUV);
                            return;
                        }
                        NpcEditGUI(player, npcid);
                    }
                    break;
                    case "tpto" : if (args.Length > 1) {
                        ulong npcid = ulong.Parse(args[1]);
                        CuiHelper.DestroyUi(player, NPCGUI);
                        CuiHelper.DestroyUi(player, NPCGUK);
                        CuiHelper.DestroyUi(player, NPCGUL);
                        CuiHelper.DestroyUi(player, NPCGUN);
                        CuiHelper.DestroyUi(player, NPCGUR);
                        CuiHelper.DestroyUi(player, NPCGUS);
                        CuiHelper.DestroyUi(player, NPCGUV);
                        IsOpen(player.userID, false);
                        Teleport(player, npcs[npcid].loc);
                    }
                    break;
                    case "npctoggle" : if (args.Length > 3) {
                        ulong userid = ulong.Parse(args[1]);
                        string toset = args[2];
                        string newval = args[3] == "True" ? "false" : "true";
                        SetHumanoidInfo(userid, args[2], args[3]);
                        NpcEditGUI(player, userid);
                        SaveData();
                    }
                    break;
                    case "npcset" : if (args.Length > 1) {
                        ulong userid = ulong.Parse(args[1]);
                        SetHumanoidInfo(userid, args[2], args[4]);
                    }
                    break;
                    case "selkitclose" : CuiHelper.DestroyUi(player, NPCGUK);
                    break;
                    case "selmonclose" : CuiHelper.DestroyUi(player, NPCGUM);
                    break;
                    case "selroadclose" : CuiHelper.DestroyUi(player, NPCGUR);
                    break;
                    case "sellococlose" : CuiHelper.DestroyUi(player, NPCGUL);
                    break;
                    case "close" : IsOpen(player.userID, false);
                    CuiHelper.DestroyUi(player, NPCGUI);
                    CuiHelper.DestroyUi(player, NPCGUK);
                    CuiHelper.DestroyUi(player, NPCGUS);
                    break;
                }
            }
        }
#endregion
#region Our Inbound Hooks
        private bool IsHumanoid(BasePlayer player) => player?.GetComponentInParent<HumanoidPlayer>() != null;
        private ulong SpawnHumanoid(Vector3 position, Quaternion currentRot, string name = "noid", bool ephemeral = false, ulong clone = 0) {
            foreach (KeyValuePair<ulong, HumanoidInfo> pair in npcs) {
                if (pair.Value.displayName == name && clone == 0) {
                    return pair.Key;
                }
            }
            ulong npcid = 0;
            HumanoidInfo hi = new(npcid, position, currentRot) {
                displayName = name, ephemeral = ephemeral
            }
            ;
            SpawnNPC(hi, out npcid);
            return npcid;
        }
        private string GetHumanoidName(ulong npcid) {
            DoLog($"Looking for humanoid: {npcid}");
            HumanoidPlayer hp = FindHumanoidByID(npcid);
            if (hp == null) return null;
            DoLog($"Found humanoid: {hp.info.displayName}");
            return hp.info.displayName;
        }
        private bool RemoveHumanoidById(ulong npcid) {
            DoLog($"RemoveHumanoidById called for {npcid}");
            HumanoidPlayer hp = FindHumanoidByID(npcid);
            if (hp == null) return false;
            BasePlayer npc = hp.GetComponentInParent<BasePlayer>();
            if (npc == null) return false;
            KillNpc(npc);
            npcs.Remove(hp.info.userid);
            SaveData();
            return true;
        }
        private bool RemoveHumanoidByName(string name) {
            DoLog($"RemoveHumanoidByName called for {name}");
            HumanoidPlayer hp = FindHumanoidByName(name);
            if (hp == null) return false;
            BasePlayer npc = hp.GetComponentInParent<BasePlayer>();
            if (npc == null) return false;
            KillNpc(npc);
            npcs.Remove(hp.info.userid);
            SaveData();
            return true;
        }
        private void SetHumanoidInfo(ulong npcid, string toset, string data, string rot = null) {
            DoLog($"SetHumanoidInfo called for {npcid} {toset},{data}");
            HumanoidPlayer hp = FindHumanoidByID(npcid);
            if (hp == null) return;
            switch (toset) {
                case "kit" : hp.info.kit = data;
                break;
                case "entrypause" : hp.info.entrypause = !GetBoolValue(data);
                break;
                case "entrypausetime" : hp.info.entrypausetime = Convert.ToSingle(data);
                break;
                case "health" : hp.info.health = Convert.ToSingle(data);
                hp.UpdateHealth(hp.info);
                break;
                case "name" : case "displayName" : hp.info.displayName = data;
                break;
                case "invulnerable" : case "invulnerability" : hp.info.invulnerable = !GetBoolValue(data);
                break;
                case "lootable" : hp.info.lootable = !GetBoolValue(data);
                break;
                case "shopnpc" : hp.info.shopnpc = !GetBoolValue(data);
                break;
                case "ahostile" : hp.info.ahostile = !GetBoolValue(data);
                break;
                case "hostile" : hp.info.hostile = !GetBoolValue(data);
                break;
                case "gather" : hp.info.gather = !GetBoolValue(data);
                hp.info.canmove = hp.info.defend;
                break;
                case "defend" : hp.info.defend = !GetBoolValue(data);
                hp.info.canmove = hp.info.defend;
                break;
                case "evade" : hp.info.evade = !GetBoolValue(data);
                hp.info.canmove = hp.info.evade;
                break;
                case "follow" : hp.info.follow = !GetBoolValue(data);
                hp.info.canmove = hp.info.follow;
                break;
                case "canmove" : hp.info.canmove = !GetBoolValue(data);
                break;
                case "allowsit" : case "cansit" : hp.info.cansit = !GetBoolValue(data);
                hp.info.canmove = hp.info.cansit;
                hp.info.locomode = LocoMode.Sit;
                break;
                case "canride" : hp.info.canride = !GetBoolValue(data);
                hp.info.canmove = hp.info.canride;
                hp.info.locomode = LocoMode.Ride;
                break;
                case "needsammo" : case "needsAmmo" : hp.info.needsammo = !GetBoolValue(data);
                break;
                case "dropWeapon" : hp.info.dropWeapon = !GetBoolValue(data);
                break;
                case "respawn" : hp.info.respawn = !GetBoolValue(data);
                break;
                case "respawnTimer" : case "respawntimer" : hp.info.respawnTimer = Convert.ToSingle(data);
                break;
                case "attackdistance" : hp.info.attackDistance = Convert.ToSingle(data);
                break;
                case "maxdistance" : hp.info.maxDistance = Convert.ToSingle(data);
                break;
                case "damagedistance" : hp.info.damageDistance = Convert.ToSingle(data);
                break;
                case "locomode" : switch (Convert.ToInt32(data)) {
                    default : hp.info.locomode = LocoMode.Default;
                    break;
                    case 1 : hp.info.locomode = LocoMode.Follow;
                    break;
                    case 2 : hp.info.locomode = LocoMode.Sit;
                    break;
                    case 4 : hp.info.locomode = LocoMode.Stand;
                    break;
                    case 8 : hp.info.locomode = LocoMode.Road;
                    break;
                    case 16 : hp.info.locomode = LocoMode.Ride;
                    break;
                    case 32 : hp.info.locomode = LocoMode.Monument;
                    break;
                }
                break;
                case "speed" : hp.info.speed = Convert.ToSingle(data);
                break;
                case "spawn" : case "loc" : hp.info.loc = StringToVector3(data);
                break;
                case "townrel" : hp.info.townRel = StringToVector3(data);
                break;
                case "rot" : hp.info.rot = StringToQuaternion(data);
                break;
            }
            DoLog("Saving Data");
            SaveData();
            DoLog("Respawning");
            RespawnNPC(hp.player);
        }
        private void GiveHumanoid(ulong npcid, string itemname, string loc = "wear", ulong skinid = 0, int count = 1) {
            HumanoidPlayer npc = FindHumanoidByID(npcid);
            DoLog($"GiveHumanoid called: {npc.info.displayName}, {itemname}, {loc}");
            if (npc.player != null) {
                switch (loc) {
                    case "kit" : npc.info.kit = itemname;
                    UpdateInventory(npc);
                    break;
                    case "belt" : {
                        Item item = ItemManager.CreateByName(itemname, 1, skinid);
                        item.MoveToContainer(npc.player.inventory.containerBelt, -1, true);
                        if (item.info.category == ItemCategory.Weapon) npc.EquipFirstWeapon();
                    }
                    break;
                    case "main" : {
                        // e.g.for ammo
                        Item item = ItemManager.CreateByName(itemname, count, skinid);
                        item.MoveToContainer(npc.player.inventory.containerMain, -1, true);
                        if (item.info.category == ItemCategory.Weapon) npc.EquipFirstWeapon();
                    }
                    break;
                    default : {
                        Item item = ItemManager.CreateByName(itemname, 1, skinid);
                        item.MoveToContainer(npc.player.inventory.containerWear, -1, true);
                    }
                    break;
                }
                npc.player.inventory.ServerUpdate(0f);
            }
        }
#endregion
#region GUI
        // Determine open GUI to limit interruptions
        private void IsOpen(ulong uid, bool set = false) {
            if (set) {
                DoLog($"Setting isopen for {uid}");
                if (!isopen.Contains(uid)) isopen.Add(uid);
                return;
            }
            DoLog($"Clearing isopen for {uid}");
            isopen.Remove(uid);
        }
        private void NPCSelectGUI(BasePlayer player) {
            if (player == null) return;
            IsOpen(player.userID, true);
            CuiHelper.DestroyUi(player, NPCGUS);
            string description = Lang("npcguisel");
            CuiElementContainer container = UI.Container(NPCGUS, UI.Color("242424", 1f), "0.1 0.1", "0.9 0.9", true, "Overlay");
            UI.Label(ref container, NPCGUS, UI.Color("#ffffff", 1f), description, 18, "0.23 0.92", "0.7 1");
            UI.Label(ref container, NPCGUS, UI.Color("#2244cc", 1f), Lang("standard"), 12, "0.79 0.92", "0.86 1");
            UI.Button(ref container, NPCGUS, UI.Color("#d85540", 1f), Lang("close"), 12, "0.92 0.93", "0.985 0.98", "noid selclose");
            int col = 0;
            int row = 0;
            foreach (KeyValuePair<ulong, HumanoidInfo> npc in npcs) {
                if (row > 10) {
                    row = 0;
                    col++;
                }
                const string color = "#2244cc";
                string hName = npc.Value.displayName;
                float[] posb = GetButtonPositionP(row, col);
                UI.Button(ref container, NPCGUS, UI.Color(color, 1f), hName, 12, $"{posb[0]} {posb[1]}", $"{posb[0] + ((posb[2] - posb[0]) / 2)} {posb[3]}", $"noid edit {npc.Value.displayName}");
                row++;
            }
            float[] posn = GetButtonPositionP(row, col);
            UI.Button(ref container, NPCGUS, UI.Color("#cc3333", 1f), Lang("new"), 12, $"{posn[0]} {posn[1]}", $"{posn[0] + ((posn[2] - posn[0]) / 2)} {posn[3]}", $"noid new");
            CuiHelper.AddUi(player, container);
        }
        private void NpcEditGUI(BasePlayer player, ulong npc = 0) {
            if (player == null) return;
            IsOpen(player.userID, true);
            CuiHelper.DestroyUi(player, NPCGUI);
            string npcname = Lang("needselect");
            if (npc > 0) {
                npcname = Lang("editing") + " " + npcs[npc].displayName + "(" + npc.ToString() + ")";
            }
            CuiElementContainer container = UI.Container(NPCGUI, UI.Color("2b2b2b", 1f), "0.05 0.05", "0.95 0.95", true, "Overlay");
            if (npc == 0) {
                UI.Button(ref container, NPCGUI, UI.Color("#cc3333", 1f), Lang("new"), 12, "0.79 0.95", "0.85 0.98", $"noid new");
            }
            else {
                UI.Button(ref container, NPCGUI, UI.Color("#cc3333", 1f), Lang("remove"), 12, "0.79 0.95", "0.85 0.98", $"noid remove {npc}");
            }
            UI.Button(ref container, NPCGUI, UI.Color("#d85540", 1f), Lang("select"), 12, "0.86 0.95", "0.92 0.98", $"noid select");
            UI.Button(ref container, NPCGUI, UI.Color("#d85540", 1f), Lang("close"), 12, "0.93 0.95", "0.99 0.98", $"noid close");
            UI.Label(ref container, NPCGUI, UI.Color("#ffffff", 1f), Lang("npcgui") + ": " + npcname, 24, "0.2 0.92", "0.7 1");
            int col = 0;
            int row = 0;
            if (npc == 0) {
                UI.Label(ref container, NPCGUI, UI.Color("#ffffff", 1f), Lang("mustselect"), 24, "0.2 0.47", "0.7 0.53");
            }
            else {
                Dictionary<string, string> npcinfo = new() {
                    {
                        "displayName", npcs[npc].displayName
                    }
                    , {
                        "kit", npcs[npc].kit
                    }
                    , {
                        "loc", npcs[npc].loc.ToString()
                    }
                    , {
                        "health", npcs[npc].health.ToString()
                    }
                    , {
                        "invulnerable", npcs[npc].invulnerable.ToString()
                    }
                    , {
                        "lootable", npcs[npc].lootable.ToString()
                    }
                    , {
                        "shopnpc", npcs[npc].shopnpc.ToString()
                    }
                    , {
                        "ahostile", npcs[npc].ahostile.ToString()
                    }
                    , {
                        "hostile", npcs[npc].hostile.ToString()
                    }
                    , {
                        "defend", npcs[npc].defend.ToString()
                    }
                    , {
                        "evade", npcs[npc].evade.ToString()
                    }
                    , {
                        "follow", npcs[npc].follow.ToString()
                    }
                    , {
                        "followtime", npcs[npc].followTime.ToString()
                    }
                    , {
                        "canmove", npcs[npc].canmove.ToString()
                    }
                    , {
                        "cansit", npcs[npc].cansit.ToString()
                    }
                    , {
                        "canride", npcs[npc].canride.ToStri
// ... [Code preview truncated due to length. Full source in attached file] ...

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