Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RoleplayNPCs v0.9.30
RoleplayNPCs.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dynamics; using HarmonyLib; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; [assembly: AssemblyProduct("RoleplayNPCs")] [assembly: AssemblyDescription("Decorative human residents for Valheim")] [assembly: AssemblyFileVersion("0.9.30.0")] [assembly: AssemblyTitle("RoleplayNPCs")] [assembly: AssemblyCompany("RoleplayNPCs contributors")] [assembly: ComVisible(false)] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.9.30.0")] namespace RoleplayNPCs; [HarmonyPatch(typeof(Character), "Damage")] internal static class CharacterDamagePatch { [HarmonyPrefix] private static bool Prefix(Character __instance) { if (RoleplayNPCPlugin.Settings == null || !RoleplayNPCPlugin.Settings.Invulnerable.Value) { return true; } if (!((Object)(object)__instance == (Object)null)) { return (Object)(object)((Component)__instance).GetComponent<RoleplayNpc>() == (Object)null; } return true; } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class CharacterRpcDamagePatch { [HarmonyPrefix] private static bool Prefix(Character __instance) { if (RoleplayNPCPlugin.Settings == null || !RoleplayNPCPlugin.Settings.Invulnerable.Value) { return true; } if (!((Object)(object)__instance == (Object)null)) { return (Object)(object)((Component)__instance).GetComponent<RoleplayNpc>() == (Object)null; } return true; } } [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class CharacterApplyDamagePatch { [HarmonyPrefix] private static bool Prefix(Character __instance) { if (RoleplayNPCPlugin.Settings == null || !RoleplayNPCPlugin.Settings.Invulnerable.Value) { return true; } if (!((Object)(object)__instance == (Object)null)) { return (Object)(object)((Component)__instance).GetComponent<RoleplayNpc>() == (Object)null; } return true; } } [HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[] { typeof(Character), typeof(Character) })] internal static class RoleplayNpcHostilityPatch { [HarmonyPrefix] private static bool Prefix(Character __0, Character __1, ref bool __result) { if (((Object)(object)__0 != (Object)null && (Object)(object)((Component)__0).GetComponent<RoleplayNpc>() != (Object)null) || ((Object)(object)__1 != (Object)null && (Object)(object)((Component)__1).GetComponent<RoleplayNpc>() != (Object)null)) { __result = false; return false; } return true; } } internal static class NpcAdminAccess { private const string RequestRpc = "RPNPC_AdminAccessRequest"; private const string ReplyRpc = "RPNPC_AdminAccessReply"; private static ZNet _net; private static ZRoutedRpc _rpc; private static ZNetPeer _server; private static Player _player; private static string _nonce; private static float _pendingUntil; private static float _nextQuery; private static float _grantUntil; private static readonly Dictionary<long, float> LastQuery = new Dictionary<long, float>(); internal static bool CanManage { get { Tick(); if ((Object)(object)_net != (Object)null) { if (!_net.IsServer()) { if ((Object)(object)_player != (Object)null && _server != null) { return Time.unscaledTime < _grantUntil; } return false; } return true; } return false; } } internal static bool AwaitingConfirmation { get { Tick(); if (_nonce != null) { return Time.unscaledTime >= _grantUntil; } return false; } } internal static void Reset() { _net = null; _rpc = null; _server = null; _player = null; _nonce = null; _pendingUntil = (_nextQuery = (_grantUntil = 0f)); LastQuery.Clear(); } internal static void Tick() { ZNet instance = ZNet.instance; ZRoutedRpc instance2 = ZRoutedRpc.instance; ZNetPeer val = (((Object)(object)instance == (Object)null || instance.IsServer()) ? null : instance.GetServerPeer()); Player localPlayer = Player.m_localPlayer; if (!object.ReferenceEquals(instance, _net) || !object.ReferenceEquals(instance2, _rpc) || !object.ReferenceEquals(val, _server) || !object.ReferenceEquals(localPlayer, _player)) { bool flag = instance2 != null && !object.ReferenceEquals(instance2, _rpc); Reset(); _net = instance; _rpc = instance2; _server = val; _player = localPlayer; if (flag) { instance2.Register<string>("RPNPC_AdminAccessRequest", (Action<long, string>)OnRequest); instance2.Register<string, bool>("RPNPC_AdminAccessReply", (Action<long, string, bool>)OnReply); } } if (!((Object)(object)instance == (Object)null) && instance2 != null && !instance.IsServer() && val != null && !((Object)(object)localPlayer == (Object)null)) { float unscaledTime = Time.unscaledTime; if (_nonce != null && unscaledTime >= _pendingUntil) { _nonce = null; } if (!(unscaledTime < _nextQuery)) { _nonce = Guid.NewGuid().ToString("N"); _pendingUntil = unscaledTime + 8f; _nextQuery = unscaledTime + 10f; instance2.InvokeRoutedRPC(val.m_uid, "RPNPC_AdminAccessRequest", new object[1] { _nonce }); } } } private static void OnRequest(long sender, string nonce) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer() || ZRoutedRpc.instance == null || instance.GetPeer(sender) == null || nonce == null || nonce.Length != 32 || !Guid.TryParseExact(nonce, "N", out var _)) { return; } Tick(); float unscaledTime = Time.unscaledTime; if (LastQuery.TryGetValue(sender, out var value) && unscaledTime - value < 2f) { return; } if (!LastQuery.ContainsKey(sender) && LastQuery.Count >= 128) { List<long> list = new List<long>(); foreach (KeyValuePair<long, float> item in LastQuery) { if (unscaledTime - item.Value >= 30f || instance.GetPeer(item.Key) == null) { list.Add(item.Key); } } foreach (long item2 in list) { LastQuery.Remove(item2); } if (LastQuery.Count >= 128) { return; } } LastQuery[sender] = unscaledTime; bool flag = NpcWardrobeRpc.IsAuthorizedAdmin(sender); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RPNPC_AdminAccessReply", new object[2] { nonce, flag }); } private static void OnReply(long sender, string nonce, bool allowed) { if (!((Object)(object)_net == (Object)null) && !_net.IsServer() && _server != null && !((Object)(object)_player == (Object)null) && object.ReferenceEquals(_net, ZNet.instance) && object.ReferenceEquals(_rpc, ZRoutedRpc.instance) && object.ReferenceEquals(_server, _net.GetServerPeer()) && object.ReferenceEquals(_player, Player.m_localPlayer) && sender == _server.m_uid && NpcWardrobeRpc.IsServerSender(sender) && _nonce != null && !(nonce != _nonce) && !(Time.unscaledTime >= _pendingUntil)) { _nonce = null; _grantUntil = (allowed ? (Time.unscaledTime + 30f) : 0f); } } } internal static class NpcAdminProtocol { private const string RequestRpc = "RPNPC_AdminRequest"; private const string ReplyRpc = "RPNPC_AdminReply"; private const int MaximumCommandLength = 2048; private static readonly Dictionary<string, ConsoleEvent> Actions = new Dictionary<string, ConsoleEvent>(StringComparer.OrdinalIgnoreCase); private static ZRoutedRpc _registeredInstance; private static bool _executingServerRequest; private static long _requesterPeer; private static ZDOID _requestTarget = ZDOID.None; private static Vector3 _requesterPosition; private static Vector3 _requesterForward = Vector3.forward; private static readonly List<string> ResponseLines = new List<string>(); internal static long RequesterPeer { get { if (!_executingServerRequest) { return ZNet.GetUID(); } return _requesterPeer; } } internal static bool IsExecutingServerRequest => _executingServerRequest; internal static void ReplyAfterDelay(long peer, bool success, string message) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { if (peer == ZNet.GetUID()) { ShowMessage(message); } else { SendReply(peer, success, message); } } } internal static void RegisterAction(string name, ConsoleEvent action) { if (!string.IsNullOrEmpty(name) && action != null) { Actions[name] = action; } } internal static void ExecuteFromLogbook(string line) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || !NpcAdminAccess.CanManage || string.IsNullOrEmpty(line) || line.Length > 2048 || line.IndexOfAny(new char[3] { '\n', '\r', ';' }) >= 0) { return; } NpcConsoleCommands.Register(); if (Actions.TryGetValue(line.Split(new char[1] { ' ' })[0], out var value)) { ConsoleEventArgs e = new ConsoleEventArgs(line, (Terminal)null, (ConsoleCommand)null); if (!ForwardToServer(e)) { value.Invoke(e); } } } internal static void Register() { if (ZRoutedRpc.instance != null && _registeredInstance != ZRoutedRpc.instance) { _registeredInstance = ZRoutedRpc.instance; _registeredInstance.Register<ZPackage>("RPNPC_AdminRequest", (Action<long, ZPackage>)OnRequest); _registeredInstance.Register<ZPackage>("RPNPC_AdminReply", (Action<long, ZPackage>)OnReply); } } internal static bool ForwardToServer(ConsoleEventArgs args) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) Register(); if (_executingServerRequest || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return false; } if (!NpcAdminAccess.CanManage) { ShowMessage("Only a server administrator can manage RoleplayNPCs."); return true; } if (args == null || string.IsNullOrEmpty(args.FullLine) || args.FullLine.Length > 2048 || ZRoutedRpc.instance == null) { ShowMessage("The RoleplayNPC command could not be sent to the server."); return true; } ZDOID val = ZDOID.None; float maximumRange = ((RoleplayNPCPlugin.Settings == null) ? 12f : NpcPersistence.ClampFinite(RoleplayNPCPlugin.Settings.CommandRange.Value, 0.5f, 100f, 12f)); RoleplayNpc roleplayNpc = NpcConsoleCommands.FindLookNpc(maximumRange); if ((Object)(object)roleplayNpc != (Object)null && (Object)(object)roleplayNpc.View != (Object)null && roleplayNpc.View.IsValid() && roleplayNpc.View.GetZDO() != null) { val = roleplayNpc.View.GetZDO().m_uid; } ZPackage val2 = new ZPackage(); val2.Write(args.FullLine); val2.Write(val); ZRoutedRpc.instance.InvokeRoutedRPC("RPNPC_AdminRequest", new object[1] { val2 }); return true; } internal static RoleplayNpc GetRequestTarget() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!_executingServerRequest || ((ZDOID)(ref _requestTarget)).IsNone()) { return null; } return RoleplayNpc.FindByZdoId(_requestTarget); } internal static bool TryGetRequesterPose(out Vector3 position, out Vector3 forward) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (_executingServerRequest) { position = _requesterPosition; forward = _requesterForward; return true; } if ((Object)(object)Player.m_localPlayer != (Object)null) { position = ((Component)Player.m_localPlayer).transform.position; forward = ((Component)Player.m_localPlayer).transform.forward; return true; } position = Vector3.zero; forward = Vector3.forward; return false; } internal static void CaptureResponse(string message) { if (_executingServerRequest && !string.IsNullOrEmpty(message)) { ResponseLines.Add(message); } } private static void OnRequest(long sender, ZPackage package) { //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZRoutedRpc.instance == null || package == null) { return; } if (!NpcWardrobeRpc.IsAuthorizedAdmin(sender)) { SendReply(sender, success: false, "Only a server administrator can manage RoleplayNPCs."); return; } string text; ZDOID val; try { text = package.ReadString(); val = package.ReadZDOID(); } catch (Exception ex) { RoleplayNPCPlugin.DebugLog("[NpcAdminProtocol] Rejected malformed request: " + ex.Message); SendReply(sender, success: false, "Malformed RoleplayNPC command request."); return; } if (string.IsNullOrEmpty(text) || text.Length > 2048) { SendReply(sender, success: false, "Invalid RoleplayNPC command request."); return; } string key = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0]; if (!Actions.TryGetValue(key, out var value)) { SendReply(sender, success: false, "The server does not recognize that RoleplayNPC command."); return; } if (!TryGetPeerPose(sender, out var position, out var forward)) { SendReply(sender, success: false, "The server could not resolve your player position."); return; } if (!((ZDOID)(ref val)).IsNone()) { RoleplayNpc roleplayNpc = RoleplayNpc.FindByZdoId(val); float num = ((RoleplayNPCPlugin.Settings == null) ? 12f : NpcPersistence.ClampFinite(RoleplayNPCPlugin.Settings.CommandRange.Value, 0.5f, 100f, 12f)); if ((Object)(object)roleplayNpc == (Object)null || Vector3.Distance(position, ((Component)roleplayNpc).transform.position) > num + 1f) { val = ZDOID.None; } } ResponseLines.Clear(); _executingServerRequest = true; _requesterPeer = sender; _requestTarget = val; _requesterPosition = position; _requesterForward = forward; try { value.Invoke(new ConsoleEventArgs(text, (Terminal)null, (ConsoleCommand)null)); string message = ((ResponseLines.Count == 0) ? "RoleplayNPC command completed on the server." : string.Join("\n", ResponseLines.ToArray())); SendReply(sender, success: true, message); } catch (Exception ex2) { RoleplayNPCPlugin.Log.LogError((object)("Server RoleplayNPC command failed: " + ex2)); SendReply(sender, success: false, "The RoleplayNPC command failed on the server."); } finally { _executingServerRequest = false; _requesterPeer = 0L; _requestTarget = ZDOID.None; ResponseLines.Clear(); } } internal static bool TryGetPeerPose(long sender, out Vector3 position, out Vector3 forward) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; forward = Vector3.forward; if ((Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null) { return false; } ZDOID val; if (sender == ZNet.GetUID()) { val = ZNet.instance.LocalPlayerCharacterID; } else { ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null) { return false; } val = peer.m_characterID; } ZDO zDO = ZDOMan.instance.GetZDO(val); if (zDO == null) { return false; } position = zDO.GetPosition(); forward = zDO.GetRotation() * Vector3.forward; forward.y = 0f; forward = ((((Vector3)(ref forward)).sqrMagnitude < 0.01f) ? Vector3.forward : ((Vector3)(ref forward)).normalized); return true; } private static void SendReply(long sender, bool success, string message) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown if (ZRoutedRpc.instance != null) { ZPackage val = new ZPackage(); val.Write(success); val.Write(message ?? string.Empty); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RPNPC_AdminReply", new object[1] { val }); } } private static void OnReply(long sender, ZPackage package) { if (!NpcWardrobeRpc.IsServerSender(sender) || package == null) { return; } try { bool flag = package.ReadBool(); string text = package.ReadString(); ShowMessage((flag ? string.Empty : "RoleplayNPCs: ") + text); } catch (Exception ex) { RoleplayNPCPlugin.DebugLog("[NpcAdminProtocol] Rejected malformed reply: " + ex.Message); } } private static void ShowMessage(string message) { bool flag = message?.StartsWith("[Dialogue] ", StringComparison.Ordinal) ?? false; if (!flag) { NpcResidentLogbook.Record(message); } if ((Object)(object)MessageHud.instance != (Object)null) { string text = ((message != null && (message.IndexOf('\n') >= 0 || message.Length > 180)) ? "RoleplayNPC server response received; see the console." : message); MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true); } if ((Object)(object)Console.instance != (Object)null) { ((Terminal)Console.instance).AddString(message); } if (!flag && RoleplayNPCPlugin.Log != null) { RoleplayNPCPlugin.Log.LogInfo((object)message); } } } public sealed class NpcAppearance { private static readonly string[] HairOptions = new string[38] { "Hair1", "Hair2", "Hair3", "Hair4", "Hair5", "Hair6", "Hair7", "Hair8", "Hair9", "Hair10", "Hair11", "Hair12", "Hair13", "Hair14", "Hair15", "Hair16", "Hair17", "Hair18", "Hair19", "Hair20", "Hair21", "Hair22", "Hair23", "Hair24", "Hair25", "Hair26", "Hair27", "Hair28", "Hair29", "Hair30", "Hair31", "Hair32", "Hair33", "Hair34", "Hair35", "Hair36", "Hair37", "Hair38" }; private static readonly string[] BeardOptions = new string[29] { "", "", "", "Beard1", "Beard2", "Beard3", "Beard4", "Beard5", "Beard6", "Beard7", "Beard8", "Beard9", "Beard10", "Beard11", "Beard12", "Beard13", "Beard14", "Beard15", "Beard16", "Beard17", "Beard18", "Beard19", "Beard20", "Beard21", "Beard22", "Beard23", "Beard24", "Beard25", "Beard26" }; private static readonly Vector3[] HairColors = (Vector3[])(object)new Vector3[10] { new Vector3(0.08f, 0.06f, 0.04f), new Vector3(0.16f, 0.1f, 0.06f), new Vector3(0.3f, 0.18f, 0.09f), new Vector3(0.48f, 0.3f, 0.13f), new Vector3(0.68f, 0.5f, 0.24f), new Vector3(0.82f, 0.68f, 0.42f), new Vector3(0.38f, 0.12f, 0.05f), new Vector3(0.62f, 0.2f, 0.07f), new Vector3(0.42f, 0.42f, 0.4f), new Vector3(0.72f, 0.72f, 0.68f) }; private static readonly Vector3[] SkinColors = (Vector3[])(object)new Vector3[6] { new Vector3(0.98f, 0.88f, 0.76f), new Vector3(0.94f, 0.79f, 0.65f), new Vector3(0.86f, 0.67f, 0.51f), new Vector3(0.72f, 0.5f, 0.35f), new Vector3(0.55f, 0.35f, 0.23f), new Vector3(0.36f, 0.22f, 0.15f) }; public int ModelIndex; public string Hair; public string Beard; public Vector3 HairColor; public Vector3 SkinColor; public string Chest; public string Legs; public string Helmet; public string Cape; public static NpcAppearance Default() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) NpcAppearance npcAppearance = new NpcAppearance(); npcAppearance.ModelIndex = 1; npcAppearance.Hair = "Hair1"; npcAppearance.Beard = ""; npcAppearance.HairColor = new Vector3(0.55f, 0.38f, 0.18f); npcAppearance.SkinColor = new Vector3(0.95f, 0.82f, 0.68f); npcAppearance.Chest = "ArmorRagsChest"; npcAppearance.Legs = "ArmorRagsLegs"; npcAppearance.Helmet = ""; npcAppearance.Cape = ""; return npcAppearance; } public static NpcAppearance Randomized(int modelIndex) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) NpcAppearance npcAppearance = Default(); npcAppearance.ModelIndex = ((modelIndex != 0) ? 1 : 0); npcAppearance.Hair = HairOptions[Random.Range(0, HairOptions.Length)]; npcAppearance.Beard = ((npcAppearance.ModelIndex == 0) ? BeardOptions[Random.Range(0, BeardOptions.Length)] : ""); npcAppearance.HairColor = HairColors[Random.Range(0, HairColors.Length)]; npcAppearance.SkinColor = SkinColors[Random.Range(0, SkinColors.Length)]; return npcAppearance; } public string Serialize() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) CultureInfo invariantCulture = CultureInfo.InvariantCulture; NpcAppearance npcAppearance = Default(); Vector3 val = SanitizeColor(HairColor, npcAppearance.HairColor); Vector3 val2 = SanitizeColor(SkinColor, npcAppearance.SkinColor); return string.Join(";", "1", ModelIndex.ToString(invariantCulture), Safe(Hair), Safe(Beard), val.x.ToString("F3", invariantCulture), val.y.ToString("F3", invariantCulture), val.z.ToString("F3", invariantCulture), val2.x.ToString("F3", invariantCulture), val2.y.ToString("F3", invariantCulture), val2.z.ToString("F3", invariantCulture), Safe(Chest), Safe(Legs), Safe(Helmet), Safe(Cape)); } public static NpcAppearance Deserialize(string data) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(data)) { return Default(); } try { string[] array = data.Split(new char[1] { ';' }); if (array.Length < 14 || array[0] != "1") { return Default(); } CultureInfo invariantCulture = CultureInfo.InvariantCulture; NpcAppearance npcAppearance = new NpcAppearance(); npcAppearance.ModelIndex = int.Parse(array[1], invariantCulture); npcAppearance.Hair = array[2]; npcAppearance.Beard = array[3]; NpcAppearance npcAppearance2 = Default(); npcAppearance.HairColor = SanitizeColor(new Vector3(float.Parse(array[4], invariantCulture), float.Parse(array[5], invariantCulture), float.Parse(array[6], invariantCulture)), npcAppearance2.HairColor); npcAppearance.SkinColor = SanitizeColor(new Vector3(float.Parse(array[7], invariantCulture), float.Parse(array[8], invariantCulture), float.Parse(array[9], invariantCulture)), npcAppearance2.SkinColor); npcAppearance.Chest = array[10]; npcAppearance.Legs = array[11]; npcAppearance.Helmet = array[12]; npcAppearance.Cape = array[13]; return npcAppearance; } catch (Exception) { return Default(); } } private static string Safe(string value) { if (string.IsNullOrEmpty(value)) { return ""; } return value.Replace(";", ""); } private static Vector3 SanitizeColor(Vector3 value, Vector3 fallback) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) return new Vector3(NpcPersistence.ClampFinite(value.x, 0f, 1f, fallback.x), NpcPersistence.ClampFinite(value.y, 0f, 1f, fallback.y), NpcPersistence.ClampFinite(value.z, 0f, 1f, fallback.z)); } } internal static class NpcArchiveLifecycle { private static NpcRecoveryArchive _archive; private static NpcArchiveWorld _world; private static ZDOMan _manager; private static float _nextSave; internal static void Begin(ZNet net, bool loadError) { _archive = null; _world = null; _manager = null; if ((Object)(object)net == (Object)null || !net.IsServer() || loadError || ZDOMan.instance == null) { return; } try { _manager = ZDOMan.instance; _world = new NpcArchiveWorld(_manager, net.GetWorldUID()); NpcArchiveStore npcArchiveStore = new NpcArchiveStore(Path.Combine(Paths.ConfigPath, "RoleplayNPCs", "archives")); NpcRecoveryArchive npcRecoveryArchive = new NpcRecoveryArchive(npcArchiveStore, _world); int num = npcRecoveryArchive.Begin(RoleplayNPCPlugin.Settings.ArchiveAutoRestore.Value); _archive = npcRecoveryArchive; _nextSave = Time.unscaledTime + 60f; Save(); RoleplayNPCPlugin.Log.LogInfo((object)("NPC recovery archive: " + npcArchiveStore.PathFor(net.GetWorldUID()) + "; restored " + num + " missing resident(s).")); } catch (Exception ex) { _archive = null; RoleplayNPCPlugin.Log.LogWarning((object)("NPC archive unavailable for this session; existing files preserved: " + ex.Message)); } } private static bool Active() { if (_archive != null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { return object.ReferenceEquals(_manager, ZDOMan.instance); } return false; } internal static void Track(ZDO zdo) { if (Active() && zdo != null) { _world.Track(zdo); _archive.Track(zdo.GetString(NpcPersistence.UniqueId, "")); } } internal static void Tick() { if (Active() && !(Time.unscaledTime < _nextSave)) { _nextSave = Time.unscaledTime + 60f; Save(); } } internal static void Save() { if (!Active()) { return; } try { _archive.Save(); } catch (Exception ex) { RoleplayNPCPlugin.Log.LogWarning((object)("NPC archive save failed; will retry: " + ex.Message)); } } internal static void Deleted(ZDO zdo) { if (!Active() || zdo == null || zdo.GetPrefab() != StringExtensionMethods.GetStableHashCode("RP_HumanNPC")) { return; } try { _archive.Forget(zdo.GetString(NpcPersistence.UniqueId, "")); } catch (Exception ex) { RoleplayNPCPlugin.Log.LogWarning((object)("NPC archive deletion could not be saved; will retry: " + ex.Message)); } } internal static bool TryRetireResident(string id, out string reason) { reason = "the server recovery archive is unavailable; no records were removed"; if (!Active() || string.IsNullOrEmpty(id)) { return false; } try { _archive.Forget(id); reason = ""; return true; } catch (Exception ex) { _archive.Track(id); reason = "recovery retirement could not be saved: " + ex.Message; return false; } } } [HarmonyPatch(typeof(ZNet), "ServerLoadWorld")] internal static class NpcArchiveLoadPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, bool ___m_loadError) { NpcArchiveLifecycle.Begin(__instance, ___m_loadError); } } [HarmonyPatch(typeof(ZNet), "SaveWorld")] internal static class NpcArchiveSavePatch { [HarmonyPrefix] private static void Prefix() { NpcArchiveLifecycle.Save(); } } [HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")] internal static class NpcArchiveDeletePatch { [HarmonyPrefix] private static void Prefix(ZDOMan __instance, ZDOID uid) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) NpcArchiveLifecycle.Deleted(__instance.GetZDO(uid)); } } internal sealed class NpcArchivePoint { public float X; public float Y; public float Z; public float W; internal void Validate() { if (!Finite(X) || !Finite(Y) || !Finite(Z) || !Finite(W)) { throw new InvalidDataException("Non-finite archive coordinate."); } } internal static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal sealed class NpcArchiveData { internal static readonly string[] ReferenceKeys = new string[3] { "RPNPC_AssignedBed", "RPNPC_PoseExitFixture", "RPNPC_BathExitFixture" }; public NpcArchivePoint Position = new NpcArchivePoint(); public NpcArchivePoint Rotation = new NpcArchivePoint { W = 1f }; public Dictionary<int, float> Floats = new Dictionary<int, float>(); public Dictionary<int, NpcArchivePoint> Vectors = new Dictionary<int, NpcArchivePoint>(); public Dictionary<int, NpcArchivePoint> Quaternions = new Dictionary<int, NpcArchivePoint>(); public Dictionary<int, int> Ints = new Dictionary<int, int>(); public Dictionary<int, long> Longs = new Dictionary<int, long>(); public Dictionary<int, string> Strings = new Dictionary<int, string>(); public Dictionary<int, byte[]> Bytes = new Dictionary<int, byte[]>(); public Dictionary<string, NpcArchiveReference> References = new Dictionary<string, NpcArchiveReference>(); internal void Validate() { if (Position == null || Rotation == null || Floats == null || Vectors == null || Quaternions == null || Ints == null || Longs == null || Strings == null || Bytes == null || References == null) { throw new InvalidDataException("Incomplete resident archive data."); } Position.Validate(); Rotation.Validate(); foreach (float value2 in Floats.Values) { float value = value2; if (!NpcArchivePoint.Finite(value)) { throw new InvalidDataException("Non-finite archive value."); } } foreach (NpcArchivePoint value3 in Vectors.Values) { ValidatePoint(value3); } foreach (NpcArchivePoint value4 in Quaternions.Values) { ValidatePoint(value4); } foreach (string value5 in Strings.Values) { if (value5 == null) { throw new InvalidDataException("Null archive string."); } } foreach (byte[] value6 in Bytes.Values) { if (value6 == null) { throw new InvalidDataException("Null archive bytes."); } } foreach (KeyValuePair<string, NpcArchiveReference> reference in References) { if (Array.IndexOf(ReferenceKeys, reference.Key) < 0 || reference.Value == null || reference.Value.Prefab == 0) { throw new InvalidDataException("Invalid archived fixture reference."); } ValidatePoint(reference.Value.Position); } } private static void ValidatePoint(NpcArchivePoint value) { if (value == null) { throw new InvalidDataException("Null archive coordinate."); } value.Validate(); } } internal sealed class NpcArchiveReference { public int Prefab; public NpcArchivePoint Position; } internal sealed class NpcArchiveResident { public NpcArchiveData Npc; public NpcArchiveData Wardrobe; } internal sealed class NpcArchiveDocument { public int Version = 1; public long WorldUid; public Dictionary<string, NpcArchiveResident> Residents = new Dictionary<string, NpcArchiveResident>(); internal void Validate(long worldUid) { if (Version != 1 || WorldUid != worldUid || Residents == null || Residents.Count > 10000) { throw new InvalidDataException("Unsupported, wrong-world or oversized NPC archive."); } foreach (KeyValuePair<string, NpcArchiveResident> resident in Residents) { if (!Guid.TryParseExact(resident.Key, "N", out var _) || resident.Value == null || resident.Value.Npc == null) { throw new InvalidDataException("Invalid resident identity in archive."); } resident.Value.Npc.Validate(); if (resident.Value.Wardrobe != null) { resident.Value.Wardrobe.Validate(); } } } } internal sealed class NpcArchiveStore { private const int MaximumBytes = 67108864; private readonly string _directory; private string _lastJson; internal NpcArchiveStore(string directory) { _directory = directory; } internal string PathFor(long worldUid) { return Path.Combine(_directory, worldUid.ToString(CultureInfo.InvariantCulture) + ".json"); } private static JsonSerializerSettings Settings() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown JsonSerializerSettings val = new JsonSerializerSettings(); val.TypeNameHandling = (TypeNameHandling)0; val.MetadataPropertyHandling = (MetadataPropertyHandling)2; val.MaxDepth = 32; val.MissingMemberHandling = (MissingMemberHandling)1; return val; } internal NpcArchiveDocument Load(long worldUid) { string text = PathFor(worldUid); if (!File.Exists(text)) { NpcArchiveDocument npcArchiveDocument = new NpcArchiveDocument(); npcArchiveDocument.WorldUid = worldUid; return npcArchiveDocument; } if (new FileInfo(text).Length > 67108864) { throw new InvalidDataException("NPC archive exceeds 64 MiB."); } string text2 = File.ReadAllText(text, Encoding.UTF8); NpcArchiveDocument npcArchiveDocument2 = JsonConvert.DeserializeObject<NpcArchiveDocument>(text2, Settings()); if (npcArchiveDocument2 == null) { throw new InvalidDataException("Empty NPC archive."); } npcArchiveDocument2.Validate(worldUid); _lastJson = text2; return npcArchiveDocument2; } internal void Save(NpcArchiveDocument document) { document.Validate(document.WorldUid); string text = JsonConvert.SerializeObject((object)document, (Formatting)0, Settings()); if (Encoding.UTF8.GetByteCount(text) > 67108864) { throw new InvalidDataException("NPC archive exceeds 64 MiB."); } if (!(text == _lastJson)) { Directory.CreateDirectory(_directory); string text2 = PathFor(document.WorldUid); string text3 = text2 + ".tmp"; using (FileStream fileStream = new FileStream(text3, FileMode.Create, FileAccess.Write, FileShare.None)) { byte[] bytes = Encoding.UTF8.GetBytes(text); fileStream.Write(bytes, 0, bytes.Length); fileStream.Flush(flushToDisk: true); } if (File.Exists(text2)) { File.Replace(text3, text2, text2 + ".bak"); } else { File.Move(text3, text2); } _lastJson = text; } } } internal interface INpcArchiveWorld { long WorldUid { get; } IEnumerable<string> ResidentIds(); NpcArchiveResident Capture(string id); void Validate(string id, NpcArchiveResident resident); void Restore(string id, NpcArchiveResident resident); void RestoreWardrobe(string id, NpcArchiveResident resident); } internal sealed class NpcRecoveryArchive { private readonly NpcArchiveStore _store; private readonly INpcArchiveWorld _world; private readonly HashSet<string> _tracked = new HashSet<string>(); private NpcArchiveDocument _document; internal NpcRecoveryArchive(NpcArchiveStore store, INpcArchiveWorld world) { _store = store; _world = world; } internal int Begin(bool restoreMissing) { _document = _store.Load(_world.WorldUid); foreach (KeyValuePair<string, NpcArchiveResident> resident in _document.Residents) { _world.Validate(resident.Key, resident.Value); } foreach (string item in _world.ResidentIds()) { _tracked.Add(item); } int num = 0; if (restoreMissing) { foreach (KeyValuePair<string, NpcArchiveResident> resident2 in _document.Residents) { if (!_tracked.Contains(resident2.Key)) { _world.Restore(resident2.Key, resident2.Value); _tracked.Add(resident2.Key); num++; } else { _world.RestoreWardrobe(resident2.Key, resident2.Value); } } } else { _document.Residents.Clear(); } return num; } internal void Track(string id) { if (!string.IsNullOrEmpty(id)) { _tracked.Add(id); } } internal void Forget(string id) { _tracked.Remove(id); _document.Residents.Remove(id); _store.Save(_document); } internal void Save() { foreach (string item in _tracked) { NpcArchiveResident npcArchiveResident = _world.Capture(item); if (npcArchiveResident != null) { _document.Residents[item] = npcArchiveResident; } } _store.Save(_document); } } internal sealed class NpcArchiveWorld : INpcArchiveWorld { internal const string WardrobeResidentKey = "RPNPC_ArchiveWardrobeResident"; private static readonly FieldInfo ObjectsField = AccessTools.Field(typeof(ZDOMan), "m_objectsByID"); private readonly ZDOMan _manager; private readonly Dictionary<string, ZDOID> _residents = new Dictionary<string, ZDOID>(); private readonly Dictionary<ZDOID, string> _identities = new Dictionary<ZDOID, string>(); private readonly Dictionary<string, List<ZDOID>> _wardrobes = new Dictionary<string, List<ZDOID>>(); public long WorldUid { get; private set; } internal NpcArchiveWorld(ZDOMan manager, long worldUid) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) _manager = manager; WorldUid = worldUid; if (!(ObjectsField.GetValue(manager) is Dictionary<ZDOID, ZDO> dictionary)) { throw new InvalidOperationException("World resident index is unavailable."); } foreach (ZDO value2 in dictionary.Values) { Track(value2); if (value2.GetPrefab() != StringExtensionMethods.GetStableHashCode("RP_NPCWardrobe")) { continue; } string text = value2.GetString("RPNPC_ArchiveWardrobeResident", ""); if (!string.IsNullOrEmpty(text)) { if (!_wardrobes.TryGetValue(text, out var value)) { value = new List<ZDOID>(); _wardrobes.Add(text, value); } value.Add(value2.m_uid); } } } public IEnumerable<string> ResidentIds() { return _residents.Keys; } internal void Track(ZDO zdo) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || zdo.GetPrefab() != StringExtensionMethods.GetStableHashCode("RP_HumanNPC")) { return; } string text = zdo.GetString(NpcPersistence.UniqueId, ""); if (!string.IsNullOrEmpty(text)) { if (_identities.TryGetValue(zdo.m_uid, out var value) && value != text) { _residents.Remove(value); } _identities[zdo.m_uid] = text; _residents[text] = zdo.m_uid; } } public NpcArchiveResident Capture(string id) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) ZDOID value; ZDO val = (_residents.TryGetValue(id, out value) ? _manager.GetZDO(value) : null); if (val == null || val.GetString(NpcPersistence.UniqueId, "") != id) { return null; } ZDO val2 = _manager.GetZDO(val.GetZDOID("RPNPC_WardrobeZDO")); if (val2 != null && (val2.GetPrefab() != StringExtensionMethods.GetStableHashCode("RP_NPCWardrobe") || val2.GetZDOID("RPNPC_WardrobeNpcZDO") != val.m_uid)) { val2 = null; } if (val2 != null) { val2.Set("RPNPC_ArchiveWardrobeResident", id); } NpcArchiveResident npcArchiveResident = new NpcArchiveResident(); npcArchiveResident.Npc = Snapshot(val); npcArchiveResident.Wardrobe = ((val2 == null) ? null : Snapshot(val2)); return npcArchiveResident; } public void Validate(string id, NpcArchiveResident resident) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (!resident.Npc.Strings.TryGetValue(NpcPersistence.UniqueId, out var value) || value != id) { throw new InvalidDataException("Archive resident identity does not match its saved data."); } int num = 0; if (_wardrobes.TryGetValue(id, out var value2)) { foreach (ZDOID item in value2) { ZDO zDO = _manager.GetZDO(item); if (zDO != null && _manager.GetZDO(zDO.GetZDOID("RPNPC_WardrobeNpcZDO")) == null) { num++; } } } if (num > 1) { throw new InvalidDataException("Conflicting orphan wardrobes; automatic recovery stopped."); } } public void Restore(string id, NpcArchiveResident resident) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) ZDO val = Create(resident.Npc, "RP_HumanNPC"); val.Set(NpcPersistence.UniqueId, id); val.Set("RPNPC_WardrobeZDO", ZDOID.None); Track(val); RestoreWardrobe(id, resident); } public void RestoreWardrobe(string id, NpcArchiveResident resident) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (!_residents.TryGetValue(id, out var value)) { return; } ZDO zDO = _manager.GetZDO(value); if (zDO == null) { return; } ZDO zDO2 = _manager.GetZDO(zDO.GetZDOID("RPNPC_WardrobeZDO")); if (zDO2 != null && zDO2.GetPrefab() == StringExtensionMethods.GetStableHashCode("RP_NPCWardrobe") && zDO2.GetZDOID("RPNPC_WardrobeNpcZDO") == zDO.m_uid) { return; } ZDO val = null; if (_wardrobes.TryGetValue(id, out var value2)) { foreach (ZDOID item in value2) { ZDO zDO3 = _manager.GetZDO(item); if (zDO3 == null) { continue; } ZDO zDO4 = _manager.GetZDO(zDO3.GetZDOID("RPNPC_WardrobeNpcZDO")); if (zDO4 == null || zDO4 == zDO) { if (val != null) { throw new InvalidDataException("Conflicting wardrobe archives; automatic recovery stopped."); } val = zDO3; } } } if (val == null && resident.Wardrobe != null) { val = Create(resident.Wardrobe, "RP_NPCWardrobe"); } if (val != null) { val.SetPosition(zDO.GetPosition()); val.Set("RPNPC_ArchiveWardrobeResident", id); val.Set("RPNPC_WardrobeNpcZDO", zDO.m_uid); zDO.Set("RPNPC_WardrobeZDO", val.m_uid); } } private ZDO Create(NpcArchiveData data, string prefab) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) ZDO val = _manager.CreateNewZDO(Vector(data.Position), StringExtensionMethods.GetStableHashCode(prefab)); val.SetPrefab(StringExtensionMethods.GetStableHashCode(prefab)); val.SetPosition(Vector(data.Position)); val.SetRotation(new Quaternion(data.Rotation.X, data.Rotation.Y, data.Rotation.Z, data.Rotation.W)); foreach (KeyValuePair<int, float> @float in data.Floats) { val.Set(@float.Key, @float.Value); } foreach (KeyValuePair<int, NpcArchivePoint> vector in data.Vectors) { val.Set(vector.Key, Vector(vector.Value)); } foreach (KeyValuePair<int, NpcArchivePoint> quaternion in data.Quaternions) { val.Set(quaternion.Key, new Quaternion(quaternion.Value.X, quaternion.Value.Y, quaternion.Value.Z, quaternion.Value.W)); } foreach (KeyValuePair<int, int> @int in data.Ints) { val.Set(@int.Key, @int.Value, false); } foreach (KeyValuePair<int, long> @long in data.Longs) { val.Set(@long.Key, @long.Value); } foreach (KeyValuePair<int, string> @string in data.Strings) { val.Set(@string.Key, @string.Value); } foreach (KeyValuePair<int, byte[]> @byte in data.Bytes) { val.Set(@byte.Key, @byte.Value); } if (prefab == "RP_HumanNPC") { string[] referenceKeys = NpcArchiveData.ReferenceKeys; foreach (string text in referenceKeys) { val.Set(text, data.References.TryGetValue(text, out var value) ? Resolve(value) : ZDOID.None); } } val.Persistent = true; val.SetType((ObjectType)(prefab == "RP_HumanNPC")); val.SetDistant(false); val.SetOwner(ZDOMan.GetSessionID()); return val; } private ZDOID Resolve(NpcArchiveReference reference) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (!(ObjectsField.GetValue(_manager) is Dictionary<ZDOID, ZDO> dictionary)) { return ZDOID.None; } ZDOID result = ZDOID.None; Vector3 val = Vector(reference.Position); foreach (ZDO value in dictionary.Values) { if (value.GetPrefab() == reference.Prefab && !(Vector3.Distance(value.GetPosition(), val) > 0.05f)) { if (!((ZDOID)(ref result)).IsNone()) { return ZDOID.None; } result = value.m_uid; } } return result; } private NpcArchiveData Snapshot(ZDO zdo) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<int, float>> list = default(List<KeyValuePair<int, float>>); List<KeyValuePair<int, Vector3>> list2 = default(List<KeyValuePair<int, Vector3>>); List<KeyValuePair<int, Quaternion>> list3 = default(List<KeyValuePair<int, Quaternion>>); List<KeyValuePair<int, int>> list4 = default(List<KeyValuePair<int, int>>); List<KeyValuePair<int, long>> list5 = default(List<KeyValuePair<int, long>>); List<KeyValuePair<int, string>> list6 = default(List<KeyValuePair<int, string>>); List<KeyValuePair<int, byte[]>> list7 = default(List<KeyValuePair<int, byte[]>>); ZDOConnection val = default(ZDOConnection); ZDOExtraData.GetData(zdo.m_uid, ref list, ref list2, ref list3, ref list4, ref list5, ref list6, ref list7, ref val); Vector3 position = zdo.GetPosition(); Quaternion rotation = zdo.GetRotation(); NpcArchiveData npcArchiveData = new NpcArchiveData(); npcArchiveData.Position = Point(position); npcArchiveData.Rotation = new NpcArchivePoint { X = rotation.x, Y = rotation.y, Z = rotation.z, W = rotation.w }; NpcArchiveData npcArchiveData2 = npcArchiveData; foreach (KeyValuePair<int, float> item in list) { npcArchiveData2.Floats.Add(item.Key, item.Value); } foreach (KeyValuePair<int, Vector3> item2 in list2) { npcArchiveData2.Vectors.Add(item2.Key, Point(item2.Value)); } foreach (KeyValuePair<int, Quaternion> item3 in list3) { npcArchiveData2.Quaternions.Add(item3.Key, new NpcArchivePoint { X = item3.Value.x, Y = item3.Value.y, Z = item3.Value.z, W = item3.Value.w }); } foreach (KeyValuePair<int, int> item4 in list4) { npcArchiveData2.Ints.Add(item4.Key, item4.Value); } foreach (KeyValuePair<int, long> item5 in list5) { npcArchiveData2.Longs.Add(item5.Key, item5.Value); } foreach (KeyValuePair<int, string> item6 in list6) { npcArchiveData2.Strings.Add(item6.Key, item6.Value); } foreach (KeyValuePair<int, byte[]> item7 in list7) { npcArchiveData2.Bytes.Add(item7.Key, (byte[])item7.Value.Clone()); } if (zdo.GetPrefab() == StringExtensionMethods.GetStableHashCode("RP_HumanNPC")) { string[] referenceKeys = NpcArchiveData.ReferenceKeys; foreach (string text in referenceKeys) { ZDO zDO = _manager.GetZDO(zdo.GetZDOID(text)); if (zDO != null) { npcArchiveData2.References.Add(text, new NpcArchiveReference { Prefab = zDO.GetPrefab(), Position = Point(zDO.GetPosition()) }); } } } return npcArchiveData2; } private static NpcArchivePoint Point(Vector3 p) { NpcArchivePoint npcArchivePoint = new NpcArchivePoint(); npcArchivePoint.X = p.x; npcArchivePoint.Y = p.y; npcArchivePoint.Z = p.z; return npcArchivePoint; } private static Vector3 Vector(NpcArchivePoint p) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(p.X, p.Y, p.Z); } } internal sealed class NpcArrivalSpeech : MonoBehaviour { internal static readonly string[] NewArrival = new string[6] { "Wait... I should be dead. Is this the afterlife?", "I really should not have drunk so much yesterday.", "One moment, darkness. The next, this. Where am I?", "Well, my feet are on the ground. That is a start.", "Did someone call for me, or is this another strange dream?", "If this is the afterlife, I hope there is supper." }; internal static readonly string[] Recalled = new string[3] { "A little warning next time, please!", "That was quicker than walking. What do you need?", "Here again? Give me a moment to catch my breath." }; private static int _lastNew = -1; private static int _lastRecall = -1; private RoleplayNpc _npc; private string _line; private float _due; private float _expires; private bool _spoken; internal static bool IsPending(RoleplayNpc npc) { if (!Authority(npc)) { return false; } NpcArrivalSpeech component = ((Component)npc).GetComponent<NpcArrivalSpeech>(); if ((Object)(object)component != (Object)null && ((Behaviour)component).isActiveAndEnabled && (Object)(object)component._npc == (Object)(object)npc && !string.IsNullOrEmpty(component._line) && Time.time <= component._expires) { if (component._spoken) { return npc.IsSpeechActive; } return true; } return false; } private static bool Authority(RoleplayNpc npc) { if ((Object)(object)npc != (Object)null && ((Behaviour)npc).isActiveAndEnabled && (Object)(object)npc.View != (Object)null && npc.View.IsValid() && npc.View.IsOwner() && (Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } internal static void Queue(RoleplayNpc npc, bool recalled) { if (Authority(npc)) { RoleplayNpcAI component = ((Component)npc).GetComponent<RoleplayNpcAI>(); if ((Object)(object)component != (Object)null) { component.ResetFuelStockObservation(); } string[] array = (recalled ? Recalled : NewArrival); int num = (recalled ? _lastRecall : _lastNew); int num2 = Random.Range(0, (num < 0) ? array.Length : (array.Length - 1)); if (num2 >= num && num >= 0) { num2++; } if (recalled) { _lastRecall = num2; } else { _lastNew = num2; } NpcArrivalSpeech npcArrivalSpeech = ((Component)npc).GetComponent<NpcArrivalSpeech>(); if ((Object)(object)npcArrivalSpeech == (Object)null) { npcArrivalSpeech = ((Component)npc).gameObject.AddComponent<NpcArrivalSpeech>(); } npcArrivalSpeech._npc = npc; npcArrivalSpeech._line = array[num2]; npcArrivalSpeech._due = Time.time + 2f; npcArrivalSpeech._expires = Time.time + 12f; npcArrivalSpeech._spoken = false; ((Behaviour)npcArrivalSpeech).enabled = true; if (npc.IsSpeechActive) { npc.ClearSpeech(); } } } private void OnDisable() { Clear(); } private void Clear() { _npc = null; _line = null; _spoken = false; } private void Update() { if (string.IsNullOrEmpty(_line)) { return; } if (!Authority(_npc) || Time.time > _expires) { Clear(); } else if (_spoken) { if (!_npc.IsSpeechActive) { Clear(); } } else if (_npc.IsSpeechActive) { Clear(); } else if (!(Time.time < _due)) { RoleplayNpcAI component = ((Component)_npc).GetComponent<RoleplayNpcAI>(); if (!((Object)(object)component == (Object)null) && component.CanSpeakArrival) { _npc.Say(_line, 6f); _spoken = true; _expires = Time.time + 15f; } } } } public sealed class RoleplayNpcAI : BaseAI { private sealed class HomeMealPlan { internal TavernServing Meal; internal Vector3 Home; internal Vector3 SeatPosition; internal Vector3 SeatApproach; internal float Radius; internal float Until; internal int Probe; } private sealed class HomeServingHost : INpcWorkActivityHost { private readonly RoleplayNpcAI _ai; private readonly HomeMealPlan _plan; private float _nextValidation; public float Now => Time.time; public Vector3 Position => ((Component)_ai).transform.position; internal HomeServingHost(RoleplayNpcAI ai, HomeMealPlan plan) { _ai = ai; _plan = plan; } public bool Current(NpcWorkActivity a) { return object.ReferenceEquals(_ai._homeServingActivity, a); } public bool CanContinue(NpcWorkActivity a) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!_ai.HomeServingAuthority() || _ai._npc.HomePosition != _plan.Home || _ai._npc.HomeRadius != _plan.Radius || !_ai.ServingGuestStillSeated(_plan.Meal) || !_ai.ServingGuestNeedsMeal(_plan.Meal) || _plan.Meal.Day != NpcRelationships.Day || !object.ReferenceEquals(_plan.Meal.World, ZoneSystem.instance)) { return false; } if (Now < _nextValidation) { return true; } _nextValidation = Now + 1f; return _ai.CanContinueServing(a, _plan.Meal); } public bool CanAccess(Component fixture) { return _ai.CanReadServingFixture(fixture, home: true); } public bool Arrive(NpcWorkActivity a, Component f, float dt) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!(Vector3.Distance(Position, a.Approach) <= 0.35f)) { return _ai.MoveWalking(dt, a.Approach, 0.25f); } return true; } public bool CanInteract(Component f) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) return _ai.HasClearFixtureLine(f.transform, Position); } public float Duration(NpcWorkActivity a, Component f) { return 2f; } public float GestureDelay() { return 5f; } public void BeginPose(NpcWorkActivity a, Component f) { _ai.TriggerKitchenInteraction(); } public bool Displaced(NpcWorkActivity a, Component f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(Position, a.WorkPosition) > 1f; } public bool HoldPose(Component f) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) _ai.StopWalking(); ((BaseAI)_ai).LookAt(f.transform.position + Vector3.up); return true; } public void RepeatGesture(Component f) { _ai.TriggerKitchenInteraction(); } public bool Route(NpcWorkActivity a, Component f, bool recovery, out Vector3 approach) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) approach = _plan.SeatApproach; if (!recovery && _ai.TryValidateApproachPoint(approach, approach, 0.01f, _plan.Home, _plan.Radius, null, null, out var _)) { return _ai.HasClearFixtureLine(f.transform, approach); } return false; } public void Move(NpcWorkActivity a) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _ai.EnterMovementState(ResidentState.MovingToPointOfInterest, a.Approach, Mathf.Max(1f, a.Expires - Now)); } public bool Commit(NpcWorkActivity a) { return _ai.CommitTavernServing(a, _plan.Meal); } public void Finish(bool pushed) { NpcWorkActivity homeServingActivity = _ai._homeServingActivity; _ai._homeServingActivity = null; homeServingActivity?.Cancel(); _ai.EnterIdle(); } public void Cancelled(NpcWorkActivity a) { _ai.ReleaseTavernServing(a); if (object.ReferenceEquals(_ai._homeServingActivity, a)) { _ai._homeServingActivity = null; } if (a.Completed) { _ai._homeServingStatus = "free spouse meal gift placed; daily gift used"; } else if (_ai._homeServingStatus.StartsWith("bringing", StringComparison.Ordinal) || _ai._homeServingStatus.StartsWith("preparing", StringComparison.Ordinal)) { _ai._homeServingStatus = "home meal interrupted before placement"; } _ai._nextHomeServing = Now + 20f; } } private sealed class SeatCollisionMask { internal Collider Collider; internal int Added; } private sealed class SocialActivityHost : INpcSocialActivityHost { internal readonly RoleplayNpcAI Ai; internal SocialActivityHost(RoleplayNpcAI ai) { Ai = ai; } private static RoleplayNpcAI Other(INpcSocialActivityHost host) { return ((SocialActivityHost)host).Ai; } public NpcConversationPlan CreateExchange(INpcSocialActivityHost listener) { if (!Ai._tavernRoomConversation) { return NpcDialogue.PlanExchange(Ai._npc, Other(listener)._npc); } return Ai.TavernRoomExchange(Other(listener)._npc); } public float Greet(Transform target) { string text = Ai.ChooseConversationLine(speakingToNpc: false); float num = NpcSpeechTiming.Duration(text, 4f); Ai._npc.Say(text, num, NpcSpeechContext.TargetModel(target)); Ai.TrySocialGesture("emote_wave"); return num; } public void Speak(string line, int index, INpcSocialActivityHost listener) { Ai._npc.Say(line, 4f, Other(listener)._npc.Appearance.ModelIndex); if (index == 0) { Ai.TrySocialGesture("emote_wave"); } else if (line.IndexOf("perhaps", StringComparison.OrdinalIgnoreCase) >= 0 || line.IndexOf("maybe", StringComparison.OrdinalIgnoreCase) >= 0 || line.IndexOf("don't know", StringComparison.OrdinalIgnoreCase) >= 0) { Ai.TrySocialGesture("emote_shrug"); } } public void Completed(INpcSocialActivityHost listener, NpcConversationIntent intent) { NpcRelationships.Conversation(Ai._npc, Other(listener)._npc, intent); } public void ClearSpeech() { Ai.StopSocialGesture(); } public void Cancelled(Transform target, bool workplace) { Ai._tavernRoomConversation = false; if (workplace && (Object)(object)target != (Object)null && Ai._patronNewArrivals.Contains(target)) { Ai._patronGreetingRetry[target] = Time.time + 30f; } } public void ReservationReleased() { if (Ai._state == ResidentState.Idle) { Ai._stateTimer = Mathf.Min(Ai._stateTimer, 3f); } } public void Interrupted() { Ai.EndWorkSocial(); } } private sealed class TavernServing { internal Chair Seat; internal RoleplayNpc Resident; internal Player Player; internal string Guest; internal string Prefab; internal string Revision; internal int Day; internal Piece Surface; internal Vector3 Point; internal ZoneSystem World; internal bool Home; internal Vector3 HomePosition; internal float HomeRadius; internal ZDO HomeGiftRecord; internal int PreviousHomeGiftDay; } private sealed class TavernServingHost : INpcWorkActivityHost { private readonly RoleplayNpcAI _ai; private readonly INpcWorkActivityHost _work; private readonly TavernServing _serving; private float _nextValidation; public float Now => _work.Now; public Vector3 Position => _work.Position; internal TavernServingHost(RoleplayNpcAI ai, INpcWorkActivityHost work, TavernServing serving) { _ai = ai; _work = work; _serving = serving; } public bool Current(NpcWorkActivity a) { return _work.Current(a); } public bool CanContinue(NpcWorkActivity a) { if (!_work.CanContinue(a) || !_ai.ServingGuestStillSeated(_serving) || !_ai.ServingGuestNeedsMeal(_serving) || _serving.Day != NpcRelationships.Day) { return false; } if (Now < _nextValidation) { return true; } _nextValidation = Now + 1f; return _ai.CanContinueServing(a, _serving); } public bool CanAccess(Component f) { return _ai.CanReadServingFixture(f); } public bool Arrive(NpcWorkActivity a, Component f, float dt) { return _work.Arrive(a, f, dt); } public bool CanInteract(Component f) { return _work.CanInteract(f); } public float Duration(NpcWorkActivity a, Component f) { return 2f; } public float GestureDelay() { return 5f; } public void BeginPose(NpcWorkActivity a, Component f) { _ai.TriggerKitchenInteraction(); } public bool Displaced(NpcWorkActivity a, Component f) { return _work.Displaced(a, f); } public bool HoldPose(Component f) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) _ai.StopWalking(); ((BaseAI)_ai).LookAt(_serving.Point); return true; } public void RepeatGesture(Component f) { _ai.TriggerKitchenInteraction(); } public bool Route(NpcWorkActivity a, Component f, bool recovery, out Vector3 approach) { return _work.Route(a, f, recovery, out approach); } public void Move(NpcWorkActivity a) { _work.Move(a); } public bool Commit(NpcWorkActivity a) { return _ai.CommitTavernServing(a, _serving); } public void Finish(bool pushed) { _work.Finish(pushed); } public void Cancelled(NpcWorkActivity a) { _work.Cancelled(a); } } private sealed class WorkActivityHost : INpcWorkActivityHost { private readonly RoleplayNpcAI _ai; private readonly NpcWorkActivity _activity; public float Now => Time.time; public Vector3 Position => ((Component)_ai).transform.position; internal WorkActivityHost(RoleplayNpcAI ai, NpcWorkActivity activity) { _ai = ai; _activity = activity; } public bool Current(NpcWorkActivity activity) { return object.ReferenceEquals(_ai._workActivity, activity); } public bool CanContinue(NpcWorkActivity activity) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!_ai.WorkAuthority() || !_ai.InWorkRadius(activity.Target.transform.position) || ((Object)(object)activity.Source != (Object)null && !_ai.InWorkRadius(activity.Source.transform.position))) { return false; } if (Time.time < _ai._workCustomerCheck) { return true; } _ai._workCustomerCheck = Time.time + 1f; return !_ai.WorkCustomerNearby(); } public bool CanAccess(Component fixture) { if (_activity.Prefab == null && !_activity.LightOnly && !NpcCookingDisplay.CanWorkAt(fixture)) { return false; } if ((Object)(object)fixture != (Object)null && object.ReferenceEquals(fixture, _activity.Target) && _activity.Prefab != null && !_activity.Ore && !_activity.LightOnly && (fixture is Fireplace || fixture is CookingStation || fixture is Smelter)) { return NpcFuelTarget.CanAccess(fixture); } if ((Object)(object)fixture != (Object)null) { if (_activity.Prefab != null || _activity.LightOnly) { return _ai.HasWorkFixtureAccess(fixture); } return _ai.CanObserveWorkFixture(fixture); } return false; } public bool Arrive(NpcWorkActivity activity, Component fixture, float dt) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!NpcWorkReach.HasArrived(Vector3.Distance(Position, activity.Approach), Vector3.Distance(Position, fixture.transform.position), Position.y - activity.Approach.y, fixture is Fireplace)) { return _ai.MoveWalking(dt, activity.Approach, 0.25f); } return true; } public bool CanInteract(Component fixture) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (!NpcOvenApproach.Allows(fixture.transform, Position)) { _ai.ReportWorkResult("oven approach ended outside the front work area"); return false; } return _ai.HasClearFixtureLine(fixture.transform, Position); } public float Duration(NpcWorkActivity activity, Component fixture) { bool flag = activity.Prefab == null && !(fixture is Container) && (_ai._npc.Profession == NpcProfession.Blacksmith || _ai._npc.Profession == NpcProfession.Tavernkeeper); if (activity.Prefab == null) { if (!flag) { return Random.Range(5f, 9f); } if (_ai._npc.Profession != NpcProfession.Tavernkeeper) { return Random.Range(60f, 90f); } return Random.Range(25f, 45f); } return 1.5f; } public float GestureDelay() { return Random.Range(5f, 9f); } public void BeginPose(NpcWorkActivity activity, Component fixture) { _ai.ReportWorkResult("arrived at " + ((Object)fixture).name + "; gesture started for " + (activity.GestureUntil - Time.time).ToString("F0") + "s"); CraftingStation componentInChildren = fixture.GetComponentInChildren<CraftingStation>(); ZSyncAnimation val = (((Object)(object)((BaseAI)_ai).m_character == (Object)null) ? null : ((BaseAI)_ai).m_character.GetZAnim()); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)val != (Object)null && val.HasParameter("crafting", (AnimatorControllerParameterType)3)) { _ai.SetCraftingPose(componentInChildren.m_useAnimation); _ai._workCraftingPose = true; componentInChildren.PokeInUse(); } if (!_ai._workCraftingPose) { _ai.TriggerKitchenInteraction(); } if (_ai.CanObserveWorkFixture(fixture)) { _ai.BeginCookingDisplay(fixture, activity); } Container val2 = (Container)(object)((fixture is Container) ? fixture : null); if ((Object)(object)val2 != (Object)null) { NpcWorkChestVisual.OpenBriefly(val2); } } public bool Displaced(NpcWorkActivity activity, Component fixture) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) bool flag = NpcWorkReach.Interrupted(Vector3.Distance(Position, activity.WorkPosition), Vector3.Distance(Position, fixture.transform.position)) || !NpcOvenApproach.Allows(fixture.transform, Position); if (flag) { _ai.ReportWorkResult("displaced outside the fixture work area"); } return flag; } public bool HoldPose(Component fixture) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) _ai.StopWalking(); ((BaseAI)_ai).LookAt(fixture.transform.position + Vector3.up); return _ai.TickCookingDisplay(); } public void RepeatGesture(Component fixture) { if (!_ai._workCraftingPose && _ai._displayCookingLease == null) { _ai.TriggerKitchenInteraction(); } CraftingStation componentInChildren = fixture.GetComponentInChildren<CraftingStation>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.PokeInUse(); } } public bool Route(NpcWorkActivity activity, Component fixture, bool recovery, out Vector3 approach) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) _ai._workPathProbeBudget = 16; if (!_ai.TryWorkFixtureApproach(fixture.transform, out approach, out var _, out var reason, recovery ? new Vector3?(activity.Approach) : ((Vector3?)null))) { _ai.ReportWorkResult((recovery ? "stalled delivery cannot reroute: " : "delivery approach failed: ") + reason); return false; } if (recovery) { _ai.ReportWorkResult("retrying stalled approach to " + ((Object)fixture).name + " at " + ((Vector3)(ref approach)).ToString("F1")); } return true; } public void Move(NpcWorkActivity activity) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _ai.EnterMovementState(ResidentState.MovingToPointOfInterest, activity.Approach, Mathf.Max(1f, activity.Expires - Time.time)); } public bool Commit(NpcWorkActivity activity) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) bool result = false; if (activity.Prefab != null && _ai.HasClearFixtureLine(activity.Target.transform, Position) && Vector3.Distance(Position, activity.Approach) <= 1f) { result = _ai.CommitWorkActivity(activity); } if (activity.Prefab == null) { result = !activity.LightOnly || NpcCandleLighting.Light((Fireplace)/*isinst with value type is only supported in some contexts*/); } _ai._nextCachedWorkTask = Time.time + Random.Range(5f, 10f); return result; } public void Finish(bool pushed) { if (pushed) { _ai.InterruptPushedWork(); return; } _ai.EnterIdle(); if (_activity.Completed) { _ai.QueueCounterReturn(); } } public void Cancelled(NpcWorkActivity activity) { _ai.WorkActivityCancelled(activity); } } private sealed class WorkRoute { internal Transform Fixture; internal Vector3 FixturePosition; internal Vector3 Origin; internal Vector3 Center; internal Vector3 Approach; internal float Radius; internal float Length; internal float Until; internal int Probe; internal bool Complete; internal bool Success; internal string Reason; } private enum ResidentState { Idle, Wander, MovingToConversation, Conversing, ReservingSeat, MovingToSeat, Sitting, ReservingFood, ConsumingFood, Eating, ReservingBed, MovingToBed, Sleeping, MovingToPointOfInterest, AtPointOfInterest, ReturningHome, MovingToFuelStore, CollectingFuel, MovingToFireplace, Refuelling } private const string BathFixtureId = "RPNPC_BathExitFixture"; internal const string PoseExitFixture = "RPNPC_PoseExitFixture"; private const float TavernCallRange = 10f; private const float TavernConversationRange = 10f; private const int WorkCandidateLimit = 64; private const float ArrivalDistance = 0.75f; private const float HomeArrivalDistance = 1f; private const float TerritoryPathEpsilon = 0.15f; private const float ApproachFloorBelowTolerance = 1.75f; private const float ApproachFloorAboveTolerance = 0.75f; private const int DestinationAttempts = 12; private const float DefaultIdleMinSeconds = 2f; private const float DefaultIdleMaxSeconds = 6f; private const float DefaultWanderMinSeconds = 5f; private const float DefaultWanderMaxSeconds = 30f; private const float SeatArrivalDistance = 0.55f; private const float SeatedFoodReach = 2.1f; private const float SeatRpcTimeoutSeconds = 5f; private const float CasualSitMinSeconds = 15f; private const float CasualSitMaxSeconds = 40f; private const float DinnerSitMinSeconds = 75f; private const float DinnerSitMaxSeconds = 210f; private const float FoodRpcTimeoutSeconds = 5f; private const float FoodRetrySeconds = 30f; private const float BedArrivalDistance = 0.65f; private const float BedRpcTimeoutSeconds = 5f; private const float BedRetrySeconds = 30f; private const float HarlotFollowTimeoutSeconds = 120f; private const float HarlotArrivalDwellSeconds = 2f; private const float HarlotCompletionPoseSeconds = 5f; private const float ConversationDistance = 1.6f; private const float ConversationSearchDistance = 5f; private const float ConversationCooldownSeconds = 30f; private const float AutomaticPointVerticalSearch = 20f; private const float NavigationPreparationSeconds = 10f; private const float NavigationPreparationRetrySeconds = 1f; private const float NavigationPreparationCooldownSeconds = 20f; private const string BedAnimation = "attach_bed"; private const string BathAnimation = "emote_sit"; private const string InteractAnimation = "interact"; private const int ZSyncBoolBaseHash = 438569; private static readonly int BathExitPending = StringExtensionMethods.GetStableHashCode("RPNPC_BathExitPending"); private static readonly int BathExitPoint = StringExtensionMethods.GetStableHashCode("RPNPC_BathExitPoint"); private static readonly int BathAttachPoint = StringExtensionMethods.GetStableHashCode("RPNPC_BathAttachPoint"); private float _nextBathExitRetry; private readonly NpcExitPhysicsHold _bathExitHold = new NpcExitPhysicsHold(); private ZDOID _bathExitSourceFixture; private int _bathExitProbe; private string _savedBathExitFailure; private string _bathExitFailure; private string _lastBedDetour = "not attempted"; private double _lastBedDetourMilliseconds; private readonly List<string> _bedAdmissionDetails = new List<string>(); private int _smithChoreCursor; private int _smithFurnaceCursor; private float _smithIdleSince = -1f; private readonly List<int> _completedSmithChores = new List<int>(); private readonly float[] _smithChoreRetry = new float[3]; private float _nextCommittedInteractionReply; private CookingStation _displayCookingStation; private string _displayCookingLease; private float _displayCookingCheck; private float _displayCookingTake; private bool _displayCookingTaken; private float _displayCookingEnd; private bool _homeCookingDisplay; private bool _homeCookingAttempted; private bool _counterReturnPending; private float _nextCounterReturnTry; private float _counterReturnUntil; private Vector3 _counterReturnAnchor; private string _counterReturnReason = "not requested"; private bool _departing; private string _lastDryRouteFailure; private float _lastDryRouteFailureAt; private bool _dryRouteDiagnosticsSuppressed; private RaycastHit _drySupportHit; private string _drySupportReason; private Vector3 _lastDryRoutePoint; private bool _hasDryRouteSample; private bool _fishingTravel; private bool _fishingPose; private bool _hasFishingSite; private float _fishingNext; private float _fishingUntil; private float _fishingGesture; private float _fishingCalmSince = -1f; private Vector3 _fishingFloor; private Vector3 _fishingCast; private ItemData _fishingRod; private ItemData _retiringFishingRod; private float _retiringFishingRodUntil; private int _fishingSearchPage; private float _fishingSearchLog; private int _fishingCastPhase; private float _fishingCastUntil; private float _fishingReleaseUntil; private string _fishingDrawState; private bool _fishingWindStopped; private float _fishingFloorCheck; private float _fishingRodMissingSince = -1f; private float _nextFishingRodCheck; private float _fishingWeatherSince = -1f; private float _nextFishingWeatherRemark; private float _nextFishingWeatherErrand; private bool _fishingSeatPending; private float _nextFuelStockCheck; private float _nextFuelStockWarning; private string _observedFuelShortage; private Vector3 _observedFuelCenter; private float _observedFuelRadius; private bool _missingHarlotBedFallback; private float _nextMissingBedRemark; private HomeMealPlan _homeMealPlan; private NpcWorkActivity _homeServingActivity; private float _nextHomeServing; private int _homeChairCursor; private string _homeServingStatus = "waiting for a seated hungry spouse"; private readonly object _homeServingRouteTicket = new object(); private static readonly int HomeServingGiftDay = StringExtensionMethods.GetStableHashCode("RPNPC_HomeMealGiftDay"); private float _bathUntil; private float _nextBathTime; private CraftingStation _homeKitchenStation; private bool _homeKitchenPose; private float _nextPatronArrivalScan; private float _nextPatronGreetingTry; private readonly HashSet<Transform> _patronPresent = new HashSet<Transform>(); private readonly HashSet<Transform> _patronNewArrivals = new HashSet<Transform>(); private readonly Dictionary<Transform, float> _patronGreetingRetry = new Dictionary<Transform, float>(); private readonly Dictionary<Transform, float> _patronArrivalMemory = new Dictionary<Transform, float>(); private NpcSeatTarget _pendingSeatChange; private long _pendingSeatChangeToken; private float _pendingSeatChangeUntil; private float _nextSeatChange; private int _seatChangeSearchCursor; private string _seatChangeStatus; private string _seatChangeFailureReply; private static readonly FieldInfo NativePoseBoolHashes = typeof(ZSyncAnimation).GetField("m_boolHashes", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly int PoseExitPending = StringExtensionMethods.GetStableHashCode("RPNPC_PoseExitPending"); private static readonly int PoseExitPoint = StringExtensionMethods.GetStableHashCode("RPNPC_PoseExitPoint"); private static readonly int PoseAttachPoint = StringExtensionMethods.GetStableHashCode("RPNPC_PoseAttachPoint"); private static readonly int PoseExitLegacy = StringExtensionMethods.GetStableHashCode("RPNPC_PoseExitLegacy"); private static readonly int PoseExitBuilding = StringExtensionMethods.GetStableHashCode("RPNPC_PoseExitBuilding"); private readonly NpcExitPhysicsHold _poseExitHold = new NpcExitPhysicsHold(); private float _nextPoseExitRetry; private float _nextPoseExitLog; private int _poseExitProbe; private string _poseExitFailure; private string _savedPoseExitFailure; private ZDOID _poseExitSourceFixture = ZDOID.None; private bool _poseExitIsBed; private string _recoveryPoseAnimation; private Quaternion _recoveryPoseRotation; private Rigidbody _recoveryPoseBody; private NpcRefuelTask _refuelTask; private float _nextRefuelCheck; private readonly NpcResidentControl _residentControl = new NpcResidentControl(); private float _nextScheduleDiagnostic; private string _lastScheduleDiagnostic; private readonly List<SeatCollisionMask> _seatCharacterMasks = new List<SeatCollisionMask>(); private float _nextSeatedMealCheck; private bool _requireCoveredSeat; private bool _routineRest; private bool _rainShelter; private bool _shelterWalking; private float _nextRainCheck; private float _nextShelterSearch; private float _nextShelterRemark; private float _shelterUntil; private float _nextRestCheck; private float _nextRoutineSeat; private float _restUntil; private float _restSettledUntil; private Vector3 _shelterCenter; private Vector3 _shelterPoint; private float _shelterRadius; private int _roofSeatCursor; private int _shelterPieceCursor; private readonly List<Piece> _shelterPieces = new List<Piece>(); private float _shelterPiecesUntil; private float _shelterPiecesRadius; private Vector3 _shelterPiecesCenter; private float _nextCounterRoofCheck; private bool _counterRoofCovered; private Vector3 _counterRoofPoint; private bool _skaldPerformance; private bool _skaldInternalTransition; private float _skaldPreparingUntil; private float _nextSkaldPreparationRoute; private Vector3 _skaldStage; private Vector3 _skaldForward; private float _skaldStageRadius; private NpcSocialActivity _social; private bool _socialDuty; private bool _socialTravelling; private float _socialRetry; private NpcSocialSchedule _socialDutySettings; private float _nextSocialGesture; private float _socialGestureUntil; private float _nextSeatedDrink; private float _seatedDrinkUntil; private int _strandedFailures; private float _strandedSince; private float _strandedLast; private float _recoveryCheck; private float _recoveryAfter; private Vector3 _strandedOrigin; private bool _tavernRoomConversation; private Vector3 _tavernRoomAnchor; private float _nextTavernContact; private readonly Dictionary<Transform, float> _tavernContactUntil = new Dictionary<Transform, float>(); private readonly ConditionalWeakTable<NpcWorkActivity, TavernServing> _tavernServings = new ConditionalWeakTable<NpcWorkActivity, TavernServing>(); private static readonly Dictionary<string, NpcWorkActivity> ServingGuests = new Dictionary<string, NpcWorkActivity>(); private static ZoneSystem _servingWorld; private float _nextServingScan; private int _servingSeatCursor; private readonly Collider[] _servingFood = (Collider[])(object)new Collider[128]; private TavernServing _pendingTavernServing; private float _pendingServingUntil; private string _tavernServingStatus = "waiting for the first occupied-seat scan"; private float _lastServingSeatScan = -1f; private int _servingPlayerCursor; private int _servingInspectedSeats; private int _servingLocalSeats; private static int _trafficSnapshotFrame = -1; private static RoleplayNpc[] _trafficResidents; private float _trafficSince = -1f; private float _trafficLastBlocked = -1f; private float _trafficProbeAfter; private float _nextTrafficRequest; private Vector3 _trafficStep; private Vector3 _trafficHeading; private bool _hasTrafficStep; private bool _trafficDetour; private Vector3 _trafficDetourPoint; private float _trafficDetourUntil; private float _nextTrafficDetour; private Vector3 _trafficRejoinPoint; private bool _trafficHasRejoin; private float _nextTrafficLegCheck; private int _trafficDetourProbe; private readonly NpcTrafficDetourHistory _trafficDetourHistory = new NpcTrafficDetourHistory(); private Vector3 _trafficHistoryTarget; private bool _hasTrafficHistoryTarget; private static readonly int LastDryPointKey = StringExtensionMethods.GetStableHashCode("RPNPC_LastDryPoint"); private static readonly int HasDryPointKey = StringExtensionMethods.GetStableHashCode("RPNPC_HasDryPoint"); private bool _waterRecovery; private float _waterSince; private float _waterProgressAt; private float _waterSearchAt; private float _dryRecordAt; private float _waterRescueAt; private Vector3 _waterProgressPosition; private Vector3 _waterLanding; private readonly List<Vector3> _waterRoute = new List<Vector3>(); private int _waterCorner; private int _waterSearchPage; private NpcWorkActivity _workActivity; private float _nextWorkActivity; private float _nextWorkPushReply; private float _counterDwellRemaining = 20f; private readonly List<Component> _recentWorkFixtures = new List<Component>(); private float _workCustomerCheck; private readonly Collider[] _workDrops = (Collider[])(object)new Collider[128]; private static readonly MethodInfo WorkSaveContainer = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null); private static readonly MethodInfo WorkLoadDrop = AccessTools.Method(typeof(ItemDrop), "Load", (Type[])null, (Type[])null); private bool _workCraftingPose; private int _workPathProbeBudget; private int _workCandidateCursor; private float _nextCachedWorkTask; private float _nextWorkRouteLog; private float _workScanRetry; private int _workFixtureCursor; private readonly List<Piece> _workKnownFixtures = new List<Piece>(); private string _workLastResult = "waiting for first workplace scan"; private readonly List<Container> _workKnownStores = new List<Container>(); private readonly Dictionary<Piece, float> _failedWorkFixtures = new Dictionary<Piece, float>(); private bool _workFallbackRequested; private bool _tryingAlternateWork; private float _workHomeFallbackUntil; private float _workFallbackPlanningUntil; private float _nextWorkFallbackScan; private float _workFallbackRetryNotBefore; private string _workFallbackCause = "not requested"; private Vector3 _workFallbackAnchor; private NpcProfession _workFallbackProfession; private readonly List<WorkRoute> _workRoutes = new List<WorkRoute>(); private bool _workRouteDeferred; private float _nextWorkSocial; private readonly List<Transform> _workSocialCandidates = new List<Transform>(); private readonly List<Transform> _completedWorkConversations = new List<Transform>(); private bool _checkingWorkRoute; private bool _checkingHarlotRoute; private bool _checkingSkaldRoute; private bool _professionSeatDuty; internal static readonly int SeatAnimationKey = StringExtensionMethods.GetStableHashCode("RPNPC_SeatAnimation"); private RoleplayNpc _npc; private ResidentState _state; private float _stateTimer; private Vector3 _destination; private bool _hasDestination; private string _locomotionMode = "Stopped"; private float _returnRetryTimer; private Vector3 _progressSamplePosition; private float _progressSampleTimer; private float _stalledSeconds; private float _lastProgressDistance; private float _noApproachSeconds; private bool _verticalRouteKickActive; private float _foodRetryTimer; private NpcEatingTarget _foodTarget; private long _foodLeaseToken; private int _foodDay = -1; private NpcSeatTarget _seatTarget; private long _seatLeaseToken; private bool _isSeated; private float _sitTimer; private Rigidbody _seatBody; private bool _seatBodyUsedGravity; private bool _seatBodyWasKinematic; private Collider[] _npcSeatColliders; private Collider[] _chairSeatColliders; private string _seatAnimation; private Chair _recentlyFailedChair; private float _failedChairRetryAfter; private string _pointOfInterestType; private Vector3 _pointOfInterestForward; private float _pointOfInterestAnimationTimer; private string _lastActivityFailure = "none"; private bool _wasOwner; private NpcBedTarget _bedTarget; private long _bedLeaseToken; private bool _isSleeping; private float _bedRetryTimer; private Rigidbody _sleepBody; private bool _sleepBodyUsedGravity; private bool _sleepBodyWasKinematic; private Collider[] _npcSleepColliders; private Collider[] _bedSleepColliders; private string _activityAnimation; private bool _harlotService; private bool _harlotServiceCompleted; private long _harlotServicePeer; private ZDOID _harlotServicePlayer = ZDOID.None; private float _harlotServiceTimer; private float _harlotArrivalDwell; private float _conversationCooldownTimer; private string _lastConversationLine; private float _doorRetryTimer; private int _doorAttempts; private float _nextWorldReactionCheck; private float _professionRetryAfter; private bool _worldReactionActive; private string _worldReactionKind; private bool _navigationPreparationPending; private float _navigationPreparationDeadline; private float _navigationPreparationRetryAfter; private Vector3 _navigationPreparationOrigin; private Pathfinding _navigationPreparationSource; private int _lastScheduledActivity = -1; private string _lastScheduledPointType; private Chair _lastScheduledChair; private static readonly int ActivityAnimationKey = StringExtensionMethods.GetStableHashCode("RPNPC_ActivityAnimation"); private readonly List<Vector3> _candidatePath = new List<Vector3>(); private readonly List<Piece> _automaticPointPieces = new List<Piece>(); private static int _solidMask; private Vector3 _kitchenWorkPosition; private int _seatSearchCursor; internal bool CanSpeakArrival { get { //IL_006f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.m_character != (Object)null && !base.m_character.IsDead() && !IsRestingInBed && !IsRecoveringFromWater && !_worldReactionActive && !_harlotService && (Object)(object)Social.Target == (Object)null && (Object)(object)ConversationInviter == (Object)null && !NpcProfessionProtocol.HasActiveTradeCustomer(_npc)) { return !IsDangerEventAt(((Component)this).transform.position); } return false; } } internal bool IsRecoveringBathExit { get { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (!_isSeated && !_isSleeping && OwnsPoseExit() && !IsRecoveringFromWater && _npc.View.GetZDO().GetBool(BathExitPending, false)) { return BathExitNear(_npc.View.GetZDO().GetVec3(BathAttachPoint, ((Component)this).transform.position), ((Component)this).transform.position); } return false; } } internal bool HasCommittedInteraction { get { if (!HasSkaldActivity) { return _harlotService; } return true; } } internal bool HasHomeServing { get { if (_homeServingActivity == null) { return _homeMealPlan != null; } return true; } } private Vector3 NavigationOrigin { get { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!_isSeated || _seatTarget == null) { return ((Component)this).transform.position; } return _seatTarget.ApproachPoint; } } internal string ObservedReactionBlock { get { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_npc == (Object)null || !_npc.AutonomousEnabled) { return "autonomy paused/unavailable"; } if (!InspectResidentActivity(out var reason)) { return reason; } if ((Object)(object)base.m_character == (Object)null || base.m_character.IsDead()) { return "resident dead/unavailable"; } if (_worldReactionActive || IsDangerEventAt(((Component)this).transform.position)) { return "danger reaction"; } if (IsRestingInBed || NpcDutySchedule.SleepDue(_npc)) { return "sleep/rest due"; } if (IsRecoveringFromWater || IsRecoveringExit || _isSeated) { return "pose/water recovery or seated"; } if (_harlotService) { return "invited paid visit"; } if (HasWorkActivity || _pendingTavernServing != null) { return "committed work/serving"; } if ((Object)(object)Social.Target != (Object)null || (Object)(object)ConversationInviter != (Object)null || HasWorkSocial) { return "social conversation"; } if (NpcProfessionProtocol.HasActiveTradeCustomer(_npc)) { return "trade customer"; } if (_npc.IsSpeechActive) { return "speech active"; } if (_state != ResidentState.Idle && _state != ResidentState.Wander && _state != ResidentState.ReturningHome && ((_state != ResidentState.AtPointOfInterest && _state != ResidentState.MovingToPointOfInterest) || !(_pointOfInterestType == "work"))) { return "activity " + StateName; } return string.Empty; } } internal string ObservedReactionAdmissionBlock { get { if (!CanAdmitResidentActivity(out var reason)) { return reason; } return ObservedReactionBlock; } } private bool _poseExitHolding => _poseExitHold.Active; internal bool IsRecoveringPoseExit { get { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (_isSeated || _isSleeping || !OwnsPoseExit()) { return false; } ZDO zDO = _npc.View.GetZDO(); if (!_poseExitHolding) { if (zDO.GetBool(PoseExitPending, false)) { return BathExitNear(zDO.GetVec3(PoseAttachPoint, ((Component)this).transform.position), ((Component)this).transform.position); } return false; } return true; } } internal bool IsRecoveringExit { get { if (!IsRecoveringPoseExit) { return IsRecoveringBathExit; } return true; } } private NpcControlDecision ResidentControlDecision => _residentControl.Decide(new NpcControlSnapshot(OwnsPoseExit(), _departing, (Object)(object)base.m_character != (Object)null && base.m_character.IsDead(), IsRecoveringFromWater, IsRecoveringPoseExit, IsRecoveringBathExit)); internal bool HasSeatedCollisionExclusion { get { if (_isSeated) { return true; } if (_poseExitHolding && OwnsPoseExit() && !string.IsNullOrEmpty(_recoveryPoseAnimation) && _recoveryPoseAnimation != "attach_bed") { return true; } if ((Object)(object)_npc != (Object)null && (Object)(object)_npc.View != (Object)null && _npc.View.IsValid() && !_npc.View.IsOwner()) { return !string.IsNullOrEmpty(_npc.View.GetZDO().GetString(SeatAnimationKey, string.Empty)); } return false; } } private bool WeatherCommitment { get { if (!HasWeatherWorkCommitment() && !_harlotService && !_worldReactionActive && !IsRecoveringFromWater && !IsRestingInBed && _state != ResidentState.ReservingFood && _state != ResidentState.ConsumingFood && _state != ResidentState.Eating) { return WorkCustomerNearby(); } return true; } } internal bool IsSeatedUnderRoof { get { if (_isSeated && _seatTarget != null && (Object)(object)_seatTarget.Chair != (Object)null) { return NpcShelter.SeatCovered(_seatTarget.Chair, refresh: true); } return false; } } internal bool HasSkaldActivity { get { if (!_skaldPerformance) { return Time.time < _skaldPreparingUntil; } return true; } } private bool SkaldOtherCommitment { get { if (!HasWorkActivity && !HasHomeServing && !HasWorkSocial && !((Object)(object)Social.Target != (Object)null) && !((Object)(object)ConversationInviter != (Object)null) && !_harlotService && _state != ResidentState.ReservingFood && _state != ResidentState.ConsumingFood) { return _state == ResidentState.Eating; } return true; } } private bool SkaldCommittedActivity { get { if (!HasWorkActivity && !HasHomeServing && !_harlotService && _state != ResidentState.ReservingFood && _state != ResidentState.ConsumingFood) { return _state == ResidentState.Eating; } return true; } } internal bool IsRestingInBed { get { if (!_isSleeping) { return _state == ResidentState.Sleeping; } return true; } } private NpcSocialActivity Social => _s