using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; using UnityEngine.UI; using ValheimVillages.Abilities; using ValheimVillages.Attributes; using ValheimVillages.Behaviors; using ValheimVillages.Behaviors.Combat; using ValheimVillages.Behaviors.Crafting; using ValheimVillages.Behaviors.Farming; using ValheimVillages.Behaviors.Patrol; using ValheimVillages.Behaviors.Repair; using ValheimVillages.Behaviors.Tidy; using ValheimVillages.Behaviors.Work; using ValheimVillages.Diagnostics; using ValheimVillages.Enums; using ValheimVillages.Interfaces; using ValheimVillages.Items; using ValheimVillages.Items.Icons; using ValheimVillages.Items.VirtualRecipes; using ValheimVillages.Items.WorkOrders; using ValheimVillages.Patches; using ValheimVillages.Schemas; using ValheimVillages.Tags; using ValheimVillages.TaskQueue; using ValheimVillages.TaskQueue.ActivityLog; using ValheimVillages.TaskQueue.Handlers; using ValheimVillages.Testing; using ValheimVillages.UI.ContextMenus; using ValheimVillages.UI.Core; using ValheimVillages.UI.Interaction; using ValheimVillages.UI.Panels; using ValheimVillages.UI.Tabs; using ValheimVillages.Villager; using ValheimVillages.Villager.AI; using ValheimVillages.Villager.AI.Memory; using ValheimVillages.Villager.AI.Navigation; using ValheimVillages.Villager.AI.Pathfinding; using ValheimVillages.Villager.AI.Work; using ValheimVillages.Villager.Records; using ValheimVillages.Villager.Registry; using ValheimVillages.Villager.Station; using ValheimVillages.Villages; using ValheimVillages.Villages.Entity; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Valheim Villages")] [assembly: AssemblyDescription("A village-building and NPC management mod for Valheim")] [assembly: AssemblyCompany("Myrcutio")] [assembly: AssemblyProduct("ValheimVillages")] [assembly: AssemblyCopyright("Copyright © Myrcutio 2026")] [assembly: AssemblyFileVersion("0.1.1")] [assembly: InternalsVisibleTo("ValheimVillages.Tests")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.1.1.0")] namespace ValheimVillages { internal static class DebugLog { private sealed class ThrottleState { public bool EverEmitted; public TimeSpan LastEmitted; public int Suppressed; } private static int _captureCounter; private static DebugCaptureBehaviour _captureBehaviour; private static readonly string LogPath = Path.Combine(Paths.ConfigPath, "vv_dumps", "legacy_debug.ndjson"); private static int _cycleNumber; private static readonly Dictionary _throttle = new Dictionary(); private static readonly TimeSpan DefaultThrottleWindow = TimeSpan.FromSeconds(10.0); private static readonly Stopwatch _sessionClock = Stopwatch.StartNew(); private static string SidecarDir { get { string path; try { path = Paths.ConfigPath; } catch { path = "."; } return Path.Combine(path, "vv_dumps"); } } public static void Capture(string trigger) { Capture(CaptureRequest.Default(trigger)); } public static void Capture(CaptureRequest request) { try { Plugin instance = Plugin.Instance; if (!((Object)(object)instance == (Object)null)) { if ((Object)(object)_captureBehaviour == (Object)null) { _captureBehaviour = ((Component)instance).gameObject.GetComponent() ?? ((Component)instance).gameObject.AddComponent(); } _captureBehaviour.Enqueue(request); } } catch { } } internal static int NextCaptureCounter() { return Interlocked.Increment(ref _captureCounter); } public static string Vid(Guid id) { string text = id.ToString("N"); if (text.Length < 8) { return text; } return text.Substring(0, 8); } public static string Vid(string id) { if (string.IsNullOrEmpty(id)) { return "unknown"; } if (Guid.TryParse(id, out var result)) { return Vid(result); } string text = id.Replace("-", ""); if (text.Length < 8) { return text; } return text.Substring(0, 8); } public static string Tid(string taskName, int instanceId) { return (taskName ?? "task") + "#" + instanceId; } public static void Append(string location, string message, Dictionary data, string hypothesisId, string runId) { try { long num = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append('{'); stringBuilder.AppendFormat("\"timestamp\":{0}", num); stringBuilder.AppendFormat(",\"location\":\"{0}\"", Esc(location)); stringBuilder.AppendFormat(",\"message\":\"{0}\"", Esc(message)); stringBuilder.AppendFormat(",\"hypothesisId\":\"{0}\"", Esc(hypothesisId)); stringBuilder.AppendFormat(",\"runId\":\"{0}\"", Esc(runId)); stringBuilder.Append(",\"data\":{"); bool flag = true; foreach (KeyValuePair datum in data) { if (!flag) { stringBuilder.Append(','); } flag = false; stringBuilder.AppendFormat("\"{0}\":", Esc(datum.Key)); if (datum.Value is string v) { stringBuilder.AppendFormat("\"{0}\"", Esc(v)); } else if (datum.Value is bool flag2) { stringBuilder.Append(flag2 ? "true" : "false"); } else if (datum.Value is float num2) { stringBuilder.Append(num2.ToString(CultureInfo.InvariantCulture)); } else if (datum.Value is double num3) { stringBuilder.Append(num3.ToString(CultureInfo.InvariantCulture)); } else { stringBuilder.Append(datum.Value?.ToString() ?? "null"); } } stringBuilder.Append("}}"); File.AppendAllText(LogPath, stringBuilder?.ToString() + "\n"); } catch { } } private static string Esc(string v) { return v?.Replace("\\", "\\\\").Replace("\"", "\\\"") ?? ""; } public static void BeginCycle(bool isHotReload) { int num = Interlocked.Increment(ref _cycleNumber); string arg = (isHotReload ? "true" : "false"); string arg2 = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); Plugin.Log.LogInfo((object)$"===== VV CYCLE n={num} hot={arg} t={arg2} ====="); } public static void Event(string component, string eventName, params (string key, object val)[] kv) { StringBuilder stringBuilder = new StringBuilder(64 + ((kv != null) ? kv.Length : 0) * 16); stringBuilder.Append('[').Append(component).Append("] ") .Append(eventName); stringBuilder.Append(' ').Append(T()); if (kv != null) { for (int i = 0; i < kv.Length; i++) { stringBuilder.Append(' ').Append(kv[i].key).Append('='); AppendValue(stringBuilder, kv[i].val); } } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } private static void AppendValue(StringBuilder sb, object v) { if (v == null) { sb.Append("null"); return; } string text = ((v is float num) ? num.ToString("0.###", CultureInfo.InvariantCulture) : ((v is double num2) ? num2.ToString("0.###", CultureInfo.InvariantCulture) : ((!(v is bool)) ? (v.ToString() ?? "") : (((bool)v) ? "true" : "false")))); bool flag = false; foreach (char c in text) { if (c == ' ' || c == '=' || c == '"') { flag = true; break; } } if (flag) { sb.Append('"').Append(text.Replace("\"", "\\\"")).Append('"'); } else { sb.Append(text); } } public static void List(string component, string name, IEnumerable items) { string[] array = items?.Select((object i) => i?.ToString() ?? "null").ToArray() ?? new string[0]; string text = ShortSha(string.Join(",", array)); string sidecarDir = SidecarDir; string text2 = Path.Combine(sidecarDir, name + "_" + text + ".json"); try { Directory.CreateDirectory(sidecarDir); if (!File.Exists(text2)) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append('['); for (int num = 0; num < array.Length; num++) { if (num > 0) { stringBuilder.Append(','); } stringBuilder.Append('"').Append(JsonEscape(array[num])).Append('"'); } stringBuilder.Append(']'); File.WriteAllText(text2, stringBuilder.ToString()); } } catch { } Event(component, name, ("count", array.Length), ("sha", text), ("path", text2)); } private static string ShortSha(string s) { using SHA1 sHA = SHA1.Create(); byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(s ?? "")); StringBuilder stringBuilder = new StringBuilder(8); for (int i = 0; i < 4; i++) { stringBuilder.AppendFormat("{0:x2}", array[i]); } return stringBuilder.ToString(); } private static string JsonEscape(string s) { return (s ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r") .Replace("\t", "\\t"); } public static void Throttled(string key, string component, string eventName, params (string key, object val)[] kv) { ThrottledWindow(key, DefaultThrottleWindow, component, eventName, kv); } public static void ThrottledWindow(string key, TimeSpan window, string component, string eventName, params (string key, object val)[] kv) { if (string.IsNullOrEmpty(key)) { Event(component, eventName, kv); return; } ThrottleState value; lock (_throttle) { if (!_throttle.TryGetValue(key, out value)) { value = new ThrottleState(); _throttle[key] = value; } } lock (value) { TimeSpan timeSpan = Elapsed(); bool num = !value.EverEmitted; bool flag = timeSpan - value.LastEmitted >= window; if (num || flag) { if (value.Suppressed > 0) { (string, object)[] array = new(string, object)[kv.Length + 2]; Array.Copy(kv, array, kv.Length); array[kv.Length] = ("suppressed", value.Suppressed); array[kv.Length + 1] = ("window_s", window.TotalSeconds); Event(component, eventName, array); } else { Event(component, eventName, kv); } value.LastEmitted = timeSpan; value.EverEmitted = true; value.Suppressed = 0; } else { value.Suppressed++; } } } public static TimeSpan Elapsed() { return _sessionClock.Elapsed; } public static string T() { return "t=+" + _sessionClock.Elapsed.TotalSeconds.ToString("0.00", CultureInfo.InvariantCulture) + "s"; } } internal readonly struct CaptureRequest { public readonly string Trigger; public readonly string OutputSubdir; public readonly string OutputBaseName; public readonly Vector3? AnchorOverride; public readonly float AnchorClearance; public readonly bool IncludeDiagnostics; public CaptureRequest(string trigger, string outputSubdir, string outputBaseName, Vector3? anchorOverride, float anchorClearance, bool includeDiagnostics) { Trigger = trigger ?? "unknown"; OutputSubdir = outputSubdir ?? ""; OutputBaseName = (string.IsNullOrEmpty(outputBaseName) ? "last_capture" : outputBaseName); AnchorOverride = anchorOverride; AnchorClearance = anchorClearance; IncludeDiagnostics = includeDiagnostics; } public static CaptureRequest Default(string trigger) { return new CaptureRequest(trigger, "", "last_capture", null, 45f, includeDiagnostics: true); } public static CaptureRequest ForIncident(string trigger, string incidentSubdir, string baseName, Vector3 anchor, float clearance) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return new CaptureRequest(trigger, incidentSubdir, baseName, anchor, clearance, includeDiagnostics: false); } } internal class DebugCaptureBehaviour : MonoBehaviour { private readonly ConcurrentQueue _pending = new ConcurrentQueue(); private bool _processing; private static readonly HashSet OrchestratedTriggers = new HashSet { "repartition", "manual" }; private void Update() { if (!_processing && !_pending.IsEmpty) { ((MonoBehaviour)this).StartCoroutine(ProcessQueue()); } } public void Enqueue(CaptureRequest req) { _pending.Enqueue(req); } private IEnumerator ProcessQueue() { _processing = true; try { CaptureRequest result; while (_pending.TryDequeue(out result)) { int counter = DebugLog.NextCaptureCounter(); yield return CaptureRoutine(result, counter); yield return null; } } finally { _processing = false; } } private IEnumerator CaptureRoutine(CaptureRequest req, int counter) { yield return (object)new WaitForSecondsRealtime(0.6f); Camera cam = Camera.main; if ((Object)(object)cam == (Object)null) { yield break; } OrchestrationSession session = null; if (OrchestratedTriggers.Contains(req.Trigger) || req.AnchorOverride.HasValue) { session = OrchestrationSession.TryBegin(req); session?.LogStarted(req.Trigger, session.AnchorPos); } try { if (session != null) { yield return null; } session?.ApplyCameraPose(); Vector3 pos = ((Component)cam).transform.position; Vector3 euler = ((Component)cam).transform.eulerAngles; float worldTime = -1f; try { if ((Object)(object)EnvMan.instance != (Object)null) { worldTime = EnvMan.instance.GetDayFraction(); } } catch { } yield return (object)new WaitForEndOfFrame(); WritePngAndSidecar(req, counter, pos, euler, worldTime); } finally { session?.Restore(); } } private static void WritePngAndSidecar(CaptureRequest req, int counter, Vector3 pos, Vector3 euler, float worldTime) { string text; try { string path; try { path = Paths.ConfigPath; } catch { path = "."; } text = Path.Combine(path, "vv_dumps"); if (!string.IsNullOrEmpty(req.OutputSubdir)) { text = Path.Combine(text, req.OutputSubdir); } Directory.CreateDirectory(text); } catch { return; } string path2 = Path.Combine(text, req.OutputBaseName + ".png"); string path3 = Path.Combine(text, req.OutputBaseName + ".json"); Texture2D val = null; try { val = ScreenCapture.CaptureScreenshotAsTexture(); byte[] bytes = ImageConversion.EncodeToPNG(val); File.WriteAllBytes(path2, bytes); } catch { } finally { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } try { StringBuilder stringBuilder = new StringBuilder(2048); stringBuilder.Append('{'); stringBuilder.Append("\"counter\":").Append(counter.ToString(CultureInfo.InvariantCulture)).Append(','); stringBuilder.Append("\"trigger\":\"").Append(JsonEscape(req.Trigger)).Append("\","); stringBuilder.Append("\"timestampUtc\":\"").Append(DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)).Append("\","); stringBuilder.Append("\"worldTimeOfDay\":").Append(worldTime.ToString("R", CultureInfo.InvariantCulture)).Append(','); stringBuilder.Append("\"cameraPos\":[").Append(pos.x.ToString("R", CultureInfo.InvariantCulture)).Append(',') .Append(pos.y.ToString("R", CultureInfo.InvariantCulture)) .Append(',') .Append(pos.z.ToString("R", CultureInfo.InvariantCulture)) .Append("],"); stringBuilder.Append("\"cameraYaw\":").Append(euler.y.ToString("R", CultureInfo.InvariantCulture)).Append(','); stringBuilder.Append("\"cameraPitch\":").Append(euler.x.ToString("R", CultureInfo.InvariantCulture)); if (req.IncludeDiagnostics) { AppendDiagnostics(stringBuilder); } stringBuilder.Append('}'); File.WriteAllText(path3, stringBuilder.ToString()); } catch { } } private static void AppendDiagnostics(StringBuilder sb) { sb.Append(",\"diagnostics\":{"); sb.Append("\"lastRelaxation\":{\"available\":false},"); sb.Append("\"villages\":["); bool flag = true; try { foreach (RegionGraph item in VillageRegistry.AllGraphs()) { if (!flag) { sb.Append(','); } flag = false; sb.Append('{'); sb.Append("\"key\":\"").Append(JsonEscape(item.RegisteredVillageKey ?? "")).Append("\","); sb.Append("\"regionCount\":").Append(item.RegionCount).Append(','); sb.Append("\"linkCount\":").Append(item.LinkCount).Append(','); sb.Append("\"bfsCells\":").Append(item.Diagnostics.LookupGridCellCount).Append(','); sb.Append("\"boundaryCells\":").Append(item.Diagnostics.BoundaryCellCount).Append(','); sb.Append("\"bfsBounds\":"); AppendBounds(sb, item.Diagnostics.TryGetLookupGridBounds(out var minX, out var maxX, out var minZ, out var maxZ), minX, maxX, minZ, maxZ); sb.Append(",\"boundaryBounds\":"); AppendBounds(sb, item.Diagnostics.TryGetBoundaryCellsBounds(out var minX2, out var maxX2, out var minZ2, out var maxZ2), minX2, maxX2, minZ2, maxZ2); sb.Append('}'); } } catch { } sb.Append(']'); sb.Append('}'); } private static void AppendBounds(StringBuilder sb, bool ok, float minX, float maxX, float minZ, float maxZ) { if (!ok) { sb.Append("null"); } else { sb.Append("{\"x\":[").Append(minX.ToString("R", CultureInfo.InvariantCulture)).Append(',') .Append(maxX.ToString("R", CultureInfo.InvariantCulture)) .Append("],\"z\":[") .Append(minZ.ToString("R", CultureInfo.InvariantCulture)) .Append(',') .Append(maxZ.ToString("R", CultureInfo.InvariantCulture)) .Append("]}"); } } private static string JsonFloat(float v) { if (float.IsNaN(v) || float.IsInfinity(v)) { return "null"; } return v.ToString("R", CultureInfo.InvariantCulture); } private static string JsonEscape(string s) { return (s ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r") .Replace("\t", "\\t"); } } internal class OrchestrationSession { private readonly Player m_player; private readonly Vector3 m_savedPos; private readonly Quaternion m_savedRot; private readonly Hud m_hud; private readonly bool m_savedHudVisible; private readonly Vector3 m_savedCamPos; private readonly Quaternion m_savedCamRot; private readonly GameCamera m_gameCamera; private readonly bool m_savedGameCameraEnabled; private readonly Vector3 m_anchorPos; private readonly Quaternion m_anchorRot; public Vector3 AnchorPos => m_anchorPos; private OrchestrationSession(Player player, Vector3 savedPos, Quaternion savedRot, Hud hud, bool savedHudVisible, Vector3 savedCamPos, Quaternion savedCamRot, GameCamera gameCamera, bool savedGameCameraEnabled, Vector3 anchorPos, Quaternion anchorRot) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_004e: 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_0056: Unknown result type (might be due to invalid IL or missing references) m_player = player; m_savedPos = savedPos; m_savedRot = savedRot; m_hud = hud; m_savedHudVisible = savedHudVisible; m_savedCamPos = savedCamPos; m_savedCamRot = savedCamRot; m_gameCamera = gameCamera; m_savedGameCameraEnabled = savedGameCameraEnabled; m_anchorPos = anchorPos; m_anchorRot = anchorRot; } public void ApplyCameraPose() { //IL_0018: 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) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return; } try { ((Component)main).transform.position = m_anchorPos; ((Component)main).transform.rotation = m_anchorRot; } catch { } } public static OrchestrationSession TryBegin(CaptureRequest req) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[Capture] Orchestration skipped: no local player. Falling back to passive capture."); } return null; } CaptureAnchor.Result result = ((!req.AnchorOverride.HasValue) ? CaptureAnchor.Resolve(((Component)localPlayer).transform.position) : CaptureAnchor.ResolveAt(req.AnchorOverride.Value, req.AnchorClearance)); if (!result.HasAnchor) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Capture] Orchestration skipped: " + result.Reason + ". Falling back to passive capture (no silent coordinate fabrication).")); } return null; } Vector3 position = ((Component)localPlayer).transform.position; Quaternion rotation = ((Component)localPlayer).transform.rotation; Hud instance = Hud.instance; bool flag = true; try { if ((Object)(object)instance != (Object)null) { flag = ((Component)instance).gameObject.activeSelf; } } catch { } Camera main = Camera.main; Vector3 savedCamPos = (((Object)(object)main != (Object)null) ? ((Component)main).transform.position : Vector3.zero); Quaternion savedCamRot = (((Object)(object)main != (Object)null) ? ((Component)main).transform.rotation : Quaternion.identity); GameCamera instance2 = GameCamera.instance; bool flag2 = (Object)(object)instance2 != (Object)null && ((Behaviour)instance2).enabled; Quaternion val = Quaternion.Euler(result.Pitch, result.Yaw, 0f); try { ((Component)localPlayer).transform.position = result.Pos; ((Component)localPlayer).transform.rotation = val; if ((Object)(object)main != (Object)null) { ((Component)main).transform.position = result.Pos; ((Component)main).transform.rotation = val; } if ((Object)(object)instance2 != (Object)null) { ((Behaviour)instance2).enabled = false; } if ((Object)(object)instance != (Object)null) { ((Component)instance).gameObject.SetActive(false); } } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Capture] Orchestration apply failed: " + ex.GetType().Name + ": " + ex.Message + ". Restoring state and falling back to passive capture.")); } try { ((Component)localPlayer).transform.position = position; ((Component)localPlayer).transform.rotation = rotation; } catch { } try { if ((Object)(object)instance2 != (Object)null) { ((Behaviour)instance2).enabled = flag2; } } catch { } try { if ((Object)(object)instance != (Object)null) { ((Component)instance).gameObject.SetActive(flag); } } catch { } return null; } return new OrchestrationSession(localPlayer, position, rotation, instance, flag, savedCamPos, savedCamRot, instance2, flag2, result.Pos, val); } public void LogStarted(string trigger, Vector3 anchorPos) { //IL_001b: 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_0037: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Capture] Orchestrated trigger='{trigger}' anchor=({anchorPos.x:F1},{anchorPos.y:F1},{anchorPos.z:F1}) yaw=0 pitch=90"); } } public void Restore() { //IL_001a: 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) try { if ((Object)(object)m_player != (Object)null) { ((Component)m_player).transform.position = m_savedPos; ((Component)m_player).transform.rotation = m_savedRot; } } catch { } try { if ((Object)(object)m_gameCamera != (Object)null) { ((Behaviour)m_gameCamera).enabled = m_savedGameCameraEnabled; } } catch { } try { if ((Object)(object)m_hud != (Object)null) { ((Component)m_hud).gameObject.SetActive(m_savedHudVisible); } } catch { } } } public static class HotReloadHelper { private const string ModPrefix = "VV_"; private const string ModPrefabPrefix = "vv_"; private const string VillagerStationPrefix = "$vv_"; private static readonly Assembly CurrentAssembly = typeof(HotReloadHelper).Assembly; public static void FullCleanup() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[HotReload] Starting full cleanup..."); } ResetAllStaticState(); int num = DestroyStaleComponents(); int num2 = DestroyOrphanedModObjects(); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[HotReload] Cleanup complete: " + $"{num} stale component(s), " + $"{num2} orphaned GameObject(s) destroyed.")); } } public static string PurgeStaleObjects() { string arg = ReportModInstances(); int num = DestroyStaleComponents(); return $"{arg}\n[HotReload] Purged {num} stale component(s)."; } public static string ReportModInstances() { Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); MonoBehaviour[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (MonoBehaviour val in array) { if (!((Object)(object)val == (Object)null)) { Type type = ((object)val).GetType(); if (type.FullName != null && type.FullName.StartsWith("ValheimVillages.")) { Dictionary obj = ((type.Assembly == CurrentAssembly) ? dictionary : dictionary2); obj.TryGetValue(type.Name, out var value); obj[type.Name] = value + 1; } } } int num = 0; List list = new List(); foreach (KeyValuePair item in dictionary2) { num += item.Value; list.Add($" STALE {item.Key} x{item.Value}"); } string text = $"[HotReload] Mod MonoBehaviours: {dictionary.Count} current type(s), " + $"{num} stale instance(s)"; if (list.Count <= 0) { return text; } return text + "\n" + string.Join("\n", list); } private static void ResetAllStaticState() { AttributeScanner.InvokeAllCleanup(CurrentAssembly); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)"[HotReload] All static registries cleared."); } } private static int DestroyStaleComponents() { int num = 0; MonoBehaviour[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (MonoBehaviour val in array) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); string fullName = type.FullName; if (fullName != null && fullName.StartsWith("ValheimVillages.") && !(type.Assembly == CurrentAssembly)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[HotReload] Destroying stale component: " + fullName + " on \"" + ((Object)((Component)val).gameObject).name + "\"")); } ((Behaviour)val).enabled = false; Object.Destroy((Object)(object)val); num++; } } return num; } private static int DestroyOrphanedModObjects() { int num = 0; Transform[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); List list = new List(); Transform[] array2 = array; foreach (Transform val in array2) { if (!((Object)(object)val == (Object)null)) { GameObject gameObject = ((Component)val).gameObject; string name = ((Object)gameObject).name; if ((AttributeScanner.GetModObjectNames(CurrentAssembly).Contains(name) || name.StartsWith("VV_") || name.StartsWith("vv_")) && !((Object)(object)gameObject.GetComponentInParent(true) != (Object)null) && !HasCurrentAssemblyComponent(gameObject)) { list.Add(gameObject); } } } foreach (GameObject item in list) { if (!((Object)(object)item == (Object)null)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[HotReload] Destroying orphaned mod object: \"" + ((Object)item).name + "\"")); } item.SetActive(false); Object.Destroy((Object)(object)item); num++; } } return num; } private static bool HasCurrentAssemblyComponent(GameObject go) { MonoBehaviour[] components = go.GetComponents(); foreach (MonoBehaviour val in components) { if (!((Object)(object)val == (Object)null)) { Type type = ((object)val).GetType(); if (type.FullName != null && type.FullName.StartsWith("ValheimVillages.") && type.Assembly == CurrentAssembly) { return true; } } } return false; } public static void FixupExistingNPCs() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00bb: Unknown result type (might be due to invalid IL or missing references) int num = 0; ZNetView[] array = Object.FindObjectsOfType(); foreach (ZNetView val in array) { if ((Object)(object)val == (Object)null) { continue; } ZDO zDO = val.GetZDO(); if (zDO == null || zDO.GetPrefab() == RecordPrefabFactory.RecordPrefabHash || NativeNpcStripper.IsPlayerOwned(((Component)val).gameObject) || (string.IsNullOrEmpty(zDO.GetString("vv_record_id", "")) && string.IsNullOrEmpty(zDO.GetString("vv_villager_type", "")))) { continue; } if (zDO.GetVec3("vv_home_position", Vector3.zero) == Vector3.zero) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)($"[HotReload] NPC at {((Component)val).transform.position} " + "has no anchor position stored, skipping")); } continue; } RemoveOrphanedCraftingStations(((Component)val).gameObject); VillagerRestoration.Restore(((Component)val).gameObject, zDO); num++; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)$"[HotReload] Fixed up NPC at {((Component)val).transform.position}"); } } if (num > 0) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[HotReload] Fixed up {num} existing NPC(s)"); } } } public static void FixupExistingRegistries() { int stableHashCode = StringExtensionMethods.GetStableHashCode("vv_village_registry"); int num = 0; ZNetView[] array = Object.FindObjectsOfType(); foreach (ZNetView val in array) { if (!((Object)(object)val == (Object)null)) { ZDO zDO = val.GetZDO(); if (zDO != null && zDO.GetPrefab() == stableHashCode) { PieceFactory.ReapplyInteractionToInstance(((Component)val).gameObject); num++; } } } if (num > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[HotReload] Re-applied interaction to {num} placed registry station(s)"); } } } private static void RemoveOrphanedCraftingStations(GameObject go) { CraftingStation[] components = go.GetComponents(); foreach (CraftingStation val in components) { if (!((Object)(object)val == (Object)null) && val.m_name != null && val.m_name.StartsWith("$vv_")) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[HotReload] Removing orphaned CraftingStation '" + val.m_name + "' on \"" + ((Object)go).name + "\"")); } ((Behaviour)val).enabled = false; Object.Destroy((Object)(object)val); } } } } public static class PathTelemetry { [Serializable] private class HnaGraphData { public int regionCount; public int linkCount; public float minX; public float minZ; public float maxX; public float maxZ; public string regionCenters; public string linksSummary; } [Serializable] private class HnaPlayerDebugData { public float px; public float py; public float pz; public string regionId; public bool graphAvailable; public bool regionValid; public float solidHeightAtPosition; public float cellMinX; public float cellMaxX; public float cellMinZ; public float cellMaxZ; public float centerY; public float minY; public float maxY; public float verticalSpread; } private static readonly string LogPath = Path.Combine(Paths.ConfigPath, "vv_dumps", "path_telemetry.ndjson"); private static readonly object Lock = new object(); public static void LogRegionGraph(int regionCount, int linkCount, float minX, float minZ, float maxX, float maxZ, string regionCenters, string linksSummary) { HnaGraphData hnaGraphData = new HnaGraphData { regionCount = regionCount, linkCount = linkCount, minX = (float)Math.Round(minX, 2), minZ = (float)Math.Round(minZ, 2), maxX = (float)Math.Round(maxX, 2), maxZ = (float)Math.Round(maxZ, 2), regionCenters = (regionCenters ?? ""), linksSummary = (linksSummary ?? "") }; Write("hna_graph", JsonUtility.ToJson((object)hnaGraphData), "hna"); } public static void LogHnaPlayerDebug(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) float px = (float)Math.Round(position.x, 2); float py = (float)Math.Round(position.y, 2); float pz = (float)Math.Round(position.z, 2); RegionGraph regionGraph = VillageRegistry.GraphAt(position); string text = regionGraph?.PointToRegionId(position); float originX; float originZ; bool graphAvailable = regionGraph?.GetOrigin(out originX, out originZ) ?? false; bool flag = regionGraph != null && !string.IsNullOrEmpty(text) && regionGraph.IsValidRegion(text); float num = 0f; if ((Object)(object)ZoneSystem.instance != (Object)null) { ZoneSystem.instance.GetSolidHeight(new Vector3(position.x, 0f, position.z), ref num, 500); } float cellMinX = 0f; float cellMaxX = 0f; float cellMinZ = 0f; float cellMaxZ = 0f; float centerY = 0f; float num2 = 0f; float num3 = 0f; float minX = 0f; float maxX = 0f; float minZ = 0f; float maxZ = 0f; if (flag && regionGraph.GetRegionBounds(text, out minX, out maxX, out minZ, out maxZ)) { cellMinX = (float)Math.Round(minX, 2); cellMaxX = (float)Math.Round(maxX, 2); cellMinZ = (float)Math.Round(minZ, 2); cellMaxZ = (float)Math.Round(maxZ, 2); } float centerY2 = 0f; float minY = 0f; float maxY = 0f; if (flag && regionGraph.GetRegionSampleHeights(text, out centerY2, out minY, out maxY)) { centerY = (float)Math.Round(centerY2, 2); num2 = (float)Math.Round(minY, 2); num3 = (float)Math.Round(maxY, 2); } HnaPlayerDebugData hnaPlayerDebugData = new HnaPlayerDebugData { px = px, py = py, pz = pz, regionId = (text ?? ""), graphAvailable = graphAvailable, regionValid = flag, solidHeightAtPosition = (float)Math.Round(num, 2), cellMinX = cellMinX, cellMaxX = cellMaxX, cellMinZ = cellMinZ, cellMaxZ = cellMaxZ, centerY = centerY, minY = num2, maxY = num3, verticalSpread = (float)Math.Round(num3 - num2, 2) }; Write("hna_player_debug", JsonUtility.ToJson((object)hnaPlayerDebugData), "hna_debug"); } private static void Write(string message, string dataJson, string runId) { try { long num = (long)(Time.time * 1000f); string text = "pt_" + num; string contents = "{\"id\":\"" + text + "\",\"timestamp\":" + num + ",\"location\":\"PathTelemetry\",\"message\":\"" + Escape(message) + "\",\"data\":" + dataJson + ",\"runId\":\"" + Escape(runId) + "\",\"hypothesisId\":\"path_compare\"}\n"; lock (Lock) { File.AppendAllText(LogPath, contents); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[PathTelemetry] Write failed: " + ex.Message)); } } } private static string Escape(string s) { if (string.IsNullOrEmpty(s)) { return ""; } return s.Replace("\\", "\\\\").Replace("\"", "\\\""); } } public static class PhysicsHelper { public static T GetFirstInRadius(Vector3 center, float radius) where T : Component { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(center, radius); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { T componentInParent = ((Component)val).gameObject.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } } } return default(T); } public static List GetAllInRadius(Vector3 center, float radius) where T : Component { //IL_0006: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Collider[] array = Physics.OverlapSphere(center, radius); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { T componentInParent = ((Component)val).gameObject.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { list.Add(componentInParent); } } } return list; } } [BepInPlugin("com.valheimvillages.mod", "Valheim Villages", "0.1.1")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "com.valheimvillages.mod"; public const string PluginName = "Valheim Villages"; public const string PluginVersion = "0.1.1"; private static bool _recipeRefreshEnqueued; private static bool _regionPartitionEnqueued; private static bool _recordIndexEnqueued; private static bool _villageIndexEnqueued; private static float _hotReloadAt; private Harmony _harmony; public static readonly DateTime AssemblyLoadedAt = DateTime.UtcNow; public static ManualLogSource Log { get; private set; } public static Plugin Instance { get; private set; } public static bool LastLoadWasHotReload { get; private set; } private void Awake() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; bool num = (LastLoadWasHotReload = (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count > 0); DebugLog.BeginCycle(num); RegionGraphPersistence.LogAction = delegate(string msg) { Log.LogInfo((object)msg); }; Log.LogInfo((object)"Valheim Villages v0.1.1 loading..."); Harmony.UnpatchID("com.valheimvillages.mod"); _harmony = new Harmony("com.valheimvillages.mod"); _harmony.PatchAll(); LocalizationPatch.RegisterTokens(); if (num) { Log.LogInfo((object)"Hot reload detected — running full cleanup"); HotReloadHelper.FullCleanup(); } TaskHandlerRegistry.Clear(); AttributeScanner.ScanAndRegister(typeof(Plugin).Assembly); if (num) { Log.LogInfo((object)"Hot reload — re-registering items in ObjectDB"); ItemFactory.RegisterAll(ObjectDB.instance); VirtualRecipeLoader.RegisterAll(ObjectDB.instance); AttributeScanner.InvokeObjectDBRegistrations(typeof(Plugin).Assembly, ObjectDB.instance); } if (num && (Object)(object)ZNetScene.instance != (Object)null) { Log.LogInfo((object)"Hot reload — re-registering prefabs in ZNetScene"); ItemFactory.RegisterAllInZNetScene(ZNetScene.instance); PieceFactory.RegisterAllInZNetScene(ZNetScene.instance); RecordPrefabFactory.RegisterInZNetScene(ZNetScene.instance); VillagePrefabFactory.RegisterInZNetScene(ZNetScene.instance); Log.LogInfo((object)"Hot reload — fixing up existing NPC components"); HotReloadHelper.FixupExistingNPCs(); Log.LogInfo((object)"Hot reload — fixing up placed registry stations"); HotReloadHelper.FixupExistingRegistries(); _hotReloadAt = Time.realtimeSinceStartup; _regionPartitionEnqueued = false; _recordIndexEnqueued = false; _villageIndexEnqueued = false; Log.LogInfo((object)"Hot reload — armed hna_partition (will fire 5s after settle)"); } Log.LogInfo((object)"Valheim Villages loaded successfully!"); IncidentRecorder.ClearOnLoad(); FreezeTime.ApplyAutoFreeze(); if (num && ModTestRunner.AutoRunEnabled) { Log.LogInfo((object)"Scheduling integration tests (will defer until fixtures are ready)..."); GlobalTaskQueue.Enqueue(new VillagerTask { Name = "integration_tests", SourceId = "system", Priority = TaskPriority.Low, TimeoutSeconds = 120f, Attributes = new Dictionary() }); } } private void Update() { if (!_recipeRefreshEnqueued && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ZNetScene.instance != (Object)null && Time.realtimeSinceStartup > 3f) { _recipeRefreshEnqueued = true; GlobalTaskQueue.Enqueue(new VillagerTask { Name = "recipe_discovery_refresh", SourceId = "system", Priority = TaskPriority.Low, TimeoutSeconds = 30f, Attributes = new Dictionary() }); ManualLogSource log = Log; if (log != null) { log.LogDebug((object)"[Valheim Villages] Enqueued recipe_discovery_refresh (post–world load)"); } } if (!_recordIndexEnqueued && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ZNetScene.instance != (Object)null && Time.realtimeSinceStartup > 3f) { _recordIndexEnqueued = true; GlobalTaskQueue.Enqueue(new VillagerTask { Name = "villager_record_index", SourceId = "system", Priority = TaskPriority.High, TimeoutSeconds = 30f, Attributes = new Dictionary() }); ManualLogSource log2 = Log; if (log2 != null) { log2.LogDebug((object)"[Valheim Villages] Enqueued villager_record_index (post–world load)"); } } if (!_villageIndexEnqueued && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ZNetScene.instance != (Object)null && Time.realtimeSinceStartup > 3f) { _villageIndexEnqueued = true; GlobalTaskQueue.Enqueue(new VillagerTask { Name = "village_index", SourceId = "system", Priority = TaskPriority.High, TimeoutSeconds = 30f, Attributes = new Dictionary() }); ManualLogSource log3 = Log; if (log3 != null) { log3.LogDebug((object)"[Valheim Villages] Enqueued village_index (post–world load)"); } } if (!_regionPartitionEnqueued && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ZNetScene.instance != (Object)null && Time.realtimeSinceStartup > _hotReloadAt + 5f) { _regionPartitionEnqueued = true; GlobalTaskQueue.Enqueue(new VillagerTask { Name = "hna_partition", SourceId = "system", Priority = TaskPriority.Low, TimeoutSeconds = 30f, Attributes = new Dictionary() }); ManualLogSource log4 = Log; if (log4 != null) { log4.LogInfo((object)"[Valheim Villages] Enqueued hna_partition (low priority)"); } } if (PieceChangePatch.IsDirty && Time.realtimeSinceStartup - PieceChangePatch.LastStructureChangeTime > 10f) { PieceChangePatch.IsDirty = false; _regionPartitionEnqueued = false; ManualLogSource log5 = Log; if (log5 != null) { log5.LogInfo((object)"[Valheim Villages] Structure change detected, will re-enqueue hna_partition"); } } GlobalTaskQueue.ProcessBatch(); PathDebugRenderer.AutoEnable(); PlayerAvoidanceObstacle.Tick(); foreach (VillagerAI value in VillagerAIManager.ActiveVillagers.Values) { if ((Object)(object)value != (Object)null) { ((BaseAI)value).UpdateAI(Time.deltaTime); } } } } public static class VectorExtensions { public static float DistXZ(Vector3 a, Vector3 b) { //IL_0000: 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_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) float num = a.x - b.x; float num2 = a.z - b.z; return (float)Math.Sqrt(num * num + num2 * num2); } } } namespace ValheimVillages.Villages { [HarmonyPatch(typeof(BaseAI), "RandomMovement")] public static class EnemyAvoidancePatch { private const float AvoidanceRadius = 20f; private const int MaxRerollAttempts = 3; private static void Prefix(BaseAI __instance) { //IL_001a: 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) //IL_0056: 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_006b: 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) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if (VillageAreaManager.AreaCount == 0) { return; } Character component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || (int)component.m_faction == 0 || component.IsTamed()) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(BaseAI), "m_randomMoveTarget"); if (fieldInfo == null) { return; } Vector3 val = (Vector3)fieldInfo.GetValue(__instance); if (!VillageAreaManager.IsNearAnyVillage(val, 20f)) { return; } Vector3 position = ((Component)__instance).transform.position; float randomMoveRange = __instance.m_randomMoveRange; for (int i = 0; i < 3; i++) { float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f); float num2 = Random.Range(randomMoveRange * 0.3f, randomMoveRange); Vector3 val2 = position + new Vector3(Mathf.Cos(num) * num2, 0f, Mathf.Sin(num) * num2); if (!VillageAreaManager.IsNearAnyVillage(val2, 20f)) { fieldInfo.SetValue(__instance, val2); return; } } Vector3 val3 = position - val; Vector3 normalized = ((Vector3)(ref val3)).normalized; Vector3 val4 = position + normalized * randomMoveRange; fieldInfo.SetValue(__instance, val4); } } [HarmonyPatch(typeof(Piece), "SetCreator")] public static class StationBuildPatch { [HarmonyPostfix] public static void Postfix(Piece __instance) { if (!((Object)(object)__instance == (Object)null)) { VillageStationRegistry.RegisterStation(((Component)__instance).gameObject); ZNetView component = ((Component)__instance).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null && val.GetPrefab() == StringExtensionMethods.GetStableHashCode("vv_village_registry")) { LinkRegistryToVillage(val); } } } private static void LinkRegistryToVillage(ZDO registryZdo) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0029: 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) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(registryZdo.GetString("vv_village_id", ""))) { return; } Vector3 position = registryZdo.GetPosition(); Village village = VillageRegistry.GetVillageCovering(position) ?? VillageRegistry.GetOrCreateAt(position); if (village != null) { registryZdo.Set("vv_village_id", village.VillageId); registryZdo.Persistent = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[StationBuildPatch] Registry at ({position.x:F1},{position.y:F1},{position.z:F1}) -> village {village.VillageId}"); } } } } public class VillageArea { private readonly List m_polygon2D; private readonly List m_waypoints; public string VillageId { get; } public IReadOnlyList Waypoints => m_waypoints; public VillageArea(string villageId, List waypoints) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0047: 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) VillageId = villageId; m_waypoints = new List(waypoints); m_polygon2D = new List(waypoints.Count); foreach (Vector3 waypoint in waypoints) { m_polygon2D.Add(new Vector2(waypoint.x, waypoint.z)); } } public bool IsInsideArea(Vector3 position) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) if (m_polygon2D.Count < 3) { return false; } return IsPointInPolygon(new Vector2(position.x, position.z)); } public bool IsNearBoundary(Vector3 position, float radius) { //IL_0012: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (m_polygon2D.Count < 3) { return false; } Vector2 point = default(Vector2); ((Vector2)(ref point))..ctor(position.x, position.z); float num = radius * radius; for (int i = 0; i < m_polygon2D.Count; i++) { int index = (i + 1) % m_polygon2D.Count; if (PointToSegmentDistanceSq(point, m_polygon2D[i], m_polygon2D[index]) <= num) { return true; } } return false; } private bool IsPointInPolygon(Vector2 point) { //IL_0020: 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_002e: 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_0035: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_006a: 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) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) bool flag = false; int count = m_polygon2D.Count; int num = 0; int index = count - 1; while (num < count) { Vector2 val = m_polygon2D[num]; Vector2 val2 = m_polygon2D[index]; if (val.y > point.y != val2.y > point.y && point.x < (val2.x - val.x) * (point.y - val.y) / (val2.y - val.y) + val.x) { flag = !flag; } index = num++; } return flag; } private static float PointToSegmentDistanceSq(Vector2 point, Vector2 segA, Vector2 segB) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0029: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_0047: 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_004e: Unknown result type (might be due to invalid IL or missing references) Vector2 val = segB - segA; Vector2 val2 = point - segA; float sqrMagnitude = ((Vector2)(ref val)).sqrMagnitude; if (sqrMagnitude < 0.0001f) { return ((Vector2)(ref val2)).sqrMagnitude; } float num = Mathf.Clamp01(Vector2.Dot(val2, val) / sqrMagnitude); Vector2 val3 = segA + val * num; Vector2 val4 = point - val3; return ((Vector2)(ref val4)).sqrMagnitude; } } public static class VillageAreaManager { private static readonly Dictionary s_areas = new Dictionary(); public static int AreaCount => s_areas.Count; public static IEnumerable AllAreas => s_areas.Values; public static void RegisterArea(VillageArea area) { if (area != null) { s_areas[area.VillageId] = area; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[VillageArea] Registered area for {area.VillageId} with {area.Waypoints.Count} waypoints"); } VillageStationRegistry.RefreshFor(area); VillagePoiRegistry.RefreshFor(area); VillageRoomCatalog.RefreshFor(area); } } public static void UnregisterArea(string villageId) { if (s_areas.Remove(villageId)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[VillageArea] Unregistered area for " + villageId)); } VillageStationRegistry.RemoveFor(villageId); VillagePoiRegistry.RemoveFor(villageId); VillageRoomCatalog.RemoveFor(villageId); } } public static void RefreshFromVillage(Village village) { if (village == null || !village.HasGraph) { return; } string villageId = village.VillageId; List list = PatrolRouteBuilder.Build(village.Graph.GetBoundaryCells()); if (list == null || list.Count < 3) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[VillageArea] Skipped registration for village={villageId}: insufficient boundary waypoints ({list?.Count ?? 0})"); } } else { RegisterArea(new VillageArea(villageId, list)); } } public static bool IsInsideAnyVillage(Vector3 position) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) foreach (VillageArea value in s_areas.Values) { if (value.IsInsideArea(position)) { return true; } } return false; } public static bool IsNearAnyVillage(Vector3 position, float radius) { //IL_001b: 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) foreach (VillageArea value in s_areas.Values) { if (value.IsInsideArea(position) || value.IsNearBoundary(position, radius)) { return true; } } return false; } public static bool TryGetCombinedBounds(out float minX, out float minZ, out float maxX, out float maxZ) { //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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0077: 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) //IL_0089: 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_0094: Unknown result type (might be due to invalid IL or missing references) minX = (minZ = float.MaxValue); maxX = (maxZ = float.MinValue); if (s_areas.Count == 0) { return false; } foreach (VillageArea value in s_areas.Values) { foreach (Vector3 waypoint in value.Waypoints) { if (waypoint.x < minX) { minX = waypoint.x; } if (waypoint.x > maxX) { maxX = waypoint.x; } if (waypoint.z < minZ) { minZ = waypoint.z; } if (waypoint.z > maxZ) { maxZ = waypoint.z; } } } if (minX <= maxX) { return minZ <= maxZ; } return false; } [RegisterCleanup] public static void Clear() { s_areas.Clear(); VillageStationRegistry.Clear(); VillagePoiRegistry.Clear(); VillageRoomCatalog.Clear(); } } public static class VillagePoiRegistry { private static readonly Dictionary> s_poisByVillage = new Dictionary>(); public static void RefreshFor(VillageArea area) { //IL_0051: 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) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: 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_0074: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) if (area == null || area.Waypoints == null || area.Waypoints.Count < 3) { return; } float num = float.MaxValue; float num2 = float.MaxValue; float num3 = float.MinValue; float num4 = float.MinValue; float num5 = float.MaxValue; float num6 = float.MinValue; foreach (Vector3 waypoint in area.Waypoints) { if (waypoint.x < num) { num = waypoint.x; } if (waypoint.x > num3) { num3 = waypoint.x; } if (waypoint.z < num2) { num2 = waypoint.z; } if (waypoint.z > num4) { num4 = waypoint.z; } if (waypoint.y < num5) { num5 = waypoint.y; } if (waypoint.y > num6) { num6 = waypoint.y; } } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor((num + num3) * 0.5f, (num5 + num6) * 0.5f, (num2 + num4) * 0.5f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor((num3 - num) * 0.5f + 1f, (num6 - num5) * 0.5f + 20f, (num4 - num2) * 0.5f + 1f); HashSet outsideCells = RubberBandPrune.ComputeOutsideCellsForBake(new Bounds(val, new Vector3(val2.x * 2f, val2.y * 2f, val2.z * 2f))); List list = new List(); Collider[] array = Physics.OverlapBox(val, val2, Quaternion.identity); foreach (Collider val3 in array) { if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).gameObject == (Object)null) { continue; } LocationType? locationType = ClassifyPoi(((Component)val3).gameObject); if (locationType.HasValue) { Vector3 position = ((Component)val3).gameObject.transform.position; if (!RubberBandPrune.IsOutsideCell(position, outsideCells)) { bool hasShelter = VillagerBehaviorLogic.CheckShelter(position); float comfort = ComfortFor(locationType.Value, hasShelter); TryAddDeduped(list, position, locationType.Value, comfort, hasShelter); } } } s_poisByVillage[area.VillageId] = list; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[VillagePoiRegistry] {area.VillageId}: cached {list.Count} PoI(s) inside hull"); } } public static void RemoveFor(string villageKey) { s_poisByVillage.Remove(villageKey); } public static IReadOnlyList GetPois(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Village villageAt = VillageRegistry.GetVillageAt(position); if (villageAt == null) { return Array.Empty(); } if (!s_poisByVillage.TryGetValue(villageAt.VillageId, out var value)) { return Array.Empty(); } return value; } public static IEnumerable GetPois(Vector3 position, LocationType type) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) foreach (KnownLocation poi in GetPois(position)) { if (poi.Type == type) { yield return poi; } } } private static LocationType? ClassifyPoi(GameObject obj) { if ((Object)(object)obj == (Object)null) { return null; } if ((Object)(object)obj.GetComponent() != (Object)null) { return LocationType.Chair; } if ((Object)(object)obj.GetComponent() != (Object)null) { return LocationType.Fire; } string text = ((Object)obj).name.ToLowerInvariant(); if (text.Contains("table") || text.Contains("bench")) { return LocationType.Table; } if (text.Contains("cultivat") || text.Contains("sapling") || text.Contains("plant_")) { return LocationType.Farm; } return null; } private static float ComfortFor(LocationType type, bool hasShelter) { if (type == LocationType.Fire) { return hasShelter ? 2f : 0.5f; } return 1f; } private static void TryAddDeduped(List list, Vector3 pos, LocationType type, float comfort, bool hasShelter) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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) float minDistanceForType = KnownLocation.GetMinDistanceForType(type); int num = 0; foreach (KnownLocation item in list) { if (item.Type == type) { num++; if (Vector3.Distance(item.Position, pos) < minDistanceForType) { return; } } } if (num < KnownLocation.GetMaxLocationsForType(type)) { list.Add(new KnownLocation { Position = pos, Type = type, ComfortValue = comfort, HasShelter = hasShelter }); } } [DevCommand("List cached village PoIs (fire/table/chair/farm) for the village containing the player", Name = "vv_pois")] public static void DumpPois() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) //IL_0042: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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_0151: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; StringBuilder stringBuilder = new StringBuilder(); if ((Object)(object)localPlayer == (Object)null) { stringBuilder.AppendLine("[vv_pois] No local player."); } else { Vector3 position = ((Component)localPlayer).transform.position; Village villageAt = VillageRegistry.GetVillageAt(position); if (villageAt == null) { stringBuilder.AppendLine($"[vv_pois] player at ({position.x:F1},{position.z:F1}) is not inside any registered village."); } else { string villageId = villageAt.VillageId; List value; List list = (s_poisByVillage.TryGetValue(villageId, out value) ? value : null); stringBuilder.AppendLine($"[vv_pois] village {villageId}: {list?.Count ?? 0} PoI(s)"); if (list != null) { foreach (KnownLocation item in list) { stringBuilder.AppendLine($" [{item.Type}] @ ({item.Position.x:F1},{item.Position.y:F1},{item.Position.z:F1}) " + $"shelter={item.HasShelter} comfort={item.ComfortValue:F1} " + $"dist={Vector3.Distance(position, item.Position):F1}m"); } } } } Console instance = Console.instance; if (instance != null) { instance.Print(stringBuilder.ToString()); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } } [RegisterCleanup] public static void Clear() { s_poisByVillage.Clear(); } } public static class VillageRoomCatalog { public enum Feature { Fire, Seat, Table, Bed, WorkStation, Storage, Farm } public sealed class RegionRoom { public string RegionId; public readonly Dictionary Counts = new Dictionary(); public readonly List Roles = new List(); public Vector3 Center; public int PieceCount; } private static readonly Dictionary> s_roomsByVillage = new Dictionary>(); private const float ScanPadXZ = 12f; private static readonly Dictionary s_sitTypeCache = new Dictionary(); public static void RefreshFor(VillageArea area) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) if (area == null || area.Waypoints == null || area.Waypoints.Count < 3) { return; } RegionGraph regionGraph = VillageRegistry.FindById(area.VillageId)?.Graph; if (regionGraph == null) { return; } float num = float.MaxValue; float num2 = float.MaxValue; float num3 = float.MaxValue; float num4 = float.MinValue; float num5 = float.MinValue; float num6 = float.MinValue; foreach (Vector3 waypoint in area.Waypoints) { if (waypoint.x < num) { num = waypoint.x; } if (waypoint.x > num4) { num4 = waypoint.x; } if (waypoint.z < num2) { num2 = waypoint.z; } if (waypoint.z > num5) { num5 = waypoint.z; } if (waypoint.y < num3) { num3 = waypoint.y; } if (waypoint.y > num6) { num6 = waypoint.y; } } Vector3 val = new Vector3((num + num4) * 0.5f, (num3 + num6) * 0.5f, (num2 + num5) * 0.5f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor((num4 - num) * 0.5f + 12f, (num6 - num3) * 0.5f + 20f, (num5 - num2) * 0.5f + 12f); Dictionary dictionary = new Dictionary(); HashSet hashSet = new HashSet(); Collider[] array = Physics.OverlapBox(val, val2, Quaternion.identity); foreach (Collider val3 in array) { if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).gameObject == (Object)null) { continue; } Piece componentInParent = ((Component)val3).GetComponentInParent(); GameObject val4 = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).gameObject : ((Component)val3).gameObject); if (!hashSet.Add(val4) || !TryClassifyFeature(val4, out var feature)) { continue; } Vector3 position = val4.transform.position; string regionId = regionGraph.PointToRegionId(position); if (string.IsNullOrEmpty(regionId)) { regionGraph.TryFindNearestLookupCell(position, null, out var _, out regionId, 3f); } if (!string.IsNullOrEmpty(regionId)) { if (!dictionary.TryGetValue(regionId, out var value)) { string key = regionId; RegionRoom obj = new RegionRoom { RegionId = regionId }; value = obj; dictionary[key] = obj; } value.Counts.TryGetValue(feature, out var value2); value.Counts[feature] = value2 + 1; RegionRoom regionRoom = value; regionRoom.Center += position; value.PieceCount++; } } foreach (RegionRoom value3 in dictionary.Values) { if (value3.PieceCount > 0) { value3.Center /= (float)value3.PieceCount; } AssignRoles(value3); } s_roomsByVillage[area.VillageId] = dictionary; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[VillageRoomCatalog] {area.VillageId}: {dictionary.Count} furnished region(s)"); } } public static void RemoveFor(string villageKey) { s_roomsByVillage.Remove(villageKey); } public static IReadOnlyCollection GetRooms(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Village villageAt = VillageRegistry.GetVillageAt(position); if (villageAt == null) { return (IReadOnlyCollection)(object)Array.Empty(); } if (!s_roomsByVillage.TryGetValue(villageAt.VillageId, out var value)) { return (IReadOnlyCollection)(object)Array.Empty(); } return value.Values; } private static int Count(RegionRoom r, Feature f) { if (!r.Counts.TryGetValue(f, out var value)) { return 0; } return value; } private static void AssignRoles(RegionRoom r) { if (Count(r, Feature.Bed) >= 1) { r.Roles.Add("Bedroom"); } if (Count(r, Feature.Table) >= 1 && Count(r, Feature.Seat) >= 1) { r.Roles.Add((Count(r, Feature.Fire) >= 1) ? "Dining Hall" : "Dining Room"); } if (Count(r, Feature.WorkStation) >= 1) { r.Roles.Add("Workshop"); } if (Count(r, Feature.Farm) >= 1) { r.Roles.Add("Garden"); } if (Count(r, Feature.Storage) >= 1) { r.Roles.Add("Storage"); } if (r.Roles.Count == 0 && Count(r, Feature.Fire) >= 1) { r.Roles.Add("Hearth"); } } private static bool TryClassifyFeature(GameObject go, out Feature feature) { feature = Feature.Fire; if ((Object)(object)go == (Object)null) { return false; } if ((Object)(object)go.GetComponentInParent() != (Object)null) { feature = Feature.Bed; return true; } if (VillageStationRegistry.TryClassifyStation(go, out var _)) { feature = Feature.WorkStation; return true; } if (IsSittable(go)) { feature = Feature.Seat; return true; } if ((Object)(object)go.GetComponentInParent() != (Object)null) { feature = Feature.Fire; return true; } if ((Object)(object)go.GetComponentInParent() != (Object)null) { feature = Feature.Storage; return true; } string text = ((Object)go).name.ToLowerInvariant(); if (text.Contains("table")) { feature = Feature.Table; return true; } if (text.Contains("cultivat") || text.Contains("sapling") || text.Contains("plant_")) { feature = Feature.Farm; return true; } return false; } private static bool HasSitField(Type t) { if (s_sitTypeCache.TryGetValue(t, out var value)) { return value; } value = t.GetField("m_attachAnimation", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null; s_sitTypeCache[t] = value; return value; } private static bool IsSittable(GameObject go) { Piece componentInParent = go.GetComponentInParent(); MonoBehaviour[] componentsInChildren = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).gameObject : go).GetComponentsInChildren(true); foreach (MonoBehaviour val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { if (val is Chair) { return true; } if (HasSitField(((object)val).GetType())) { return true; } } } return false; } [DevCommand("List per-region room roles + furnishings for the village containing the player", Name = "vv_rooms")] public static void DumpRooms() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; StringBuilder stringBuilder = new StringBuilder(); if ((Object)(object)localPlayer == (Object)null) { stringBuilder.AppendLine("[vv_rooms] No local player."); } else { Village villageAt = VillageRegistry.GetVillageAt(((Component)localPlayer).transform.position); Dictionary value; if (villageAt == null) { stringBuilder.AppendLine("[vv_rooms] player is not inside any registered village."); } else if (!s_roomsByVillage.TryGetValue(villageAt.VillageId, out value) || value.Count == 0) { stringBuilder.AppendLine("[vv_rooms] village " + villageAt.VillageId + ": no furnished regions cached."); } else { stringBuilder.AppendLine($"[vv_rooms] village {villageAt.VillageId}: {value.Count} furnished region(s)"); foreach (RegionRoom value2 in value.Values) { string text = ((value2.Roles.Count > 0) ? string.Join(", ", value2.Roles) : "(unlabeled)"); List list = new List(); foreach (KeyValuePair count in value2.Counts) { list.Add($"{count.Key}×{count.Value}"); } stringBuilder.AppendLine($" [{value2.RegionId}] {text} @ ({value2.Center.x:F1},{value2.Center.y:F1},{value2.Center.z:F1}) — " + string.Join(" ", list)); } } } Console instance = Console.instance; if (instance != null) { instance.Print(stringBuilder.ToString()); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } } [RegisterCleanup] public static void Clear() { s_roomsByVillage.Clear(); } } public static class VillageStationRegistry { private static readonly Dictionary> s_stationsByVillage = new Dictionary>(); private const float StationScanPadXZ = 12f; private const float StationVillageReachXZ = 3f; private static readonly Dictionary s_conversionTypeCache = new Dictionary(); private const float MinApproachStandoffXZ = 1.5f; private const float PathSourceSnapMaxY = 3f; private const float ApproachMaxXzDist = 10f; private const float ApproachMaxYDelta = 3f; public static string LastApproachDiag = "(none)"; private static readonly int s_losMask = LayerMask.GetMask(new string[4] { "Default", "static_solid", "piece", "terrain" }); private static bool HasConversionField(Type t) { if (s_conversionTypeCache.TryGetValue(t, out var value)) { return value; } value = t.GetField("m_conversion", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null; s_conversionTypeCache[t] = value; return value; } public static bool TryClassifyStation(GameObject go, out Component station) { station = null; if ((Object)(object)go == (Object)null) { return false; } CraftingStation componentInParent = go.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { station = (Component)(object)componentInParent; return true; } Piece componentInParent2 = go.GetComponentInParent(); MonoBehaviour[] componentsInChildren = (((Object)(object)componentInParent2 != (Object)null) ? ((Component)componentInParent2).gameObject : go).GetComponentsInChildren(true); foreach (MonoBehaviour val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && HasConversionField(((object)val).GetType())) { station = (Component)(object)val; return true; } } return false; } private static bool BelongsToVillage(RegionGraph graph, Vector3 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (graph == null) { return false; } if (!string.IsNullOrEmpty(graph.PointToRegionId(pos))) { return true; } Vector3 worldPos; string regionId; return graph.TryFindNearestLookupCell(pos, null, out worldPos, out regionId, 3f); } public static void RegisterStation(GameObject go) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if (!TryClassifyStation(go, out var station)) { return; } Vector3 position = station.transform.position; foreach (Village item in VillageRegistry.EnumerateWithGraph()) { if (!BelongsToVillage(item.Graph, position)) { continue; } string villageId = item.VillageId; if (string.IsNullOrEmpty(villageId)) { continue; } if (!s_stationsByVillage.TryGetValue(villageId, out var value)) { value = (s_stationsByVillage[villageId] = new List()); } if (!value.Contains(station)) { value.Add(station); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[VillageStationRegistry] +" + ((object)station).GetType().Name + " " + ((Object)station.gameObject).name + " " + $"@ ({position.x:F1},{position.y:F1},{position.z:F1}) → {villageId} (on build)")); } } break; } } public static void RefreshFor(VillageArea area) { //IL_0051: 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) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_00ff: 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_0074: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) if (area == null || area.Waypoints == null || area.Waypoints.Count < 3) { return; } float num = float.MaxValue; float num2 = float.MaxValue; float num3 = float.MinValue; float num4 = float.MinValue; float num5 = float.MaxValue; float num6 = float.MinValue; foreach (Vector3 waypoint in area.Waypoints) { if (waypoint.x < num) { num = waypoint.x; } if (waypoint.x > num3) { num3 = waypoint.x; } if (waypoint.z < num2) { num2 = waypoint.z; } if (waypoint.z > num4) { num4 = waypoint.z; } if (waypoint.y < num5) { num5 = waypoint.y; } if (waypoint.y > num6) { num6 = waypoint.y; } } Vector3 val = new Vector3((num + num3) * 0.5f, (num5 + num6) * 0.5f, (num2 + num4) * 0.5f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor((num3 - num) * 0.5f + 12f, (num6 - num5) * 0.5f + 20f, (num4 - num2) * 0.5f + 12f); RegionGraph regionGraph = VillageRegistry.FindById(area.VillageId)?.Graph; List list = new List(); HashSet hashSet = new HashSet(); int num7 = 0; int num8 = 0; Collider[] array = Physics.OverlapBox(val, val2, Quaternion.identity); foreach (Collider val3 in array) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Component)val3).gameObject == (Object)null) && TryClassifyStation(((Component)val3).gameObject, out var station) && hashSet.Add(station)) { num7++; if (regionGraph == null || BelongsToVillage(regionGraph, station.transform.position)) { list.Add(station); num8++; } } } s_stationsByVillage[area.VillageId] = list; if (Plugin.Log == null) { return; } Plugin.Log.LogInfo((object)($"[VillageStationRegistry] {area.VillageId}: cached {list.Count} stations " + $"(candidates {num7} → kept {num8})")); foreach (Component item in list) { Vector3 position = item.transform.position; Plugin.Log.LogInfo((object)$" [{((object)item).GetType().Name}] {((Object)item.gameObject).name} @ ({position.x:F1},{position.y:F1},{position.z:F1})"); } } public static void RemoveFor(string villageKey) { s_stationsByVillage.Remove(villageKey); } public static bool HasVillageFor(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string villageId; return TryGetVillage(position, out villageId); } public static bool TryFindStation(Vector3 position, Func filter, out Vector3 stationPos, out T component) where T : Component { //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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) stationPos = Vector3.zero; component = default(T); if (!TryGetVillage(position, out var villageId)) { return false; } if (!s_stationsByVillage.TryGetValue(villageId, out var value)) { return false; } T val = default(T); float num = float.MaxValue; foreach (Component item in value) { if ((Object)(object)item == (Object)null) { continue; } T val2 = (T)(object)((item is T) ? item : null); if (!((Object)(object)val2 == (Object)null) && (filter == null || filter(val2))) { Vector3 val3 = ((Component)val2).transform.position - position; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val = val2; } } } if ((Object)(object)val == (Object)null) { return false; } if (!TryResolveApproach(((Component)val).transform.position, position, out var approach)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[VillageStationRegistry] " + villageId + ": no HNA-valid approach to " + ((Object)((Component)val).gameObject).name + " " + $"@ ({((Component)val).transform.position.x:F1},{((Component)val).transform.position.y:F1},{((Component)val).transform.position.z:F1})")); } stationPos = Vector3.zero; component = default(T); return false; } stationPos = approach; component = val; return true; } public static bool TryResolveApproach(Vector3 target, Vector3 pathSource, out Vector3 approach, Vector3? villageAnchor = null) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_0027: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) approach = Vector3.zero; RegionGraph regionGraph = VillageRegistry.GetVillageAt(villageAnchor.GetValueOrDefault(pathSource))?.Graph; if (regionGraph == null) { LastApproachDiag = $"no graph for source ({pathSource.x:F1},{pathSource.y:F1},{pathSource.z:F1})"; return false; } bool flag = true; if (!regionGraph.TryFindNearestLookupCell(pathSource, (Vector3 cell) => Mathf.Abs(cell.y - pathSource.y) <= 3f, out var worldPos, out var regionId)) { flag = false; if (!regionGraph.TryFindNearestLookupCell(pathSource, null, out worldPos, out regionId)) { worldPos = pathSource; } } float minStandoffSq = 2.25f; int considered = 0; int levelPass = 0; int standoffPass = 0; int losPass = 0; bool flag2 = regionGraph.TryFindNearestLookupCell(target, delegate(Vector3 candidate) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0085: 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) considered++; if (Mathf.Abs(candidate.y - target.y) > 3f) { return false; } levelPass++; float num = candidate.x - target.x; float num2 = candidate.z - target.z; if (num * num + num2 * num2 < minStandoffSq) { return false; } standoffPass++; if (!HasClearLineToStation(candidate, target)) { return false; } losPass++; return true; }, out approach, out regionId, 10f); LastApproachDiag = string.Format("src=({0:F1},{1:F1},{2:F1}) snap={3} ", pathSource.x, pathSource.y, pathSource.z, flag ? "y" : "fallback") + $"pathStart=({worldPos.x:F1},{worldPos.y:F1},{worldPos.z:F1}) " + $"tgt=({target.x:F1},{target.y:F1},{target.z:F1}) " + $"considered={considered} levelPass={levelPass} standoffPass={standoffPass} losPass={losPass} " + "result=" + (flag2 ? $"({approach.x:F1},{approach.y:F1},{approach.z:F1})" : "FAIL"); return flag2; } private static bool HasClearLineToStation(Vector3 approach, Vector3 station) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0026: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_004b: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_008b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = approach + Vector3.up * 1.2f; Vector3 val2 = station + Vector3.up * 1.2f - val; float magnitude = ((Vector3)(ref val2)).magnitude; if (magnitude < 0.01f) { return true; } Vector3 val3 = val2 / magnitude; RaycastHit[] array = Physics.RaycastAll(val, val3, magnitude, s_losMask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val4 = array[i]; if (!((Object)(object)((RaycastHit)(ref val4)).collider == (Object)null)) { Bounds bounds = ((RaycastHit)(ref val4)).collider.bounds; if (!((Bounds)(ref bounds)).Contains(station)) { return false; } } } return true; } [DevCommand("Diagnose HNA approach resolution to a target from a source (default player). Usage: vv_approach [ ]", Name = "vv_approach")] public static void ApproachDiag(ConsoleEventArgs args) { //IL_0080: 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_0085: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013f: 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_00c3: Unknown result type (might be due to invalid IL or missing references) CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (args?.Args == null || args.Args.Length < 3 || !float.TryParse(args.Args[1], NumberStyles.Float, invariantCulture, out var result) || !float.TryParse(args.Args[2], NumberStyles.Float, invariantCulture, out var result2)) { Console instance = Console.instance; if (instance != null) { instance.Print("Usage: vv_approach [ ]"); } return; } Vector3 val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero); if (args.Args.Length >= 5 && float.TryParse(args.Args[3], NumberStyles.Float, invariantCulture, out var result3) && float.TryParse(args.Args[4], NumberStyles.Float, invariantCulture, out var result4)) { ((Vector3)(ref val))..ctor(result3, val.y, result4); } float num = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.GetGroundHeight(new Vector3(result, 0f, result2)) : 0f); Vector3 approach; bool flag = TryResolveApproach(new Vector3(result, num, result2), val, out approach); string text = $"[vv_approach] ok={flag} approach=({approach.x:F1},{approach.y:F1},{approach.z:F1})\n {LastApproachDiag}"; Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(text); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } } [DevCommand("Dump cached village stations + HNA approach resolution for each villager anchor", Name = "vv_stations")] public static void DumpStations() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); List allAnchorPositions = VillagerAIManager.GetAllAnchorPositions(); stringBuilder.AppendLine($"[vv_stations] {allAnchorPositions.Count} anchor(s); {s_stationsByVillage.Count} village(s) cached"); foreach (Vector3 item in allAnchorPositions) { if (!TryGetVillage(item, out var villageId)) { stringBuilder.AppendLine($" anchor=({item.x:F1},{item.y:F1},{item.z:F1}) → NO containing village"); continue; } List value; List list = (s_stationsByVillage.TryGetValue(villageId, out value) ? value : null); stringBuilder.AppendLine($" anchor=({item.x:F1},{item.y:F1},{item.z:F1}) → village {villageId}: " + $"{list?.Count ?? 0} station(s)"); if (list == null) { continue; } foreach (Component item2 in list) { if (!((Object)(object)item2 == (Object)null)) { Vector3 position = item2.transform.position; Vector3 approach; bool flag = TryResolveApproach(position, item, out approach); stringBuilder.AppendLine(" [" + ((object)item2).GetType().Name + "] " + ((Object)item2.gameObject).name + " " + $"@ ({position.x:F1},{position.y:F1},{position.z:F1}) dist={Vector3.Distance(item, position):F1}m " + "approach=" + (flag ? $"({approach.x:F1},{approach.y:F1},{approach.z:F1})" : "UNREACHABLE")); } } } Console instance = Console.instance; if (instance != null) { instance.Print(stringBuilder.ToString()); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } } [RegisterCleanup] public static void Clear() { s_stationsByVillage.Clear(); } private static bool TryGetVillage(Vector3 position, out string villageId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Village villageAt = VillageRegistry.GetVillageAt(position); villageId = villageAt?.VillageId; return villageAt != null; } } public static class WallDetection { private static readonly string[] WallPrefixes = new string[9] { "wood_wall", "stone_wall", "stakewall", "darkwood_gate", "iron_wall", "dungeon_wall", "goblin_wall", "dvergr_wall", "piece_wall" }; private static readonly string[] DoorPrefixes = new string[5] { "wood_door", "iron_door", "darkwood_door", "dvergr_door", "door" }; private static int? s_pieceMask; private static int PieceMask { get { int valueOrDefault = s_pieceMask.GetValueOrDefault(); if (!s_pieceMask.HasValue) { valueOrDefault = LayerMask.GetMask(new string[3] { "piece", "static_solid", "Default" }); s_pieceMask = valueOrDefault; } return s_pieceMask.Value; } } public static bool IsWallPiece(GameObject obj) { if ((Object)(object)obj == (Object)null) { return false; } if ((Object)(object)obj.GetComponentInParent() == (Object)null) { return false; } string lowerName = ((Object)obj).name.ToLower(); if (!IsWallName(lowerName)) { return IsDoorName(lowerName); } return true; } public static bool RaycastForWall(Vector3 origin, Vector3 direction, float maxDist, out RaycastHit wallHit) { //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_000a: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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) wallHit = default(RaycastHit); RaycastHit[] array = Physics.RaycastAll(origin, ((Vector3)(ref direction)).normalized, maxDist, PieceMask); float num = float.MaxValue; bool result = false; RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val = array2[i]; if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && IsWallPiece(((Component)((RaycastHit)(ref val)).collider).gameObject) && ((RaycastHit)(ref val)).distance < num) { num = ((RaycastHit)(ref val)).distance; wallHit = val; result = true; } } return result; } private static bool IsWallName(string lowerName) { string[] wallPrefixes = WallPrefixes; foreach (string value in wallPrefixes) { if (lowerName.Contains(value)) { return true; } } return lowerName.Contains("wall"); } private static bool IsDoorName(string lowerName) { string[] doorPrefixes = DoorPrefixes; foreach (string value in doorPrefixes) { if (lowerName.Contains(value)) { return true; } } return false; } } } namespace ValheimVillages.Villages.Entity { public sealed class Village { public const string IdKey = "vv_village_id"; public const string AnchorKey = "vv_village_anchor"; public const string GraphKey = "vv_village_graph"; private readonly ZDO m_zdo; private RegionGraph m_graph; private bool m_hydrated; public ZDO Zdo => m_zdo; public bool IsValid { get { if (m_zdo != null) { return !string.IsNullOrEmpty(VillageId); } return false; } } public string VillageId => m_zdo.GetString("vv_village_id", ""); public Vector3 Anchor { get { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return m_zdo.GetVec3("vv_village_anchor", Vector3.zero); } set { //IL_000b: Unknown result type (might be due to invalid IL or missing references) m_zdo.Set("vv_village_anchor", value); m_zdo.Persistent = true; } } public RegionGraph Graph { get { if (!m_hydrated) { HydrateGraphFromZdo(); } return m_graph; } } public bool HasGraph { get { if (Graph != null) { return Graph.IsAvailable; } return false; } } public Village(ZDO zdo) { m_zdo = zdo; } public RegionGraph GetOrCreateGraph() { if (Graph == null) { m_graph = new RegionGraph { RegisteredVillageKey = VillageId }; m_hydrated = true; } return m_graph; } public void HydrateGraphFromZdo() { m_hydrated = true; string text = m_zdo.GetString("vv_village_graph", ""); if (string.IsNullOrEmpty(text)) { return; } RegionGraph graph = new RegionGraph { RegisteredVillageKey = VillageId }; if (RegionGraphPersistence.Restore(graph, text)) { m_graph = graph; return; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Village] Wiping unparseable graph blob for village " + VillageId + " " + $"(bytes={text.Length}); will rebuild on next partition")); } m_zdo.Set("vv_village_graph", ""); m_zdo.Persistent = true; } public void SaveGraph() { if (m_graph != null && m_graph.IsAvailable) { m_zdo.Set("vv_village_graph", RegionGraphPersistence.Serialize(m_graph)); m_zdo.Persistent = true; } } } public static class VillagePrefabFactory { public const string VillagePrefabName = "vv_village"; public static readonly int VillagePrefabHash = StringExtensionMethods.GetStableHashCode("vv_village"); private static GameObject _prefab; public static void RegisterInZNetScene(ZNetScene zNetScene) { if ((Object)(object)zNetScene == (Object)null) { return; } if ((Object)(object)_prefab == (Object)null) { _prefab = zNetScene.GetPrefab("vv_village"); } if ((Object)(object)_prefab == (Object)null) { _prefab = BuildPrefab(); } if (!((Object)(object)_prefab == (Object)null)) { if (!zNetScene.m_prefabs.Contains(_prefab)) { zNetScene.m_prefabs.Add(_prefab); } Dictionary privateDictionary = GetPrivateDictionary(zNetScene, "m_namedPrefabs"); if (privateDictionary != null) { privateDictionary[VillagePrefabHash] = _prefab; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[VillagePrefabFactory] Registered 'vv_village' carrier in ZNetScene"); } } } private static GameObject BuildPrefab() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0020: 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_0031: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown GameObject val = new GameObject("vv_village"); val.SetActive(false); ZNetView obj = val.AddComponent(); obj.m_persistent = true; obj.m_type = (ObjectType)0; obj.m_distant = false; Object.DontDestroyOnLoad((Object)val); val.SetActive(true); return val; } private static Dictionary GetPrivateDictionary(T instance, string fieldName) { return typeof(T).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance) as Dictionary; } } public static class VillageRegistry { private static readonly Dictionary s_live = new Dictionary(); public static bool IsAnyAvailable => EnumerateWithGraph().Any(); public static Village Create(Vector3 anchor) { //IL_0021: 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_0093: 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_00af: Unknown result type (might be due to invalid IL or missing references) ZDOMan instance = ZDOMan.instance; if (instance == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[VillageRegistry] Cannot create village: ZDOMan not ready"); } return null; } ZDO obj = instance.CreateNewZDO(anchor, VillagePrefabFactory.VillagePrefabHash); obj.SetPrefab(VillagePrefabFactory.VillagePrefabHash); obj.Persistent = true; string text = Guid.NewGuid().ToString(); obj.Set("vv_village_id", text); Village village = new Village(obj) { Anchor = anchor }; s_live[text] = village; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[VillageRegistry] Created village {text} at ({anchor.x:F1},{anchor.y:F1},{anchor.z:F1})"); } return village; } public static IEnumerable EnumerateAll() { ZDOMan instance = ZDOMan.instance; if (instance == null) { yield break; } Dictionary value = Traverse.Create((object)instance).Field>("m_objectsByID").Value; if (value == null) { yield break; } foreach (ZDO value3 in value.Values) { if (value3 == null || value3.GetPrefab() != VillagePrefabFactory.VillagePrefabHash) { continue; } string text = value3.GetString("vv_village_id", ""); if (!string.IsNullOrEmpty(text)) { if (!s_live.TryGetValue(text, out var value2)) { value2 = new Village(value3); s_live[text] = value2; } yield return value2; } } } public static IEnumerable EnumerateWithGraph() { return from v in EnumerateAll() where v.HasGraph select v; } public static IEnumerable AllGraphs() { return from v in EnumerateWithGraph() select v.Graph; } public static RegionGraph GraphAt(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return GetVillageAt(pos)?.Graph; } public static Village FindById(string villageId) { if (string.IsNullOrEmpty(villageId)) { return null; } if (s_live.TryGetValue(villageId, out var value) && value.IsValid) { return value; } foreach (Village item in EnumerateAll()) { if (item.VillageId == villageId) { return item; } } return null; } public static Village GetVillageAt(Vector3 pos) { //IL_0033: 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_005b: Unknown result type (might be due to invalid IL or missing references) Village result = null; float num = float.MaxValue; foreach (Village item in EnumerateAll()) { RegionGraph graph = item.Graph; if (graph == null || !graph.IsAvailable) { continue; } if (!string.IsNullOrEmpty(graph.PointToRegionId(pos))) { return item; } if (graph.GetOrigin(out var originX, out var originZ)) { float num2 = pos.x - originX; float num3 = pos.z - originZ; float num4 = num2 * num2 + num3 * num3; if (num4 < num) { num = num4; result = item; } } } return result; } public static Village FindNearAnchor(Vector3 anchor, float radius = 30f) { //IL_001b: 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) //IL_0022: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Village result = null; float num = radius * radius; foreach (Village item in EnumerateAll()) { Vector3 anchor2 = item.Anchor; float num2 = anchor.x - anchor2.x; float num3 = anchor.z - anchor2.z; float num4 = num2 * num2 + num3 * num3; if (num4 <= num) { num = num4; result = item; } } return result; } public static Village GetVillageCovering(Vector3 pos) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) foreach (Village item in EnumerateAll()) { RegionGraph graph = item.Graph; if (graph != null && graph.IsAvailable && !string.IsNullOrEmpty(graph.PointToRegionId(pos))) { return item; } } return null; } public static Village GetOrCreateAt(Vector3 anchor, float relinkRadius = 30f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) return FindNearAnchor(anchor, relinkRadius) ?? Create(anchor); } public static (int villages, int withGraph) HydrateAll() { s_live.Clear(); int num = 0; int num2 = 0; foreach (Village item in EnumerateAll()) { num++; item.HydrateGraphFromZdo(); if (item.HasGraph) { num2++; } } return (villages: num, withGraph: num2); } [RegisterCleanup] public static void ClearAll() { foreach (Village value in s_live.Values) { value.Graph?.Clear(); } s_live.Clear(); } } } namespace ValheimVillages.Villager { public class Dialog { public static void ConfigureDialog(GameObject npcObject, VillagerDef villagerDef) { if (villagerDef == null) { return; } VillagerTalk component = npcObject.GetComponent(); if (!((Object)(object)component == (Object)null)) { List randomTalk = villagerDef.randomTalk; if (randomTalk != null && randomTalk.Count > 0) { component.randomTalk = new List(villagerDef.randomTalk); } List randomGreets = villagerDef.randomGreets; if (randomGreets != null && randomGreets.Count > 0) { component.randomGreets = new List(villagerDef.randomGreets); } List randomGoodbye = villagerDef.randomGoodbye; if (randomGoodbye != null && randomGoodbye.Count > 0) { component.randomGoodbye = new List(villagerDef.randomGoodbye); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("Configured dialog for " + villagerDef.displayName)); } } } } public static class NativeNpcStripper { private static readonly string[] BaseAiRpcs = new string[3] { "Alert", "OnNearProjectileHit", "SetAggravated" }; public static bool IsPlayerOwned(GameObject go) { if ((Object)(object)go != (Object)null) { return (Object)(object)go.GetComponentInParent() != (Object)null; } return false; } public static bool IsPlayerOwned(Character character) { if ((Object)(object)character != (Object)null) { return (Object)(object)((Component)character).GetComponentInParent() != (Object)null; } return false; } public static void Strip(GameObject go) { if ((Object)(object)go == (Object)null) { return; } if (IsPlayerOwned(go)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[NativeNpcStripper] Refusing to strip native components on player-owned object '" + ((Object)go).name + "' — a villager lookup resolved to the player character.")); } return; } Character component = go.GetComponent(); UnregisterBaseAiRpcs(go.GetComponent()); PruneDeadHandlers(component); MonsterAI component2 = go.GetComponent(); if ((Object)(object)component2 != (Object)null) { DetachHandlers(component, component2); Object.DestroyImmediate((Object)(object)component2); } Tameable component3 = go.GetComponent(); if ((Object)(object)component3 != (Object)null) { DetachHandlers(component, component3); Object.DestroyImmediate((Object)(object)component3); } NpcTalk component4 = go.GetComponent(); if ((Object)(object)component4 != (Object)null) { Object.DestroyImmediate((Object)(object)component4); } } private static void UnregisterBaseAiRpcs(ZNetView nview) { if (!((Object)(object)nview == (Object)null)) { string[] baseAiRpcs = BaseAiRpcs; foreach (string text in baseAiRpcs) { nview.Unregister(text); } } } private static void DetachHandlers(Character character, object component) { if (!((Object)(object)character == (Object)null) && component != null) { character.m_onDamaged = (Action)Prune(character.m_onDamaged, component); character.m_onDeath = (Action)Prune(character.m_onDeath, component); } } private static void PruneDeadHandlers(Character character) { if (!((Object)(object)character == (Object)null)) { character.m_onDamaged = (Action)Prune(character.m_onDamaged, null); character.m_onDeath = (Action)Prune(character.m_onDeath, null); } } private static Delegate Prune(Delegate multicast, object component) { if ((object)multicast == null) { return null; } Delegate obj = multicast; Delegate[] invocationList = multicast.GetInvocationList(); foreach (Delegate obj2 in invocationList) { object target = obj2.Target; Object val = (Object)((target is Object) ? target : null); bool flag = val != null && val == (Object)null; if ((component != null && target == component) || flag) { obj = Delegate.Remove(obj, obj2); } } return obj; } } public static class VillagerSpawner { public static void LogAvailableDvergrPrefabs() { if ((Object)(object)ZNetScene.instance == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"ZNetScene not available for prefab listing"); } return; } List list = (from p in ZNetScene.instance.m_prefabs where (Object)(object)p != (Object)null && ((Object)p).name.IndexOf("dvergr", StringComparison.OrdinalIgnoreCase) >= 0 select ((Object)p).name into n orderby n select n).ToList(); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"Found {list.Count} Dvergr prefabs:"); } foreach (string item in list) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)(" - " + item)); } } } internal static GameObject SpawnVillagerNpc(VillagerDef villagerDef, string villagerType, string villagerPrefab, Vector3 anchorPos, ref VillagerRecord record, string contextVillageId = null) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0130: 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) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(villagerPrefab) : null); if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("Failed to find prefab " + villagerPrefab)); } return null; } GameObject val2 = Object.Instantiate(val, anchorPos + Vector3.up * 0.7f, Quaternion.identity); if ((Object)(object)val2 == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)"Failed to instantiate NPC"); } return null; } if (NativeNpcStripper.IsPlayerOwned(val2)) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)("[SpawnVillagerNpc] Prefab '" + villagerPrefab + "' resolved to a player-owned object; aborting spawn.")); } Object.Destroy((Object)(object)val2); return null; } Humanoid component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { ((Character)component).m_name = villagerDef.displayName; Character component2 = val2.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.m_faction = (Faction)0; } } val2.AddComponent(); val2.AddComponent(); Dialog.ConfigureDialog(val2, villagerDef); ZNetView component3 = val2.GetComponent(); if ((Object)(object)component3 == (Object)null || component3.GetZDO() == null) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)"Spawned NPC has no ZNetView/ZDO"); } Object.Destroy((Object)(object)val2); return null; } ZDOID uid = component3.GetZDO().m_uid; string text = ((record != null && !string.IsNullOrEmpty(record.Village)) ? record.Village : contextVillageId); if (string.IsNullOrEmpty(text)) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogError((object)"[SpawnVillagerNpc] No village to spawn into (villages are created only at a registry station). Aborting spawn."); } Object.Destroy((Object)(object)val2); return null; } if (record == null) { record = VillagerRecordTable.Create(villagerType, villagerDef.displayName, text, anchorPos, RecordStatus.Alive, uid); if (record == null) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogError((object)"Failed to mint villager record; aborting spawn"); } Object.Destroy((Object)(object)val2); return null; } } else { record.Status = RecordStatus.Alive; record.NpcZdoId = uid; record.HomeAnchor = anchorPos; } component3.GetZDO().Set("vv_record_id", record.RecordId); component3.GetZDO().Set("vv_village_id", text); component3.GetZDO().Set("vv_home_position", anchorPos); component3.GetZDO().Persistent = true; NativeNpcStripper.Strip(val2); val2.AddComponent(); VillagerBehaviorBridge villagerBehaviorBridge = val2.AddComponent(); villagerBehaviorBridge.villagerInstance = val2.GetComponent(); villagerBehaviorBridge.Initialize(record.RecordId); val2.AddComponent(); val2.AddComponent().Initialize(villagerType); return val2; } } public class Villager : MonoBehaviour { public string villagerName = "Villager"; public string uid; public string villagerType; public ZNetView nView; public VillagerAI villagerAI; private Vector3 m_homeAnchor; private ZDO m_zdo; public Vector3 HomeAnchor { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return m_homeAnchor; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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) m_homeAnchor = value; nView.GetZDO().Set("vv_home_position", m_homeAnchor); } } public void Awake() { nView = ((Component)this).GetComponent(); if ((Object)(object)nView != (Object)null) { m_zdo = nView.GetZDO(); } if (m_zdo != null) { LoadIdentityFromRecord(); } if ((Object)(object)villagerAI == (Object)null) { villagerAI = ((Component)this).gameObject.AddComponent(); } if (m_zdo != null && (Object)(object)villagerAI != (Object)null) { villagerAI.LoadMemories(m_zdo); } } private void LoadIdentityFromRecord() { //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_00a6: Unknown result type (might be due to invalid IL or missing references) string text = m_zdo.GetString("vv_record_id", ""); VillagerRecord villagerRecord = VillagerRecordTable.FindById(text); if (villagerRecord == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Villager] No record found for vv_record_id '" + text + "' on '" + villagerName + "' — identity unresolved (mint/migrate invariant violated)")); } } else { uid = villagerRecord.RecordId; villagerType = villagerRecord.Type; villagerName = villagerRecord.Name; m_homeAnchor = villagerRecord.HomeAnchor; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)$"[Villager] '{villagerName}' home from record={villagerRecord.HomeAnchor}"); } } } private void LoadFromZDO() { if (m_zdo != null) { LoadIdentityFromRecord(); if ((Object)(object)villagerAI != (Object)null) { villagerAI.LoadMemories(m_zdo); } } } private void SaveToZDO() { villagerAI.SaveMemories(m_zdo); } } public class VillagerAdapter : IVillager { public Vector3 HomeAnchor { get; } public VillagerWaypoint CurrentWaypoint { get; } public string VillagerName { get; } public string VillagerType { get; } public string UniqueID { get; } public VillagerAdapter(Villager villagerInstance) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) VillagerName = villagerInstance.villagerName; VillagerType = villagerInstance.villagerType; UniqueID = villagerInstance.uid; HomeAnchor = villagerInstance.HomeAnchor; CurrentWaypoint = villagerInstance.villagerAI?.GetCurrentWaypoint(); } } public static class VillagerRestoration { public static bool Restore(GameObject go, ZDO zdo) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null || zdo == null) { return false; } if (NativeNpcStripper.IsPlayerOwned(go)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[VillagerRestoration] Refusing to restore player-owned object '" + ((Object)go).name + "'.")); } return false; } if (zdo.GetPrefab() == RecordPrefabFactory.RecordPrefabHash) { return false; } VillagerRecord villagerRecord = ResolveOrMigrateRecord(zdo); if (villagerRecord == null) { return false; } string recordId = villagerRecord.RecordId; if ((Object)(object)go.GetComponent() != (Object)null) { return false; } string type = villagerRecord.Type; VillagerDef villagerDef = VillagerRegistry.Get(type); if (villagerDef == null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[VillagerRestoration] No definition for type '" + type + "', skipping")); } return false; } zdo.Persistent = true; StripNativeComponents(go); RestoreIdentity(go, villagerDef); RestoreComponents(go, recordId, type); Dialog.ConfigureDialog(go, villagerDef); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[VillagerRestoration] Restored {villagerDef.displayName} ({type}) at {go.transform.position}"); } return true; } private static VillagerRecord ResolveOrMigrateRecord(ZDO zdo) { //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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) string text = zdo.GetString("vv_record_id", ""); if (!string.IsNullOrEmpty(text)) { VillagerRecord villagerRecord = VillagerRecordTable.FindById(text); if (villagerRecord != null) { return villagerRecord; } } string text2 = zdo.GetString("vv_villager_type", ""); if (string.IsNullOrEmpty(text2)) { if (!string.IsNullOrEmpty(text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[VillagerRestoration] vv_record_id '" + text + "' has no record and no legacy identity to migrate; skipping")); } } return null; } string text3 = zdo.GetString("vv_villager_name", ""); Vector3 vec = zdo.GetVec3("vv_home_position", Vector3.zero); string text4 = zdo.GetString("vv_village_id", ""); string text5 = ((!string.IsNullOrEmpty(text4)) ? text4 : (VillageRegistry.GetVillageCovering(vec) ?? VillageRegistry.FindNearAnchor(vec))?.VillageId); if (string.IsNullOrEmpty(text5)) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)($"[VillagerRestoration] legacy villager '{text3}' ({text2}) at {vec} " + "resolves to no village; not migrating (villages are created only at a registry station).")); } return null; } VillagerRecord villagerRecord2 = VillagerRecordTable.Create(text2, string.IsNullOrEmpty(text3) ? text2 : text3, text5, vec, RecordStatus.Alive, zdo.m_uid); if (villagerRecord2 == null) { return null; } zdo.Set("vv_record_id", villagerRecord2.RecordId); zdo.Set("vv_village_id", text5); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[VillagerRestoration] Migrated legacy villager '" + text3 + "' (" + text2 + ") -> record " + villagerRecord2.RecordId)); } return villagerRecord2; } private static void StripNativeComponents(GameObject go) { NativeNpcStripper.Strip(go); } private static void RestoreIdentity(GameObject go, VillagerDef definition) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) Humanoid component = go.GetComponent(); if ((Object)(object)component != (Object)null && !string.IsNullOrEmpty(definition?.displayName)) { ((Character)component).m_name = definition.displayName; } Character component2 = go.GetComponent(); if ((Object)(object)component2 != (Object)null && !NativeNpcStripper.IsPlayerOwned(component2)) { component2.m_faction = (Faction)0; } } private static void RestoreComponents(GameObject go, string uniqueId, string typeStr) { if ((Object)(object)go.GetComponent() == (Object)null) { go.AddComponent(); } if ((Object)(object)go.GetComponent() == (Object)null) { go.AddComponent(); } if ((Object)(object)go.GetComponent() == (Object)null) { go.AddComponent(); } if ((Object)(object)go.GetComponent() == (Object)null) { VillagerBehaviorBridge villagerBehaviorBridge = go.AddComponent(); villagerBehaviorBridge.villagerInstance = go.GetComponent(); villagerBehaviorBridge.Initialize(uniqueId); } if ((Object)(object)go.GetComponent() == (Object)null) { go.AddComponent(); } if ((Object)(object)go.GetComponent() == (Object)null) { go.AddComponent().Initialize(typeStr); } } } public class VillagerTalk : MonoBehaviour { private static float s_lastTalkTime; public List randomTalk = new List(); public List randomGreets = new List(); public List randomGoodbye = new List(); public float maxRange = 20f; public float greetRange = 10f; public float byeRange = 15f; public float offset = 2.2f; public float hideDialogDelay = 12f; public float randomTalkInterval = 12f; public float randomTalkChance = 0.3f; public float minTalkInterval = 24f; private bool m_didGoodbye; private bool m_didGreet; private float m_lastTargetUpdate; private float m_nextRandomTalk; private Player m_targetPlayer; private void Start() { m_nextRandomTalk = Time.time + Random.Range(4f, randomTalkInterval); } private void Update() { //IL_0020: 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) UpdateTarget(); if ((Object)(object)m_targetPlayer == (Object)null) { return; } float num = Vector3.Distance(((Component)m_targetPlayer).transform.position, ((Component)this).transform.position); if (!m_didGreet && num < greetRange) { m_didGreet = true; m_didGoodbye = false; QueueSay(randomGreets); } if (m_didGreet && !m_didGoodbye && num > byeRange) { m_didGoodbye = true; QueueSay(randomGoodbye); } if (Time.time >= m_nextRandomTalk) { m_nextRandomTalk = Time.time + randomTalkInterval; if (Random.value < randomTalkChance) { QueueSay(randomTalk); } } } private void UpdateTarget() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - m_lastTargetUpdate < 1f)) { m_lastTargetUpdate = Time.time; m_targetPlayer = null; Player closestPlayer = Player.GetClosestPlayer(((Component)this).transform.position, maxRange); if (!((Object)(object)closestPlayer == (Object)null)) { m_targetPlayer = closestPlayer; } } } private void QueueSay(List lines) { if (lines != null && lines.Count != 0 && !(Time.time - s_lastTalkTime < minTalkInterval)) { string text = lines[Random.Range(0, lines.Count)]; Say(text); } } private void Say(string text) { //IL_001a: 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) s_lastTalkTime = Time.time; Chat instance = Chat.instance; if (instance != null) { instance.SetNpcText(((Component)this).gameObject, Vector3.up * offset, 20f, hideDialogDelay, "", text, false); } } } } namespace ValheimVillages.Villager.Station { public class VillagerStation : MonoBehaviour { public const string GenericStationName = "$vv_villager"; public CraftingStation Station { get; private set; } private static string GetVirtualStationName(string villagerType) { VillagerDef villagerDef = VillagerRegistry.Get(villagerType); if (string.IsNullOrEmpty(villagerDef?.stationName)) { return null; } return villagerDef.stationName; } public static bool HasCraftingRecipes(string villagerType) { VillagerDef villagerDef = VillagerRegistry.Get(villagerType); if (villagerDef?.tags != null) { return TagParser.HasTag(villagerDef.tags, "tab", "workorder"); } return false; } public static string GetStationName(string villagerType) { return GetVirtualStationName(villagerType) ?? "$vv_villager"; } public static bool IsVirtualStation(string stationName) { return stationName?.StartsWith("$vv_") ?? false; } public void Initialize(string villagerType) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown string stationName = GetStationName(villagerType); Station = ((Component)this).gameObject.AddComponent(); Station.m_name = stationName; Station.m_icon = GetStationIconFor(villagerType); Station.m_discoverRange = 0f; Station.m_rangeBuild = 0f; Station.m_craftRequireRoof = false; Station.m_craftRequireFire = false; Station.m_showBasicRecipies = false; Station.m_useDistance = 10f; Station.m_useAnimation = 0; Station.m_areaMarker = null; Station.m_inUseObject = null; Station.m_haveFireObject = null; Station.m_craftItemEffects = new EffectList(); Station.m_craftItemDoneEffects = new EffectList(); Station.m_repairItemDoneEffects = new EffectList(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("VillagerStation: Initialized '" + stationName + "' for " + villagerType)); } } private static Sprite GetStationIconFor(string villagerType) { string text = VillagerRegistry.Get(villagerType)?.stationIcon; if (string.IsNullOrEmpty(text)) { return null; } ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(text) : null); if ((Object)(object)val == (Object)null) { return null; } Sprite[] array = val.GetComponent()?.m_itemData?.m_shared?.m_icons; if (array == null || array.Length == 0) { return null; } return array[0]; } } } namespace ValheimVillages.Villager.Registry { public static class VillagerRegistry { private static Dictionary _definitions; public static IReadOnlyDictionary Definitions { get { EnsureInitialized(); return _definitions; } } public static IEnumerable EnabledDefinitions { get { EnsureInitialized(); foreach (VillagerDef value in _definitions.Values) { if (!value.disabled) { yield return value; } } } } public static VillagerDef Get(string villagerType) { EnsureInitialized(); if (!_definitions.TryGetValue(villagerType, out var value)) { return null; } return value; } public static bool IsEnabled(string villagerType) { VillagerDef villagerDef = Get(villagerType); if (villagerDef != null) { return !villagerDef.disabled; } return false; } private static void EnsureInitialized() { if (_definitions != null) { return; } _definitions = new Dictionary(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (!text.Contains(".Villager.Registry.Definitions.") || !text.EndsWith(".json")) { continue; } try { using Stream stream = executingAssembly.GetManifestResourceStream(text); using StreamReader streamReader = new StreamReader(stream); VillagerDef villagerDef = JsonUtility.FromJson(streamReader.ReadToEnd()); if (!string.IsNullOrEmpty(villagerDef?.type)) { _definitions[villagerDef.type] = villagerDef; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("Loaded villager: " + villagerDef.displayName + " (" + villagerDef.category + ")")); } } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("Failed to load villager definition " + text + ": " + ex.Message)); } } } ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"VillagerRegistry initialized with {_definitions.Count} types"); } } } } namespace ValheimVillages.Villager.Records { public static class RecordPrefabFactory { public const string RecordPrefabName = "vv_villager_record"; public static readonly int RecordPrefabHash = StringExtensionMethods.GetStableHashCode("vv_villager_record"); private static GameObject _prefab; public static void RegisterInZNetScene(ZNetScene zNetScene) { if ((Object)(object)zNetScene == (Object)null) { return; } if ((Object)(object)_prefab == (Object)null) { _prefab = zNetScene.GetPrefab("vv_villager_record"); } if ((Object)(object)_prefab == (Object)null) { _prefab = BuildPrefab(); } if (!((Object)(object)_prefab == (Object)null)) { if (!zNetScene.m_prefabs.Contains(_prefab)) { zNetScene.m_prefabs.Add(_prefab); } Dictionary privateDictionary = GetPrivateDictionary(zNetScene, "m_namedPrefabs"); if (privateDictionary != null) { privateDictionary[RecordPrefabHash] = _prefab; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[RecordPrefabFactory] Registered 'vv_villager_record' carrier in ZNetScene"); } } } private static GameObject BuildPrefab() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0020: 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_0031: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown GameObject val = new GameObject("vv_villager_record"); val.SetActive(false); ZNetView obj = val.AddComponent(); obj.m_persistent = true; obj.m_type = (ObjectType)0; obj.m_distant = false; Object.DontDestroyOnLoad((Object)val); val.SetActive(true); return val; } private static Dictionary GetPrivateDictionary(T instance, string fieldName) { return typeof(T).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance) as Dictionary; } } public enum RecordStatus { Egg, Alive, Dead } public sealed class VillagerRecord { public const string IdKey = "vv_record_id"; public const string TypeKey = "vv_record_type"; public const string NameKey = "vv_record_name"; public const string StatusKey = "vv_record_status"; public const string VillageTag = "vv_record_village"; public const string HomeKey = "vv_record_home"; public const string EggPrefabKey = "vv_record_egg_prefab"; public const string NpcKey = "vv_record_npc"; private readonly ZDO m_zdo; public ZDO Zdo => m_zdo; public bool IsValid { get { if (m_zdo != null) { return !string.IsNullOrEmpty(RecordId); } return false; } } public string RecordId => m_zdo.GetString("vv_record_id", ""); public string Type { get { return m_zdo.GetString("vv_record_type", ""); } set { SetString("vv_record_type", value); } } public string Name { get { return m_zdo.GetString("vv_record_name", ""); } set { SetString("vv_record_name", value); } } public RecordStatus Status { get { return (RecordStatus)m_zdo.GetInt("vv_record_status", 1); } set { m_zdo.Set("vv_record_status", (int)value); m_zdo.Persistent = true; } } public string Village { get { return m_zdo.GetString("vv_record_village", ""); } set { SetString("vv_record_village", value); } } public Vector3 HomeAnchor { get { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return m_zdo.GetVec3("vv_record_home", Vector3.zero); } set { //IL_000b: Unknown result type (might be due to invalid IL or missing references) m_zdo.Set("vv_record_home", value); m_zdo.Persistent = true; } } public string EggPrefab { get { return m_zdo.GetString("vv_record_egg_prefab", ""); } set { SetString("vv_record_egg_prefab", value); } } public ZDOID NpcZdoId { get { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return m_zdo.GetZDOID("vv_record_npc"); } set { //IL_000b: Unknown result type (might be due to invalid IL or missing references) m_zdo.Set("vv_record_npc", value); m_zdo.Persistent = true; } } public VillagerRecord(ZDO zdo) { m_zdo = zdo; } private void SetString(string key, string value) { m_zdo.Set(key, value ?? ""); m_zdo.Persistent = true; } } public static class VillagerRecordCommands { [DevCommand("Dump villager records [alive|dead|egg|]", Name = "vv_records")] public static void Dump(ConsoleEventArgs args) { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) string text = ((args.Length > 1) ? args[1] : null); List list = (string.Equals(text, "alive", StringComparison.OrdinalIgnoreCase) ? Filter(RecordStatus.Alive) : (string.Equals(text, "dead", StringComparison.OrdinalIgnoreCase) ? Filter(RecordStatus.Dead) : (string.Equals(text, "egg", StringComparison.OrdinalIgnoreCase) ? Filter(RecordStatus.Egg) : (string.IsNullOrEmpty(text) ? VillagerRecordTable.EnumerateAll().ToList() : VillagerRecordTable.QueryByVillage(text).ToList())))); Print(string.Format("[vv_records] {0} record(s){1}", list.Count, (text != null) ? (" (filter: " + text + ")") : "")); foreach (VillagerRecord item in list) { Print($" {item.Status,-5} {item.Name} ({item.Type}) village={item.Village} id={item.RecordId} npc={item.NpcZdoId}"); } } [DevCommand("Kill nearest active villager (or by record id) to test the death->Dead flow", Name = "vv_kill_villager")] public static void KillVillager(ConsoleEventArgs args) { //IL_004f: 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_0054: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) string text = ((args.Length > 1) ? args[1] : null); VillagerAI value = null; if (!string.IsNullOrEmpty(text)) { VillagerAIManager.ActiveVillagers.TryGetValue(text, out value); } else { Vector3 val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero); float num = float.MaxValue; foreach (VillagerAI value2 in VillagerAIManager.ActiveVillagers.Values) { if (!((Object)(object)value2 == (Object)null)) { Vector3 val2 = ((Component)value2).transform.position - val; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; value = value2; } } } } if ((Object)(object)value == (Object)null) { Print("[vv_kill_villager] no matching active villager found"); return; } Character component = ((Component)value).GetComponent(); if ((Object)(object)component == (Object)null) { Print("[vv_kill_villager] villager has no Character component"); return; } try { HitData val3 = new HitData { m_point = ((Component)component).transform.position, m_dir = Vector3.up, m_hitType = (HitType)0 }; val3.m_damage.m_blunt = 100000f; component.Damage(val3); Print($"[vv_kill_villager] applied lethal damage to '{component.m_name}' at {((Component)component).transform.position}"); } catch (Exception ex) { Print("[vv_kill_villager] Damage threw: " + ex.GetType().Name + ": " + ex.Message); ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[vv_kill_villager] Damage threw:\n{ex}"); } } } [DevCommand("Set a record's status: vv_set_record_status ", Name = "vv_set_record_status")] public static void SetRecordStatus(ConsoleEventArgs args) { if (args.Length < 3) { Print("usage: vv_set_record_status "); return; } if (!Enum.TryParse(args[2], ignoreCase: true, out var result)) { Print("[vv_set_record_status] unknown status '" + args[2] + "' (alive|dead|egg)"); return; } VillagerRecordTable.SetStatus(args[1], result); Print($"[vv_set_record_status] {args[1]} -> {result}"); } [DevCommand("Recruit a villager of at the player position (test): vv_recruit ", Name = "vv_recruit")] public static void Recruit(ConsoleEventArgs args) { //IL_005e: 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_0063: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (args.Length < 2) { Print("usage: vv_recruit "); return; } VillagerDef villagerDef = VillagerRegistry.Get(args[1]); if (villagerDef == null) { Print("[vv_recruit] unknown type '" + args[1] + "'"); return; } Vector3 val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero); string text = (VillageRegistry.GetVillageCovering(val) ?? VillageRegistry.FindNearAnchor(val))?.VillageId; if (string.IsNullOrEmpty(text)) { Print("[vv_recruit] no village here — place a registry station first (villages are minted only there)"); return; } string villagerPrefab = ((!string.IsNullOrEmpty(villagerDef.preferredPrefab)) ? villagerDef.preferredPrefab : "DvergerMage"); VillagerRecord record = null; Print(((Object)(object)VillagerSpawner.SpawnVillagerNpc(villagerDef, villagerDef.type, villagerPrefab, val, ref record, text) != (Object)null) ? $"[vv_recruit] recruited {villagerDef.type} at {val} into village {text}" : "[vv_recruit] failed"); } [DevCommand("Revive a fallen villager by record id: vv_revive ", Name = "vv_revive")] public static void Revive(ConsoleEventArgs args) { if (args.Length < 2) { Print("usage: vv_revive "); } else { Print(VillagerReviveService.Revive(VillagerRecordTable.FindById(args[1]), out var error) ? ("[vv_revive] revived " + args[1]) : ("[vv_revive] failed: " + error)); } } private static List Filter(RecordStatus status) { return (from r in VillagerRecordTable.EnumerateAll() where r.Status == status select r).ToList(); } private static void Print(string msg) { Console instance = Console.instance; if (instance != null) { instance.Print(msg); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)msg); } } } public static class VillagerRecordTable { public static VillagerRecord Create(string type, string name, string villageKey, Vector3 anchorPos, RecordStatus status, ZDOID npcZdoId) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) ZDOMan instance = ZDOMan.instance; if (instance == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[VillagerRecordTable] Cannot create record: ZDOMan not ready"); } return null; } ZDO obj = instance.CreateNewZDO(anchorPos, RecordPrefabFactory.RecordPrefabHash); obj.SetPrefab(RecordPrefabFactory.RecordPrefabHash); obj.Persistent = true; string text = Guid.NewGuid().ToString(); obj.Set("vv_record_id", text); VillagerRecord result = new VillagerRecord(obj) { Type = type, Name = name, Village = villageKey, HomeAnchor = anchorPos, Status = status, NpcZdoId = npcZdoId, EggPrefab = "" }; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[VillagerRecordTable] Created record {text} ({status}) type={type} name={name} village={villageKey}"); } return result; } public static IEnumerable EnumerateAll() { ZDOMan instance = ZDOMan.instance; if (instance == null) { yield break; } Dictionary value = Traverse.Create((object)instance).Field>("m_objectsByID").Value; if (value == null) { yield break; } foreach (ZDO value2 in value.Values) { if (value2 != null && value2.GetPrefab() == RecordPrefabFactory.RecordPrefabHash) { yield return new VillagerRecord(value2); } } } public static VillagerRecord FindById(string recordId) { if (string.IsNullOrEmpty(recordId)) { return null; } foreach (VillagerRecord item in EnumerateAll()) { if (item.RecordId == recordId) { return item; } } return null; } public static IEnumerable QueryByVillage(string villageKey) { foreach (VillagerRecord item in EnumerateAll()) { if (KeysMatch(item.Village, villageKey)) { yield return item; } } } public static IEnumerable QueryByStatus(string villageKey, RecordStatus status) { foreach (VillagerRecord item in EnumerateAll()) { if (item.Status == status && KeysMatch(item.Village, villageKey)) { yield return item; } } } public static void SetStatus(string recordId, RecordStatus status) { VillagerRecord villagerRecord = FindById(recordId); if (villagerRecord == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[VillagerRecordTable] SetStatus: record " + recordId + " not found")); } return; } villagerRecord.Status = status; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[VillagerRecordTable] Record {recordId} -> {status}"); } } public static int AuditOrphans() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) ZDOMan instance = ZDOMan.instance; if (instance == null) { return 0; } int num = 0; foreach (VillagerRecord item in EnumerateAll()) { if (item.Status != RecordStatus.Alive) { continue; } ZDOID npcZdoId = item.NpcZdoId; if (!(npcZdoId == ZDOID.None) && instance.GetZDO(npcZdoId) == null) { num++; ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[VillagerRecordTable] ORPHANED Alive record " + item.RecordId + " (type=" + item.Type + " name=" + item.Name + " village=" + item.Village + "): its linked NPC " + $"ZDO {npcZdoId} no longer exists in the world. The record was left INTACT — this " + "is an invariant violation, not a cue to auto-delete. Investigate why the NPC vanished (link broken on reload, removed without a clean death, etc.).")); } } } if (num > 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)($"[VillagerRecordTable] {num} orphaned Alive record(s) detected (see errors " + "above). Records were NOT modified.")); } } return num; } public static bool KeysMatch(string a, string b) { if (!string.IsNullOrEmpty(a)) { return a == b; } return false; } } public static class VillagerReviveService { public const float CooldownSeconds = 30f; private const string DefaultPrefab = "DvergerMage"; private static float s_lastReviveTime = -30f; public static bool IsOnCooldown => Time.time - s_lastReviveTime < 30f; public static float CooldownRemaining => Mathf.Max(0f, 30f - (Time.time - s_lastReviveTime)); public static bool Revive(VillagerRecord record, out string error) { return Revive(record, null, out error); } public static bool Revive(VillagerRecord record, Vector3? anchor, out string error) { //IL_007e: 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) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_009c: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) error = null; if (record == null) { error = "no record"; return false; } if (record.Status != RecordStatus.Dead) { error = "villager is not fallen"; return false; } if (IsOnCooldown) { error = $"revive on cooldown ({CooldownRemaining:F0}s)"; return false; } VillagerDef villagerDef = VillagerRegistry.Get(record.Type); if (villagerDef == null) { error = "unknown villager type '" + record.Type + "'"; return false; } Vector3 val = (Vector3)(((??)anchor) ?? record.HomeAnchor); if (val == Vector3.zero) { error = "no anchor/home position to revive at"; return false; } Vector3 val2 = val; if (RegistrySeedResolver.TryResolveWalkableSeed(val, out var seed)) { val2 = seed; } else { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)($"[Revive] No walkable seed near anchor ({val.x:F1},{val.y:F1},{val.z:F1}) " + "for '" + record.Name + "'; reviving at the anchor as-is.")); } } string villagerPrefab = ((!string.IsNullOrEmpty(villagerDef.preferredPrefab)) ? villagerDef.preferredPrefab : "DvergerMage"); VillagerRecord record2 = record; if ((Object)(object)VillagerSpawner.SpawnVillagerNpc(villagerDef, record.Type, villagerPrefab, val2, ref record2) == (Object)null) { error = "failed to spawn villager"; return false; } s_lastReviveTime = Time.time; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Revive] Revived '" + record.Name + "' (" + record.Type + ") record " + record.RecordId + " at " + $"({val2.x:F1},{val2.y:F1},{val2.z:F1})")); } return true; } } } namespace ValheimVillages.Villager.AI { public static class VillagerBehaviorLogic { public static BehaviorContext GetCurrentContext(VillagerAI ai) { //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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) Vector3 position = ai.Position; float dayFraction = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetDayFraction() : 0.5f); bool isRaining = (Object)(object)EnvMan.instance != (Object)null && (EnvMan.IsWet() || EnvMan.instance.IsEnvironment("Rain")); return new BehaviorContext { CurrentPosition = position, TimeOfDay = GetTimeOfDay(dayFraction), IsRaining = isRaining, InShelter = CheckShelter(position), CurrentComfort = 0f }; } private static TimeOfDay GetTimeOfDay(float dayFraction) { if (dayFraction >= 0.875f || dayFraction < 0.25f) { return TimeOfDay.Evening; } if (dayFraction < 0.417f) { return TimeOfDay.Morning; } if (dayFraction < 0.708f) { return TimeOfDay.Day; } return TimeOfDay.Evening; } public static bool CheckShelter(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); if (Physics.Raycast(position + Vector3.up * 0.5f, Vector3.up, ref val, 50f)) { Collider collider = ((RaycastHit)(ref val)).collider; if ((Object)(object)((collider != null) ? ((Component)collider).GetComponentInParent() : null) != (Object)null) { return true; } if ((Object)(object)((RaycastHit)(ref val)).collider != (Object)null && ((Component)((RaycastHit)(ref val)).collider).gameObject.isStatic) { return true; } } return false; } } public static class VillagerComfort { public static void UpdateExperiencedComfort(Transform transform, IVillagerMemory memory) { //IL_000e: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)transform == (Object)null) && memory != null) { Vector3 position = transform.position; memory.UpdateBestComfort(CalculateCurrentComfort(position), position); } } private static float CalculateCurrentComfort(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) float num = 0f; if (VillagerBehaviorLogic.CheckShelter(position)) { num += 1f; } Collider[] array = Physics.OverlapSphere(position, 10f); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && (Object)(object)((Component)val).GetComponent() != (Object)null) { num += 1f; break; } } return num; } } public class VillagerAI : BaseAI, IVillagerWorkContext, IVillagerStationLookup { private const float SaveInterval = 60f; private const float NavToSnapRadius = 2f; private NavMeshAgent m_navAgent; private Vector3 m_lastAgentDest = new Vector3(float.PositiveInfinity, 0f, 0f); private Vector3 m_homeAnchor; private List m_behaviors = new List(); private VillagerWaypoint m_currentWaypoint; private DoorHandler m_doorHandler; private float m_explorationStartTime; private Vector3? m_explorationTarget; private float m_lastBehaviorUpdateTime; private float m_nextReselectOverride = -1f; private float m_lastDiscoveryTime; private float m_lastMemorySaveTime; private bool m_directOrderActive; private bool m_stallLogged; private float m_stallStartTime; internal readonly AiEventRing EventRing = new AiEventRing(); private float m_stuckBackoffUntil; private string m_villagerName; private List m_waypointPath; private bool m_warnedNoHome; private bool m_rescuing; private float m_nextRescueCheck; private float m_strandedSince; private Vector3 m_rescueLastPos; private float m_rescueProgressTime; private const float RescueCheckInterval = 1f; private const float StrandConfirmSeconds = 2f; private const float RescueStuckSeconds = 3f; private const float RescueProgressEps = 0.5f; public float LingerUntilTime { get; set; } public Vector3 LingerAtPos { get; set; } public bool IsLingering => Time.time < LingerUntilTime; public bool IsCasualTravel { get; set; } private DoorHandler DoorHandler => m_doorHandler ?? (m_doorHandler = ((Component)this).GetComponent()); public Villager Villager { get; private set; } public string NpcName => m_villagerName ?? Villager?.villagerName ?? "Unknown"; public string UniqueId { get; private set; } public Vector3 Position { get { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Villager != (Object)null)) { return Vector3.zero; } return ((Component)Villager).transform.position; } } public VillagerMemory Memory { get; private set; } public BaseAI Instance => (BaseAI)(object)this; public ZNetView NView => Villager?.nView; public Character Character { get { if (!((Object)(object)Villager != (Object)null)) { return null; } return ((Component)Villager).GetComponent(); } } public Humanoid Humanoid { get { Character character = Character; return (Humanoid)(object)((character is Humanoid) ? character : null); } } public Vector3? CurrentTarget { get { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (m_currentWaypoint == null) { return null; } return m_currentWaypoint.Position; } } public CraftingBehaviorAdapter CraftingBehavior => GetBehavior(); public string VillagerType { get; private set; } Vector3 IVillagerStationLookup.HomeAnchor { get { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (Memory == null) { return default(Vector3); } return Memory.HomeAnchor; } } public Vector3 HomeAnchor => m_homeAnchor; string IVillagerWorkContext.NpcName => NpcName; Vector3 IVillagerWorkContext.Position => Position; public BehaviorState CurrentState { get; private set; } public IBehavior ActiveBehavior { get; private set; } public bool IsInBackoff => Time.time < m_stuckBackoffUntil; public bool IsPaused { get; private set; } public VillagerAI(Villager instance) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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) Villager = instance; UniqueId = Villager.uid; m_homeAnchor = Villager.HomeAnchor; VillagerType = Villager.villagerType; m_villagerName = Villager.villagerName; Memory = new VillagerMemory(m_homeAnchor); } public VillagerAI() { }//IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) protected override void Awake() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) try { ((BaseAI)this).Awake(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[VillagerAI] base.Awake() threw: " + ex.GetType().Name + ": " + ex.Message)); } } if ((Object)(object)base.m_character == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("[VillagerAI] base.Awake() did not complete (m_character is null) on '" + ((Object)this).name + "'; AI will not activate. Indicates a native-component cleanup or double-init regression.")); } return; } if (VillagerAgentType.EnsureRegistered()) { base.m_pathAgentType = VillagerAgentType.AgentType; } if ((Object)(object)Villager == (Object)null) { Villager = ((Component)this).GetComponent(); if ((Object)(object)Villager == (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)"[VillagerAI] No Villager component on this GameObject"); } return; } UniqueId = Villager.uid; m_homeAnchor = Villager.HomeAnchor; VillagerType = Villager.villagerType; m_villagerName = Villager.villagerName; Memory = new VillagerMemory(m_homeAnchor); VillagerAIManager.RegisterActive(this); } m_doorHandler = ((Component)this).GetComponent(); RegisterHome(); RegisterBehaviors(); m_lastBehaviorUpdateTime = Random.Range(0f, 11f); } private void OnDestroy() { try { ZNetView component = ((Component)this).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null) { SaveMemories(val); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[VillagerAI] OnDestroy SaveMemories failed: " + ex.Message)); } } VillagerAIManager.Unregister(this); } public void RegisterHome() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Memory.HomeAnchor = m_homeAnchor; } public override bool UpdateAI(float dt) { //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_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Villager == (Object)null) { return false; } if (!((BaseAI)this).UpdateAI(dt)) { return false; } if (m_homeAnchor == Vector3.zero) { if (!m_warnedNoHome) { m_warnedNoHome = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[AI:" + m_villagerName + "] No valid anchor position — skipping AI tick (broken/zombie villager).")); } } return false; } if ((double)m_lastBehaviorUpdateTime > 0.0) { m_lastBehaviorUpdateTime -= dt; } if (IsPaused) { return true; } if (VillageNavLock.IsHeld) { ((BaseAI)this).StopMoving(); if ((Object)(object)m_navAgent != (Object)null && m_navAgent.isOnNavMesh) { m_navAgent.ResetPath(); } return true; } if (TryOffMeshRescue(dt)) { return true; } if (Time.time - m_lastDiscoveryTime > 4f) { m_lastDiscoveryTime = Time.time; VillagerComfort.UpdateExperiencedComfort(((Component)this).transform, Memory); } if (m_lastBehaviorUpdateTime <= 0f) { if (!m_directOrderActive) { BehaviorContext ctx = default(BehaviorContext); bool flag = false; foreach (IBehavior behavior in m_behaviors) { if (behavior.WantsControl(ctx)) { ActiveBehavior = behavior; behavior.Update(dt); flag = true; break; } } if (!flag) { ActiveBehavior = null; if (CurrentState != BehaviorState.Working) { GetWorkScanner()?.TryScanForWork(); } if (CurrentState != BehaviorState.Idle) { SetState(BehaviorState.Idle); } } } m_lastBehaviorUpdateTime = ((m_nextReselectOverride >= 0f) ? m_nextReselectOverride : 2f); m_nextReselectOverride = -1f; } if (Time.time - m_lastMemorySaveTime > 60f) { m_lastMemorySaveTime = Time.time; ZNetView component = ((Component)this).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null) { SaveMemories(val); } } if (m_currentWaypoint != null && NeedsMovement(CurrentState)) { Vector3 position = m_currentWaypoint.Position; float num = Vector3.Distance(((Component)this).transform.position, position); float lookahead = ((CurrentState == BehaviorState.Patrolling) ? 2f : 0f); if (AgentHasArrived(position, lookahead)) { OnArrivedAtTarget(dt); } else { bool running = CurrentState == BehaviorState.Patrolling || (!IsCasualTravel && num > 5f); UpdateAgentMovement(position, running); } } return false; } public void LoadMemories(ZDO zdo) { Memory.LoadFromZDO(zdo); VillagerActivityLog.Instance.LoadFromZDO(UniqueId, zdo); foreach (IBehavior behavior in m_behaviors) { if (behavior is IBehaviorPersistence behaviorPersistence) { behaviorPersistence.Load(zdo); } } } public void SaveMemories(ZDO zdo) { Memory.SaveToZDO(zdo); VillagerActivityLog.Instance.SaveToZDO(UniqueId, zdo); VillagerActivityLog.Instance.MarkCommitted(UniqueId); VillagerActivityLog.Instance.TrimCommitted(UniqueId); foreach (IBehavior behavior in m_behaviors) { if (behavior is IBehaviorPersistence behaviorPersistence) { behaviorPersistence.Save(zdo); } } } private void RegisterBehaviors() { VillagerDef villagerDef = VillagerRegistry.Get(VillagerType); List list = new List(); if (villagerDef?.behaviors != null) { list.AddRange(villagerDef.behaviors); } if (villagerDef?.tags != null) { list.AddRange(TagParser.GetValues(villagerDef.tags, "behavior")); } m_behaviors = BehaviorFactory.CreateBehaviors(this, list); bool flag = false; bool flag2 = false; foreach (IBehavior behavior3 in m_behaviors) { if (behavior3 is CombatBehavior) { flag = true; } if (behavior3 is FleeBehavior) { flag2 = true; } } if (!flag && !flag2) { m_behaviors.Add(new FleeBehavior(this)); m_behaviors.Sort((IBehavior a, IBehavior b) => b.Priority.CompareTo(a.Priority)); } CraftingBehaviorAdapter behavior = GetBehavior(); FarmBehaviorAdapter behavior2 = GetBehavior(); if (behavior != null) { behavior2?.LinkToCraftingAdapter(behavior); } } private static bool NeedsMovement(BehaviorState state) { return state switch { BehaviorState.Traveling => true, BehaviorState.Exploring => true, BehaviorState.Wandering => true, BehaviorState.Patrolling => true, BehaviorState.Working => true, BehaviorState.Alarmed => true, _ => false, }; } public T GetBehavior() where T : class, IBehavior { foreach (IBehavior behavior in m_behaviors) { if (behavior is T result) { return result; } } return null; } public IBehavior GetBehavior(string matchBehaviorTag) { foreach (IBehavior behavior in m_behaviors) { if (behavior.Tag == matchBehaviorTag) { return behavior; } } return null; } public VillagerMemory GetMemory() { return Memory; } public IWorkScanBehavior GetWorkScanner() { return GetBehavior(); } public void ClearWaypoint() { m_currentWaypoint = null; ((BaseAI)this).StopMoving(); } public void SetState(BehaviorState newState, Vector3? target = null) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) VillagerWaypoint waypoint = (target.HasValue ? VillagerWaypoint.WithDefault(target.Value) : null); SetState(newState, waypoint); } public void SetState(BehaviorState newState, VillagerWaypoint waypoint) { //IL_0026: 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_002b: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) BehaviorState currentState = CurrentState; CurrentState = newState; if (waypoint != null) { Vector3 prevTarget = ((m_currentWaypoint != null) ? m_currentWaypoint.Position : Vector3.zero); m_currentWaypoint = waypoint; IsCasualTravel = false; EventRing.RecordTargetSet(waypoint.Position, prevTarget, $"SetState({newState})"); } if (currentState != newState) { EventRing.RecordStateChange(currentState.ToString(), newState.ToString(), (waypoint != null) ? "with_waypoint" : "no_waypoint"); } if (newState == BehaviorState.Idle || newState == BehaviorState.NeedsHelp) { ((BaseAI)this).StopMoving(); } if (waypoint != null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)$"[AI:{m_villagerName}] State -> {newState}, target=({waypoint.Position.x:F1},{waypoint.Position.y:F1},{waypoint.Position.z:F1})"); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)$"[AI:{m_villagerName}] State -> {newState}"); } } } public void SetPaused(bool paused) { IsPaused = paused; if (paused) { ((BaseAI)this).StopMoving(); } } public void RequestFastReselect(float seconds) { m_nextReselectOverride = Mathf.Max(0f, seconds); } public VillagerWaypoint GetCurrentWaypoint() { return m_currentWaypoint; } public bool NavTo(Vector3 target, BehaviorState state, string label, bool snapToApproach = true, Func hullPredicate = null, bool directOrder = false, bool resetPath = true) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00b2: 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) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Vector3 approach = target; if (snapToApproach && !VillagerMovement.TryResolveApproach(target, ((Component)this).transform.position, hullPredicate, out approach)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[AI:" + m_villagerName + "] NavTo('" + label + "') found no reachable approach to " + $"({target.x:F1},{target.y:F1},{target.z:F1}); not moving.")); } return false; } NavMeshHit val = default(NavMeshHit); if (VillagerAgentType.IsRegistered && NavMesh.SamplePosition(approach, ref val, 2f, AgentFilter())) { approach = ((NavMeshHit)(ref val)).position; } SetState(state, new VillagerWaypoint(approach, "default", label)); if (resetPath && (Object)(object)m_navAgent != (Object)null && m_navAgent.isOnNavMesh) { m_navAgent.ResetPath(); } m_directOrderActive = directOrder; return true; } private void EnsureAgent() { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_navAgent != (Object)null) && VillagerAgentType.IsRegistered) { m_navAgent = ((Component)this).gameObject.GetComponent() ?? ((Component)this).gameObject.AddComponent(); m_navAgent.agentTypeID = VillagerAgentType.UnityAgentTypeID; m_navAgent.updatePosition = false; m_navAgent.updateRotation = false; m_navAgent.updateUpAxis = false; m_navAgent.baseOffset = 0f; m_navAgent.autoBraking = true; m_navAgent.autoRepath = true; m_navAgent.autoTraverseOffMeshLink = false; m_navAgent.speed = 5f; m_navAgent.acceleration = 12f; m_navAgent.angularSpeed = 1080f; m_navAgent.stoppingDistance = 0.3f; m_navAgent.obstacleAvoidanceType = (ObstacleAvoidanceType)3; m_navAgent.avoidancePriority = 20 + Mathf.Abs(UniqueId?.GetHashCode() ?? 0) % 61; NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(((Component)this).transform.position, ref val, 3f, AgentFilter())) { m_navAgent.Warp(((NavMeshHit)(ref val)).position); } } } private static NavMeshQueryFilter AgentFilter() { //IL_0002: 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) NavMeshQueryFilter result = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref result)).agentTypeID = VillagerAgentType.UnityAgentTypeID; ((NavMeshQueryFilter)(ref result)).areaMask = -1; return result; } private bool AgentHasArrived(Vector3 targetPos, float lookahead = 0f) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_navAgent == (Object)null || !m_navAgent.isOnNavMesh) { return false; } if (m_navAgent.pathPending || !m_navAgent.hasPath) { return false; } Vector3 val = m_navAgent.destination - targetPos; if (((Vector3)(ref val)).sqrMagnitude > 0.25f) { return false; } if ((int)m_navAgent.pathStatus != 0) { return false; } return m_navAgent.remainingDistance <= m_navAgent.stoppingDistance + 0.25f + lookahead; } private bool TryOffMeshRescue(float dt) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) if (!VillagerAgentType.IsRegistered) { return false; } bool flag = Time.time >= m_nextRescueCheck; if (m_rescuing) { if (flag) { m_nextRescueCheck = Time.time + 1f; if (!IsStranded()) { m_rescuing = false; m_strandedSince = 0f; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[AI:" + m_villagerName + "] Rescue complete — back on the village graph.")); } if (CurrentState == BehaviorState.NeedsHelp) { SetState(BehaviorState.Idle); } ClearCachedPath(); return false; } } Vector3 val = ((Component)this).transform.position - m_rescueLastPos; if (((Vector3)(ref val)).sqrMagnitude > 0.25f) { m_rescueLastPos = ((Component)this).transform.position; m_rescueProgressTime = Time.time; } else if (Time.time - m_rescueProgressTime > 3f) { TeleportHome(); m_rescueLastPos = ((Component)this).transform.position; m_rescueProgressTime = Time.time; return true; } } else { if (!flag) { return false; } m_nextRescueCheck = Time.time + 1f; if (!IsStranded()) { m_strandedSince = 0f; return false; } if (m_strandedSince <= 0f) { m_strandedSince = Time.time; } if (Time.time - m_strandedSince < 2f) { return false; } m_rescuing = true; m_rescueLastPos = ((Component)this).transform.position; m_rescueProgressTime = Time.time; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[AI:" + m_villagerName + "] Stranded off the village graph at " + $"({((Component)this).transform.position.x:F1},{((Component)this).transform.position.z:F1}); recovering to anchor " + $"({m_homeAnchor.x:F1},{m_homeAnchor.z:F1}).")); } } ((BaseAI)this).MoveTo(dt, m_homeAnchor, 1f, true); return true; } private void TeleportHome() { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) Vector3 val = m_homeAnchor; NavMeshHit val2 = default(NavMeshHit); if (NavMesh.SamplePosition(m_homeAnchor, ref val2, 5f, AgentFilter())) { val = ((NavMeshHit)(ref val2)).position; } ((Component)this).transform.position = val; if ((Object)(object)m_navAgent != (Object)null && m_navAgent.isOnNavMesh) { m_navAgent.Warp(val); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[AI:" + m_villagerName + "] Rescue: pathing couldn't free it; teleported home to " + $"({val.x:F1},{val.y:F1},{val.z:F1}).")); } } private bool IsStranded() { //IL_0001: 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_0030: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Invalid comparison between Unknown and I4 RegionGraph regionGraph = VillageRegistry.GraphAt(m_homeAnchor); if (regionGraph != null && regionGraph.PointToRegionId(((Component)this).transform.position) != null) { return false; } NavMeshQueryFilter val = AgentFilter(); NavMeshHit val2 = default(NavMeshHit); if (!NavMesh.SamplePosition(((Component)this).transform.position, ref val2, 3f, val)) { return true; } NavMeshHit val3 = default(NavMeshHit); if (!NavMesh.SamplePosition(m_homeAnchor, ref val3, 5f, val)) { return false; } NavMeshPath val4 = new NavMeshPath(); NavMesh.CalculatePath(((NavMeshHit)(ref val2)).position, ((NavMeshHit)(ref val3)).position, val, val4); return (int)val4.status > 0; } private void UpdateAgentMovement(Vector3 targetPos, bool running) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0098: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Invalid comparison between Unknown and I4 //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0143: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) EnsureAgent(); if ((Object)(object)m_navAgent == (Object)null) { ((BaseAI)this).StopMoving(); return; } if (m_navAgent.isOnNavMesh) { m_navAgent.nextPosition = ((Component)this).transform.position; if ((Object)(object)base.m_character != (Object)null) { Vector3 velocity = base.m_character.GetVelocity(); velocity.y = 0f; m_navAgent.velocity = velocity; } } else { NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(((Component)this).transform.position, ref val, 3f, AgentFilter())) { ((BaseAI)this).StopMoving(); return; } m_navAgent.Warp(((NavMeshHit)(ref val)).position); } if (m_navAgent.hasPath) { Vector3 val2 = m_lastAgentDest - targetPos; if (!(((Vector3)(ref val2)).sqrMagnitude > 0.25f)) { goto IL_00e8; } } m_navAgent.SetDestination(targetPos); m_lastAgentDest = targetPos; goto IL_00e8; IL_00e8: if (m_navAgent.pathPending && (CurrentState != BehaviorState.Patrolling || !m_navAgent.hasPath)) { ((BaseAI)this).StopMoving(); return; } if ((int)m_navAgent.pathStatus == 2) { ((BaseAI)this).StopMoving(); return; } Vector3 moveDirection; if (m_navAgent.isOnOffMeshLink) { OffMeshLinkData currentOffMeshLinkData = m_navAgent.currentOffMeshLinkData; moveDirection = ((OffMeshLinkData)(ref currentOffMeshLinkData)).endPos - ((Component)this).transform.position; if (((Vector3)(ref moveDirection)).sqrMagnitude < 0.09f) { m_navAgent.CompleteOffMeshLink(); } } else { moveDirection = m_navAgent.desiredVelocity; } moveDirection.y = 0f; if (((Vector3)(ref moveDirection)).sqrMagnitude < 0.0001f) { ((BaseAI)this).StopMoving(); return; } if ((Object)(object)DoorHandler != (Object)null) { Door blockingDoor = DoorHandler.GetBlockingDoor(moveDirection); if ((Object)(object)blockingDoor != (Object)null) { DoorHandler.OpenDoor(blockingDoor); } } ((BaseAI)this).MoveTowards(((Vector3)(ref moveDirection)).normalized, running); } public void ClearCachedPath() { if ((Object)(object)m_navAgent != (Object)null && m_navAgent.isOnNavMesh) { m_navAgent.ResetPath(); } } private void OnArrivedAtTarget(float dt) { m_directOrderActive = false; BehaviorContext ctx = default(BehaviorContext); foreach (IBehavior behavior in m_behaviors) { if (behavior.WantsControl(ctx)) { behavior.OnArrival(dt); break; } } } [DevCommand("List active villagers with AI state, target, path status, and resolved region", Name = "vv_get_villagers")] public static void DumpVillagers() { Dictionary activeVillagers = VillagerAIManager.ActiveVillagers; StringBuilder stringBuilder = new StringBuilder(); string arg = (VillageNavLock.IsHeld ? $" [nav hold {VillageNavLock.SecondsRemaining:F1}s — rebuild settle]" : ""); stringBuilder.AppendLine($"[vv_get_villagers] {activeVillagers.Count} active villager(s):{arg}"); foreach (KeyValuePair item in activeVillagers) { if ((Object)(object)item.Value == (Object)null) { stringBuilder.AppendLine("- id=" + item.Key); } else { item.Value.AppendDebug(stringBuilder); } } Console instance = Console.instance; if (instance != null) { instance.Print(stringBuilder.ToString()); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } } [DevCommand("Reset patrol discovery for all patrollers, forcing a fresh route rebuild from the region graph", Name = "vv_patrol_reset")] public static void ResetPatrols() { int num = 0; foreach (KeyValuePair activeVillager in VillagerAIManager.ActiveVillagers) { PerimeterPatrolBehavior perimeterPatrolBehavior = activeVillager.Value?.GetBehavior(); if (perimeterPatrolBehavior != null) { perimeterPatrolBehavior.ResetDiscovery(); num++; } } string text = $"[vv_patrol_reset] Reset discovery for {num} patroller(s)"; Console instance = Console.instance; if (instance != null) { instance.Print(text); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } } [DevCommand("List work orders in chests near each villager + how many outputs exist in chests (the real completion metric)", Name = "vv_workorders")] public static void DumpWorkOrders() { //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_003a: 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_0086: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair activeVillager in VillagerAIManager.ActiveVillagers) { VillagerAI value = activeVillager.Value; if ((Object)(object)value == (Object)null) { continue; } Vector3 homeAnchor = value.m_homeAnchor; List list = ContainerScanner.FindNearbyContainers(homeAnchor, 20f); List list2 = ContainerScanner.FindAllWorkOrders(list, value.VillagerType); stringBuilder.AppendLine($"- {value.NpcName} [{value.VillagerType}] anchor=({homeAnchor.x:F0},{homeAnchor.z:F0}) " + $"containers={list.Count} orders={list2.Count}"); foreach (WorkOrderMatch item in list2) { int num = ContainerScanner.CountAcrossContainers(list, item.ItemPrefabName); stringBuilder.AppendLine($" order: {item.ItemPrefabName} x[{item.MinQuantity}-{item.MaxQuantity}] " + $"station={item.StationName} inChests={num}"); } } Console instance = Console.instance; if (instance != null) { instance.Print(stringBuilder.ToString()); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } } private void AppendDebug(StringBuilder sb) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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) //IL_00ab: 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) //IL_0023: 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_0170: 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_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)((Component)this).transform != (Object)null) ? ((Component)this).transform.position : Vector3.zero); string text = null; try { text = VillageRegistry.GraphAt(val)?.PointToRegionId(val); } catch { } sb.AppendLine("- " + NpcName + " [" + VillagerType + "] id=" + UniqueId); sb.AppendLine($" pos=({val.x:F1},{val.y:F1},{val.z:F1}) state={CurrentState} " + $"paused={IsPaused} lingering={IsLingering} casual={IsCasualTravel}"); sb.AppendLine(" region@pos=" + (text ?? "UNRESOLVED") + " " + $"anchor=({m_homeAnchor.x:F1},{m_homeAnchor.y:F1},{m_homeAnchor.z:F1})"); if (m_currentWaypoint != null) { Vector3 position = m_currentWaypoint.Position; string text2 = (string.IsNullOrEmpty(m_currentWaypoint.Label) ? "" : (" \"" + m_currentWaypoint.Label + "\"")); sb.AppendLine($" target=({position.x:F1},{position.y:F1},{position.z:F1}) dist={Vector3.Distance(val, position):F1}m{text2}"); } else { sb.AppendLine(" target="); } if ((Object)(object)base.m_character == (Object)null) { sb.AppendLine(" char: m_character=NULL (anomalous — no movement data)"); } else { Vector3 moveDir = base.m_character.GetMoveDir(); Vector3 velocity = base.m_character.GetVelocity(); object arg = moveDir.x; object arg2 = moveDir.z; Vector3 val2 = new Vector3(moveDir.x, 0f, moveDir.z); string text3 = $" char: moveDir=({arg:F2},{arg2:F2}) |{((Vector3)(ref val2)).magnitude:F2}| "; val2 = new Vector3(velocity.x, 0f, velocity.z); sb.AppendLine(text3 + $"vel={((Vector3)(ref val2)).magnitude:F2} " + $"needsMove={NeedsMovement(CurrentState)} hasWaypoint={m_currentWaypoint != null}"); } AppendAgentPathState(sb); if (m_behaviors == null || m_behaviors.Count <= 0) { return; } sb.Append(" behaviors: "); for (int i = 0; i < m_behaviors.Count; i++) { if (i > 0) { sb.Append(", "); } sb.Append(m_behaviors[i]?.Tag ?? "?"); } sb.AppendLine(); foreach (IBehavior behavior in m_behaviors) { string text4 = behavior?.GetStatusText(); if (!string.IsNullOrEmpty(text4)) { sb.AppendLine(" status[" + behavior.Tag + "]: " + text4); } if (behavior is CraftingBehaviorAdapter { Crafting: not null } craftingBehaviorAdapter) { sb.AppendLine(" note[" + behavior.Tag + "]: " + craftingBehaviorAdapter.Crafting.LastWorkNote); } if (behavior is PerimeterPatrolBehavior { HelpWaypointIndex: >=0, HelpPosition: var helpPosition } perimeterPatrolBehavior) { sb.AppendLine($" patrol-help: W{perimeterPatrolBehavior.HelpWaypointIndex} @ " + $"({helpPosition.x:F1},{helpPosition.y:F1},{helpPosition.z:F1})"); } } } private void AppendAgentPathState(StringBuilder sb) { //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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_navAgent == (Object)null) { sb.AppendLine(" agent: "); return; } if (!m_navAgent.isOnNavMesh) { sb.AppendLine(" agent: OFF-MESH — agent position not on the slot-31 navmesh; cannot path"); return; } bool pathPending = m_navAgent.pathPending; float remainingDistance = m_navAgent.remainingDistance; string arg = (pathPending ? "pending" : (float.IsInfinity(remainingDistance) ? "∞" : $"{remainingDistance:F1}m")); Vector3 desiredVelocity = m_navAgent.desiredVelocity; float magnitude = ((Vector3)(ref desiredVelocity)).magnitude; Vector3 destination = m_navAgent.destination; sb.AppendLine($" agent: status={m_navAgent.pathStatus} hasPath={m_navAgent.hasPath} " + $"pending={pathPending} onLink={m_navAgent.isOnOffMeshLink} " + $"corners={m_navAgent.path.corners.Length}"); sb.AppendLine($" agent: remaining={arg} stop={m_navAgent.stoppingDistance:F1}m " + $"desiredVel={magnitude:F2} dest=({destination.x:F1},{destination.y:F1},{destination.z:F1})"); if (m_navAgent.hasPath && !pathPending && magnitude < 0.01f && !float.IsInfinity(remainingDistance) && remainingDistance > m_navAgent.stoppingDistance + 0.25f) { sb.AppendLine(" agent: ⚠ STALLED — has path, off target, zero desired velocity"); } if (!pathPending && (int)m_navAgent.pathStatus != 0) { sb.AppendLine($" agent: ⚠ path {m_navAgent.pathStatus} — target not fully reachable on the agent navmesh"); } } public bool TryGetAgentPath(out Vector3[] corners, out NavMeshPathStatus status) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected I4, but got Unknown if ((Object)(object)m_navAgent != (Object)null && m_navAgent.isOnNavMesh && m_navAgent.hasPath) { corners = m_navAgent.path.corners; status = (NavMeshPathStatus)(int)m_navAgent.pathStatus; return true; } corners = Array.Empty(); status = (NavMeshPathStatus)2; return false; } } public static class VillagerAIManager { public static readonly Dictionary ActiveVillagers = new Dictionary(); public static void RegisterActive(VillagerAI ai) { if (!((Object)(object)ai == (Object)null) && !string.IsNullOrEmpty(ai.UniqueId)) { ActiveVillagers[ai.UniqueId] = ai; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[VillagerAIManager] Registered villager " + ai.UniqueId + " (active)")); } } } public static void Unregister(string uniqueId) { ActiveVillagers.Remove(uniqueId); } public static void Unregister(VillagerAI ai) { if ((Object)(object)ai != (Object)null) { Unregister(ai.UniqueId); } } public static List GetAllAnchorPositions() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) List list = new List(); ZDOMan instance = ZDOMan.instance; if (instance == null) { return list; } Dictionary value = Traverse.Create((object)instance).Field>("m_objectsByID").Value; if (value == null) { return list; } foreach (ZDO value2 in value.Values) { if (value2 == null || (string.IsNullOrEmpty(value2.GetString("vv_record_id", "")) && string.IsNullOrEmpty(value2.GetString("vv_villager_type", "")))) { continue; } Vector3 vec = value2.GetVec3("vv_home_position", Vector3.zero); if (vec == Vector3.zero) { continue; } bool flag = false; foreach (Vector3 item in list) { Vector3 val = item - vec; if (((Vector3)(ref val)).sqrMagnitude < 1f) { flag = true; break; } } if (!flag) { list.Add(vec); } } return list; } public static int InvalidatePathsAfterRebake() { int num = 0; foreach (VillagerAI value in ActiveVillagers.Values) { if (!((Object)(object)value == (Object)null)) { value.ClearCachedPath(); num++; } } return num; } public static int ResetPatrolRoutesAfterRepartition() { int num = 0; foreach (VillagerAI value in ActiveVillagers.Values) { PerimeterPatrolBehavior perimeterPatrolBehavior = value?.GetBehavior(); if (perimeterPatrolBehavior != null) { perimeterPatrolBehavior.ResetDiscovery(); num++; } } return num; } [RegisterCleanup] public static void Clear() { ActiveVillagers.Clear(); } } } namespace ValheimVillages.Villager.AI.Work { public static class ContainerScanner { public static List FindNearbyContainers(Vector3 center, float radius) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (Container item in PhysicsHelper.GetAllInRadius(center, radius)) { if (!((Object)(object)item == (Object)null) && !list.Contains(item)) { ZNetView component = ((Component)item).GetComponent(); if (!((Object)(object)component == (Object)null) && component.GetZDO() != null) { list.Add(item); } } } return list; } public static List FindAllWorkOrders(List containers, string villagerType) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (Container container in containers) { Inventory inventory = container.GetInventory(); if (inventory == null) { continue; } List allItems = inventory.GetAllItems(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[ContainerScan] Checking container '" + container.m_name + "' " + $"at {((Component)container).transform.position} with {allItems.Count} items")); } foreach (ItemData item in allItems) { if (item?.m_customData == null) { continue; } GameObject dropPrefab = item.m_dropPrefab; string text = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "null"; if (!IsWorkOrderItem(item)) { continue; } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("[ContainerScan] Found work order item: " + text + ", customData keys=[" + string.Join(",", item.m_customData.Keys) + "]")); } if (!item.m_customData.TryGetValue("wo_station", out var value)) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogDebug((object)"[ContainerScan] Work order missing wo_station"); } continue; } if (!StationMatcher.CanWorkStation(villagerType, value)) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogDebug((object)("[ContainerScan] Station '" + value + "' not compatible with villager type " + villagerType)); } continue; } if (!item.m_customData.TryGetValue("wo_item", out var value2)) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogDebug((object)"[ContainerScan] Work order missing wo_item field (was this created before the update?)"); } continue; } if (string.IsNullOrEmpty(value2)) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogDebug((object)"[ContainerScan] Work order has empty wo_item"); } continue; } int result = 1; int result2 = 10; if (item.m_customData.TryGetValue("wo_min", out var value3)) { int.TryParse(value3, out result); } if (item.m_customData.TryGetValue("wo_max", out var value4)) { int.TryParse(value4, out result2); } ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogDebug((object)("[ContainerScan] Work order matched! " + $"item={value2}, station={value}, qty={result}-{result2}")); } list.Add(new WorkOrderMatch { SourceContainer = container, ItemData = item, ItemPrefabName = value2, StationName = value, MinQuantity = result, MaxQuantity = result2 }); } } return list; } public static List FindIngredients(List containers, Recipe recipe) { if (recipe?.m_resources == null) { return null; } List list = new List(); Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if ((Object)(object)val.m_resItem == (Object)null) { continue; } string name = ((Object)((Component)val.m_resItem).gameObject).name; int amount = val.m_amount; int num = 0; Container container = null; ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)($"[IngredientScan] Looking for {amount}x '{name}' " + $"across {containers.Count} containers")); } foreach (Container container2 in containers) { Inventory inventory = container2.GetInventory(); if (inventory == null) { continue; } int num2 = CountByPrefab(inventory, name); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("[IngredientScan] Container '" + container2.m_name + "': " + $"{num2}x '{name}'")); } if (num2 > 0) { container = container2; num += num2; if (num >= amount) { break; } } } if (num < amount) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogDebug((object)($"[IngredientScan] MISSING: need {amount}x '{name}', " + $"found {num}")); } return null; } list.Add(new IngredientSource { PrefabName = name, Amount = amount, Container = container }); } return list; } public static bool RemoveIngredients(List sources) { foreach (IngredientSource source in sources) { Container container = source.Container; Inventory val = ((container != null) ? container.GetInventory() : null); if (val == null) { return false; } RemoveByPrefab(val, source.PrefabName, source.Amount); } return true; } public static bool CanAcceptItem(Container container, string prefabName, int amount) { if ((Object)(object)container == (Object)null) { return false; } ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(prefabName) : null); if ((Object)(object)val == (Object)null) { return false; } Inventory inventory = container.GetInventory(); if (inventory != null) { return inventory.CanAddItem(val, amount); } return false; } public static bool TryDepositItem(Container container, string prefabName, int amount) { if (!CanAcceptItem(container, prefabName, amount)) { return false; } ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(prefabName) : null); if ((Object)(object)val == (Object)null) { return false; } Inventory inventory = container.GetInventory(); ItemDrop component = val.GetComponent(); if (inventory == null || (Object)(object)component == (Object)null) { return false; } ItemData val2 = component.m_itemData.Clone(); val2.m_stack = amount; val2.m_dropPrefab = val; return inventory.AddItem(val2); } public static bool CanAcceptItemData(Container container, ItemData item) { Inventory val = ((container != null) ? container.GetInventory() : null); if (val != null && item != null) { return val.CanAddItem(item, item.m_stack); } return false; } public static bool TryDepositItemData(Container container, ItemData item) { if (!CanAcceptItemData(container, item)) { return false; } return container.GetInventory().AddItem(item); } private static bool IsWorkOrderItem(ItemData item) { object obj; if (item == null) { obj = null; } else { GameObject dropPrefab = item.m_dropPrefab; obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null); } string text = (string)obj; if (string.IsNullOrEmpty(text)) { return false; } ItemDefinition definition = ItemFactory.GetDefinition(text); if (definition != null) { return definition.itemType == "workorder"; } return false; } public static int CountByPrefab(Inventory inv, string prefabName) { int num = 0; foreach (ItemData allItem in inv.GetAllItems()) { if ((Object)(object)allItem?.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == prefabName) { num += allItem.m_stack; } } return num; } public static int CountAcrossContainers(List containers, string prefabName) { int num = 0; foreach (Container container in containers) { Inventory val = ((container != null) ? container.GetInventory() : null); if (val != null) { num += CountByPrefab(val, prefabName); } } return num; } private static void RemoveByPrefab(Inventory inv, string prefabName, int amount) { int num = amount; List allItems = inv.GetAllItems(); int num2 = allItems.Count - 1; while (num2 >= 0 && num > 0) { ItemData val = allItems[num2]; if (!((Object)(object)val?.m_dropPrefab == (Object)null) && !(((Object)val.m_dropPrefab).name != prefabName)) { int num3 = Mathf.Min(val.m_stack, num); inv.RemoveItem(val, num3); num -= num3; } num2--; } } } public static class StationFinder { private const float StationLookupRadius = 2f; private static readonly MethodInfo s_isFireLit = typeof(CookingStation).GetMethod("IsFireLit", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo s_getFuel = typeof(CookingStation).GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo s_smelterGetFuel = typeof(Smelter).GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic); private static bool InvokeIsFireLit(CookingStation station) { if ((Object)(object)station == (Object)null || s_isFireLit == null) { return false; } try { return (bool)s_isFireLit.Invoke(station, null); } catch { return false; } } public static bool IsCookingStationFireLit(CookingStation station) { if ((Object)(object)station == (Object)null) { return false; } if (!station.m_requireFire) { return true; } return InvokeIsFireLit(station); } public static bool IsCookingStationReady(CookingStation station) { if ((Object)(object)station == (Object)null) { return false; } if (station.m_requireFire && InvokeIsFireLit(station)) { return true; } if (station.m_useFuel && GetCookingStationFuel(station) > 0f) { return true; } return false; } public static Smelter GetSmelterPrefab(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } ZNetScene instance = ZNetScene.instance; if (instance?.m_prefabs == null) { return null; } for (int i = 0; i < instance.m_prefabs.Count; i++) { GameObject val = instance.m_prefabs[i]; if (!((Object)(object)val == (Object)null) && !(((Object)val).name != prefabName)) { return val.GetComponent(); } } return null; } public static bool IsSmelterReady(Smelter station) { if ((Object)(object)station == (Object)null) { return false; } if ((Object)(object)station.m_fuelItem == (Object)null) { return true; } return GetSmelterFuel(station) > 0f; } public static float GetSmelterFuel(Smelter station) { if ((Object)(object)station == (Object)null || s_smelterGetFuel == null) { return 0f; } try { return (float)s_smelterGetFuel.Invoke(station, null); } catch { return 0f; } } public static float GetCookingStationFuel(CookingStation station) { if ((Object)(object)station == (Object)null || s_getFuel == null) { return 0f; } try { return (float)s_getFuel.Invoke(station, null); } catch { return 0f; } } public static bool HasFreeSlot(CookingStation station) { if ((Object)(object)station == (Object)null) { return false; } ZNetView component = ((Component)station).GetComponent(); if ((Object)(object)component == (Object)null || component.GetZDO() == null) { return false; } int num = ((station.m_slots != null) ? station.m_slots.Length : 0); ZDO zDO = component.GetZDO(); for (int i = 0; i < num; i++) { if (string.IsNullOrEmpty(zDO.GetString("slot" + i, ""))) { return true; } } return false; } } public struct FuelNeed { public Vector3 FuelTargetPosition; public string FuelItemPrefab; public Fireplace FireplaceRef; public CookingStation CookingStationRef; public Smelter SmelterRef; public bool NeedsFireUnderneath; public bool NeedsInternalFuel; } public static class StationFuelHelper { private const float FireplaceSearchRadius = 3f; public static bool DiagnoseFuelNeed(CookingStation station, out FuelNeed need) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_0079: Unknown result type (might be due to invalid IL or missing references) need = default(FuelNeed); if ((Object)(object)station == (Object)null) { return false; } bool flag = station.m_requireFire && !StationFinder.IsCookingStationFireLit(station); bool flag2 = station.m_useFuel && StationFinder.GetCookingStationFuel(station) <= 0f; if (!flag && !flag2) { return false; } need.CookingStationRef = station; if (flag && TryFindFireplaceNear(station, out var fireplace)) { need.NeedsFireUnderneath = true; need.FireplaceRef = fireplace; need.FuelTargetPosition = ((Component)fireplace).transform.position; ItemDrop fuelItem = fireplace.m_fuelItem; object fuelItemPrefab; if (fuelItem == null) { fuelItemPrefab = null; } else { GameObject gameObject = ((Component)fuelItem).gameObject; fuelItemPrefab = ((gameObject != null) ? ((Object)gameObject).name : null); } need.FuelItemPrefab = (string)fuelItemPrefab; } else { if (!flag2) { return false; } need.NeedsInternalFuel = true; need.FuelTargetPosition = ((Component)station).transform.position; ItemDrop fuelItem2 = station.m_fuelItem; object fuelItemPrefab2; if (fuelItem2 == null) { fuelItemPrefab2 = null; } else { GameObject gameObject2 = ((Component)fuelItem2).gameObject; fuelItemPrefab2 = ((gameObject2 != null) ? ((Object)gameObject2).name : null); } need.FuelItemPrefab = (string)fuelItemPrefab2; } return !string.IsNullOrEmpty(need.FuelItemPrefab); } public static bool DiagnoseFuelNeed(Smelter station, out FuelNeed need) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) need = default(FuelNeed); if ((Object)(object)station == (Object)null) { return false; } if ((Object)(object)station.m_fuelItem == (Object)null) { return false; } if (StationFinder.GetSmelterFuel(station) > 0f) { return false; } need.SmelterRef = station; need.NeedsInternalFuel = true; need.FuelTargetPosition = ((Component)station).transform.position; GameObject gameObject = ((Component)station.m_fuelItem).gameObject; need.FuelItemPrefab = ((gameObject != null) ? ((Object)gameObject).name : null); return !string.IsNullOrEmpty(need.FuelItemPrefab); } public static bool TryFindFireplaceNear(CookingStation station, out Fireplace fireplace) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) fireplace = null; if ((Object)(object)station == (Object)null) { return false; } List list = new List(); if (station.m_fireCheckPoints != null) { Transform[] fireCheckPoints = station.m_fireCheckPoints; foreach (Transform val in fireCheckPoints) { if ((Object)(object)val != (Object)null) { list.Add(val.position); } } } if (list.Count == 0) { list.Add(((Component)station).transform.position); } foreach (Vector3 item in list) { foreach (Fireplace item2 in PhysicsHelper.GetAllInRadius(item, 3f)) { if (!((Object)(object)item2 == (Object)null) && !item2.m_infiniteFuel) { fireplace = item2; return true; } } } return false; } public static bool FindFuelInContainers(List containers, string fuelPrefabName, out Container fuelContainer) { fuelContainer = null; if (containers == null || string.IsNullOrEmpty(fuelPrefabName)) { return false; } foreach (Container container in containers) { Inventory val = ((container != null) ? container.GetInventory() : null); if (val != null && ContainerScanner.CountByPrefab(val, fuelPrefabName) > 0) { fuelContainer = container; return true; } } return false; } } public static class StationMatcher { public static string[] GetStationNames(string villagerType) { VillagerDef villagerDef = VillagerRegistry.Get(villagerType); if (villagerDef?.workStations == null || villagerDef.workStations.Count <= 0) { return Array.Empty(); } return villagerDef.workStations.ToArray(); } public static bool CanWorkStation(string villagerType, string stationName) { VillagerDef villagerDef = VillagerRegistry.Get(villagerType); if (villagerDef?.workStations != null) { return villagerDef.workStations.Contains(stationName); } return false; } public static Recipe FindRecipe(string itemPrefabName, string stationName) { if ((Object)(object)ObjectDB.instance == (Object)null) { return null; } return ((IEnumerable)ObjectDB.instance.m_recipes).FirstOrDefault((Func)((Recipe r) => (Object)(object)r.m_item != (Object)null && ((Object)((Component)r.m_item).gameObject).name == itemPrefabName && (Object)(object)r.m_craftingStation != (Object)null && r.m_craftingStation.m_name == stationName && r.m_enabled)); } public static Recipe FindRecipeForNpc(string itemPrefabName, string villagerType) { string[] stationNames = GetStationNames(villagerType); foreach (string stationName in stationNames) { Recipe val = FindRecipe(itemPrefabName, stationName); if ((Object)(object)val != (Object)null) { return val; } } return null; } } } namespace ValheimVillages.Villager.AI.Pathfinding { public class PathDebugRenderer : MonoBehaviour { private const float NodeMarkerSize = 0.15f; private const float LineYOffset = 0.1f; private static PathDebugRenderer s_instance; private static bool s_enabled = false; private static bool s_showTriangulation = false; private static string s_targetCameraName; public static readonly HashSet HighlightedRegions = new HashSet(); public static readonly List DebugPolyline = new List(); private static readonly Color ColorDebugPolyline = Color.magenta; private static readonly Color ColorComplete = Color.green; private static readonly Color ColorPartial = Color.yellow; private static readonly Color ColorNoPath = Color.red; private static readonly Color ColorTarget = new Color(1f, 0.4f, 0f); private Material m_lineMaterial; private void Awake() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown m_lineMaterial = new Material(Shader.Find("Hidden/Internal-Colored")); ((Object)m_lineMaterial).hideFlags = (HideFlags)61; m_lineMaterial.SetInt("_SrcBlend", 5); m_lineMaterial.SetInt("_DstBlend", 10); m_lineMaterial.SetInt("_Cull", 0); m_lineMaterial.SetInt("_ZWrite", 0); m_lineMaterial.SetInt("_ZTest", 8); } private void OnDestroy() { if ((Object)(object)m_lineMaterial != (Object)null) { Object.Destroy((Object)(object)m_lineMaterial); } } private void OnRenderObject() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if ((!s_enabled && !s_showTriangulation && DebugPolyline.Count == 0) || (s_targetCameraName != null && ((Object)(object)Camera.current == (Object)null || ((Object)Camera.current).name != s_targetCameraName))) { return; } m_lineMaterial.SetPass(0); GL.PushMatrix(); GL.MultMatrix(Matrix4x4.identity); if (s_enabled) { foreach (KeyValuePair activeVillager in VillagerAIManager.ActiveVillagers) { VillagerAI value = activeVillager.Value; if (!((Object)(object)value == (Object)null)) { DrawVillagerPath(value); } } } if (s_showTriangulation) { DrawTriangulation(); } if (DebugPolyline.Count > 0) { DrawDebugPolyline(); } GL.PopMatrix(); } private void DrawDebugPolyline() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.up * 0.4f; GL.Begin(1); GL.Color(ColorDebugPolyline); for (int i = 0; i < DebugPolyline.Count - 1; i++) { GL.Vertex(DebugPolyline[i] + val); GL.Vertex(DebugPolyline[i + 1] + val); } GL.End(); for (int j = 0; j < DebugPolyline.Count; j++) { DrawWireOctahedron(DebugPolyline[j] + val, 0.3f, ColorDebugPolyline); } } [DevCommand("Toggle villager path debug viz. Optional cam= restricts the overlay to that camera (cam=off clears).", Name = "vv_path_debug")] public static void Toggle(ConsoleEventArgs args) { if (TryApplyCameraArg(args, out var message)) { Console instance = Console.instance; if (instance != null) { instance.Print(message); } return; } s_enabled = !s_enabled; if (s_enabled) { EnsureInstance(); } else if ((Object)(object)s_instance != (Object)null) { Object.Destroy((Object)(object)((Component)s_instance).gameObject); s_instance = null; } string text = (s_enabled ? "ON" : "OFF"); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print("Path debug rendering " + text + CamSuffix()); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[PathDebug] Visualization " + text)); } } [DevCommand("Overlay the raw slot-31 NavMesh path between two points (magenta). Usage: vv_drawpath | vv_drawpath off", Name = "vv_drawpath")] public static void DrawRawPath(ConsoleEventArgs args) { //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) if (args?.Args != null && args.Args.Length >= 2 && args.Args[1].Equals("off", StringComparison.OrdinalIgnoreCase)) { DebugPolyline.Clear(); Console instance = Console.instance; if (instance != null) { instance.Print("[vv_drawpath] cleared"); } return; } CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (args?.Args == null || args.Args.Length < 5 || !float.TryParse(args.Args[1], NumberStyles.Float, invariantCulture, out var result) || !float.TryParse(args.Args[2], NumberStyles.Float, invariantCulture, out var result2) || !float.TryParse(args.Args[3], NumberStyles.Float, invariantCulture, out var result3) || !float.TryParse(args.Args[4], NumberStyles.Float, invariantCulture, out var result4)) { Console instance2 = Console.instance; if (instance2 != null) { instance2.Print("Usage: vv_drawpath | vv_drawpath off"); } return; } NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = VillagerAgentType.UnityAgentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; NavMeshHit val3 = default(NavMeshHit); NavMeshHit val4 = default(NavMeshHit); if (!NavMesh.SamplePosition(new Vector3(result, 40f, result2), ref val3, 8f, val2) || !NavMesh.SamplePosition(new Vector3(result3, 40f, result4), ref val4, 8f, val2)) { Console instance3 = Console.instance; if (instance3 != null) { instance3.Print("[vv_drawpath] endpoint sample failed"); } return; } NavMeshPath val5 = new NavMeshPath(); NavMesh.CalculatePath(((NavMeshHit)(ref val3)).position, ((NavMeshHit)(ref val4)).position, val2, val5); DebugPolyline.Clear(); DebugPolyline.AddRange(val5.corners); EnsureInstance(); Console instance4 = Console.instance; if (instance4 != null) { instance4.Print($"[vv_drawpath] status={val5.status} corners={val5.corners.Length} (magenta overlay)"); } } [DevCommand("Toggle NavMesh triangulation wireframe. Optional cam= restricts the overlay to that camera (cam=off clears).", Name = "vv_tri_debug")] public static void ToggleTriangulation(ConsoleEventArgs args) { if (TryApplyCameraArg(args, out var message)) { Console instance = Console.instance; if (instance != null) { instance.Print(message); } return; } s_showTriangulation = !s_showTriangulation; if (s_showTriangulation) { EnsureInstance(); } string text = (s_showTriangulation ? "ON" : "OFF"); int num = RegionBuilder.CachedTriangles?.Count ?? 0; Console instance2 = Console.instance; if (instance2 != null) { instance2.Print($"Triangulation wireframe {text} ({num} triangles){CamSuffix()}"); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[PathDebug] Triangulation wireframe " + text)); } } private static string CamSuffix() { if (s_targetCameraName == null) { return ""; } return " [cam=" + s_targetCameraName + "]"; } private static bool TryApplyCameraArg(ConsoleEventArgs args, out string message) { message = null; if (args?.Args == null) { return false; } string[] args2 = args.Args; foreach (string text in args2) { if (!string.IsNullOrEmpty(text) && text.StartsWith("cam=")) { string text2 = text.Substring(4); if (text2.Length == 0 || text2.Equals("off", StringComparison.OrdinalIgnoreCase)) { s_targetCameraName = null; message = "Debug overlay camera filter cleared (renders to all cameras)."; } else { s_targetCameraName = text2; EnsureInstance(); message = "Debug overlay restricted to camera '" + text2 + "'."; } return true; } } return false; } public static void AutoEnable() { if ((s_enabled || s_showTriangulation) && (Object)(object)s_instance == (Object)null) { EnsureInstance(); } } private static void EnsureInstance() { //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_001e: Expected O, but got Unknown if (!((Object)(object)s_instance != (Object)null)) { GameObject val = new GameObject("PathDebugRenderer"); Object.DontDestroyOnLoad((Object)val); s_instance = val.AddComponent(); } } private void DrawVillagerPath(VillagerAI ai) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) //IL_0069: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)ai).transform.position; Vector3 val = Vector3.up * 0.1f; if (!ai.TryGetAgentPath(out var corners, out var status) || corners.Length == 0) { if (ai.CurrentTarget.HasValue) { GL.Begin(1); GL.Color(ColorNoPath); GL.Vertex(position + val); GL.Vertex(ai.CurrentTarget.Value + val); GL.End(); DrawWireOctahedron(ai.CurrentTarget.Value + val, 0.3f, ColorNoPath); } return; } Color val2 = (((int)status == 0) ? ColorComplete : ColorPartial); GL.Begin(1); GL.Color(val2); GL.Vertex(position + val); GL.Vertex(corners[0] + val); for (int i = 0; i < corners.Length - 1; i++) { GL.Vertex(corners[i] + val); GL.Vertex(corners[i + 1] + val); } GL.End(); for (int j = 0; j < corners.Length; j++) { DrawWireOctahedron(corners[j] + val, 0.15f, val2); } if (ai.CurrentTarget.HasValue) { Vector3 value = ai.CurrentTarget.Value; Vector3 val3 = corners[^1]; if (Vector3.Distance(value, val3) > 0.5f) { GL.Begin(1); GL.Color(ColorTarget); GL.Vertex(val3 + val); GL.Vertex(value + val); GL.End(); } DrawWireOctahedron(value + val, 0.3f, ColorTarget); } } private static void DrawWireOctahedron(Vector3 center, float radius, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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_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_0012: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0025: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_004f: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0062: 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_0072: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) Vector3 val = center + Vector3.up * radius; Vector3 val2 = center - Vector3.up * radius; Vector3 val3 = center + Vector3.forward * radius; Vector3 val4 = center - Vector3.forward * radius; Vector3 val5 = center + Vector3.right * radius; Vector3 val6 = center - Vector3.right * radius; GL.Begin(1); GL.Color(color); GL.Vertex(val); GL.Vertex(val3); GL.Vertex(val); GL.Vertex(val4); GL.Vertex(val); GL.Vertex(val5); GL.Vertex(val); GL.Vertex(val6); GL.Vertex(val2); GL.Vertex(val3); GL.Vertex(val2); GL.Vertex(val4); GL.Vertex(val2); GL.Vertex(val5); GL.Vertex(val2); GL.Vertex(val6); GL.Vertex(val3); GL.Vertex(val5); GL.Vertex(val5); GL.Vertex(val4); GL.Vertex(val4); GL.Vertex(val6); GL.Vertex(val6); GL.Vertex(val3); GL.End(); } private void DrawTriangulation() { //IL_0012: 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_003e: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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) //IL_0071: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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_0168: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) List cachedTriangles = RegionBuilder.CachedTriangles; if (cachedTriangles == null || cachedTriangles.Count == 0) { return; } Vector3 val = Vector3.up * 0.1f; GL.Begin(1); foreach (RegionBuilder.CachedTriangle item in cachedTriangles) { GL.Color(RegionColor(item.RegionId)); GL.Vertex(item.V0 + val); GL.Vertex(item.V1 + val); GL.Vertex(item.V1 + val); GL.Vertex(item.V2 + val); GL.Vertex(item.V2 + val); GL.Vertex(item.V0 + val); } GL.End(); if (HighlightedRegions.Count == 0) { return; } Color val2 = new Color(1f, 1f, 1f, 0.95f); GL.Begin(1); GL.Color(val2); for (int i = 0; i < 5; i++) { float num = 0.15f + (float)i * 0.02f; Vector3 val3 = Vector3.up * num; foreach (RegionBuilder.CachedTriangle item2 in cachedTriangles) { if (HighlightedRegions.Contains(item2.RegionId)) { GL.Vertex(item2.V0 + val3); GL.Vertex(item2.V1 + val3); GL.Vertex(item2.V1 + val3); GL.Vertex(item2.V2 + val3); GL.Vertex(item2.V2 + val3); GL.Vertex(item2.V0 + val3); } } } GL.End(); } private static Color RegionColor(string regionId) { //IL_006d: 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_007f: 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) if (string.IsNullOrEmpty(regionId)) { return new Color(1f, 1f, 1f, 0.3f); } int num = regionId.GetHashCode() & 0x7FFFFFFF; float num2 = (float)(num % 360) / 360f; float num3 = 0.6f + (float)(num / 360 % 4) * 0.1f; float num4 = 0.7f + (float)(num / 1440 % 3) * 0.1f; Color result = Color.HSVToRGB(num2, num3, num4); result.a = 0.7f; return result; } [DevCommand("Inspect village region graph (use near=x,z or near=player for position-filtered triangle detail)", Name = "vv_tri_inspect")] public static void TriInspect(ConsoleEventArgs args) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Vector3? val = ParseNearArg(args); if (val.HasValue) { InspectNearPosition(val.Value); } else { InspectVillage(); } } private static Vector3? ParseNearArg(ConsoleEventArgs args) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if (args?.Args == null) { return null; } for (int i = 1; i < args.Args.Length; i++) { string text = args.Args[i]; if (string.IsNullOrEmpty(text) || !text.StartsWith("near=", StringComparison.OrdinalIgnoreCase)) { continue; } string text2 = text.Substring("near=".Length); if (text2.Equals("player", StringComparison.OrdinalIgnoreCase)) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer != (Object)null)) { return null; } return ((Component)localPlayer).transform.position; } string[] array = text2.Split(new char[1] { ',' }); if (array.Length >= 2 && float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return new Vector3(result, 0f, result2); } } return null; } private static void InspectVillage() { //IL_0063: 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) //IL_0071: 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_0089: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; List list = new List(); foreach (RegionGraph item2 in VillageRegistry.AllGraphs()) { num2++; num3 += item2.RegionCount; num4 += item2.LinkCount; List list2 = new List(); foreach (Vector3 allRegionCenter in item2.Diagnostics.GetAllRegionCenters()) { list2.Add($"{allRegionCenter.x:F2},{allRegionCenter.y:F2},{allRegionCenter.z:F2}"); } DebugLog.List("Region", $"village_{num}_centers", list2); item2.GetOrigin(out var originX, out var originZ); string item = $" graph[{num}] regions={item2.RegionCount} " + $"links={item2.LinkCount} origin=({originX:F0},{originZ:F0})"; list.Add(item); num++; } if (num2 == 0) { string text = "[TriInspect] No region graphs available. Run hna_partition (or move a Guard into a village)."; Console instance = Console.instance; if (instance != null) { instance.Print(text); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } return; } DebugLog.Event("TriInspect", "village_summary", ("graphs", num2), ("regions", num3), ("links", num4)); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("[TriInspect] village graphs=").Append(num2).Append(" regions=") .Append(num3) .Append(" links=") .Append(num4) .AppendLine(); foreach (string item3 in list) { stringBuilder.AppendLine(item3); } stringBuilder.AppendLine(" (per-region centroids written to /config/vv_dumps/)"); string text2 = stringBuilder.ToString(); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(text2); } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)text2); } } private static void InspectNearPosition(Vector3 pos) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: 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_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0462: Unknown result type (might be due to invalid IL or missing references) //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_05e6: Unknown result type (might be due to invalid IL or missing references) //IL_0608: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_0634: Unknown result type (might be due to invalid IL or missing references) //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_083f: Unknown result type (might be due to invalid IL or missing references) //IL_0844: Unknown result type (might be due to invalid IL or missing references) //IL_0698: Unknown result type (might be due to invalid IL or missing references) //IL_069f: Unknown result type (might be due to invalid IL or missing references) //IL_06a4: Unknown result type (might be due to invalid IL or missing references) //IL_06ab: Unknown result type (might be due to invalid IL or missing references) //IL_06b0: Unknown result type (might be due to invalid IL or missing references) //IL_06ba: Unknown result type (might be due to invalid IL or missing references) //IL_06bf: Unknown result type (might be due to invalid IL or missing references) //IL_06ca: Unknown result type (might be due to invalid IL or missing references) //IL_06db: Unknown result type (might be due to invalid IL or missing references) //IL_06ec: Unknown result type (might be due to invalid IL or missing references) //IL_0707: Unknown result type (might be due to invalid IL or missing references) //IL_0718: Unknown result type (might be due to invalid IL or missing references) //IL_0729: Unknown result type (might be due to invalid IL or missing references) //IL_0744: Unknown result type (might be due to invalid IL or missing references) //IL_0755: Unknown result type (might be due to invalid IL or missing references) //IL_0766: Unknown result type (might be due to invalid IL or missing references) //IL_077f: Unknown result type (might be due to invalid IL or missing references) //IL_078b: Unknown result type (might be due to invalid IL or missing references) //IL_0797: Unknown result type (might be due to invalid IL or missing references) //IL_0866: Unknown result type (might be due to invalid IL or missing references) //IL_086b: Unknown result type (might be due to invalid IL or missing references) //IL_086d: Unknown result type (might be due to invalid IL or missing references) //IL_086f: Unknown result type (might be due to invalid IL or missing references) List cachedTriangles = RegionBuilder.CachedTriangles; if (cachedTriangles == null || cachedTriangles.Count == 0) { Console instance = Console.instance; if (instance != null) { instance.Print("No cached triangles. Run vv_tri_debug first."); } return; } Dictionary> dictionary = new Dictionary>(); Vector3 val; foreach (RegionBuilder.CachedTriangle item3 in cachedTriangles) { val = (item3.V0 + item3.V1 + item3.V2) / 3f - pos; if (!(((Vector3)(ref val)).sqrMagnitude > 4f)) { string key = (string.IsNullOrEmpty(item3.RegionId) ? "(none)" : item3.RegionId); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List()); } value.Add(item3); } } if (dictionary.Count == 0) { Console instance2 = Console.instance; if (instance2 != null) { instance2.Print($"No triangles within {2f}m of ({pos.x:F1}, {pos.y:F1}, {pos.z:F1})"); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[TriInspect] No triangles within {2f}m of ({pos.x:F1}, {pos.y:F1}, {pos.z:F1})"); } return; } RegionGraph regionGraph = VillageRegistry.GraphAt(pos); NavMeshQueryFilter val2 = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val2)).agentTypeID = VillagerAgentType.ResolveValheimHumanoidAgentTypeID(); ((NavMeshQueryFilter)(ref val2)).areaMask = -1; NavMeshQueryFilter val3 = val2; float num = 0f; bool flag = (Object)(object)ZoneSystem.instance != (Object)null; if (flag) { num = ZoneSystem.instance.GetGroundHeight(new Vector3(pos.x, 0f, pos.z)); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"[TriInspect] Pos=({pos.x:F1}, {pos.y:F1}, {pos.z:F1}) " + $"Terrain={num:F1} Δ={pos.y - num:F1}m above terrain"); stringBuilder.AppendLine($" {dictionary.Count} region(s) within {2f}m sphere:"); Dictionary> dictionary2 = new Dictionary>(); NavMeshHit val5 = default(NavMeshHit); foreach (KeyValuePair> item4 in dictionary) { string key2 = item4.Key; List value2 = item4.Value; float num2 = float.MaxValue; float num3 = float.MinValue; float num4 = 0f; float num5 = 0f; List<(Vector3, int)> list2 = new List<(Vector3, int)>(); int num6 = 0; foreach (RegionBuilder.CachedTriangle item5 in value2) { float[] array = new float[3] { item5.V0.y, item5.V1.y, item5.V2.y }; foreach (float num7 in array) { if (num7 < num2) { num2 = num7; } if (num7 > num3) { num3 = num7; } } float num8 = num4; val = Vector3.Cross(item5.V1 - item5.V0, item5.V2 - item5.V0); num4 = num8 + ((Vector3)(ref val)).magnitude * 0.5f; float num9 = Vector3.Distance(item5.V0, item5.V1); float num10 = Vector3.Distance(item5.V1, item5.V2); float num11 = Vector3.Distance(item5.V2, item5.V0); float num12 = Mathf.Max(num9, Mathf.Max(num10, num11)); if (num12 > num5) { num5 = num12; } list2.Add((item5.V0, num6 * 3)); list2.Add((item5.V1, num6 * 3 + 1)); list2.Add((item5.V2, num6 * 3 + 2)); num6++; } dictionary2[key2] = list2; Vector3 val4 = (value2[0].V0 + value2[0].V1 + value2[0].V2) / 3f; int num13 = Mathf.FloorToInt(val4.x / 3f); int num14 = Mathf.FloorToInt(val4.z / 3f); int num15 = Mathf.FloorToInt(val4.y / 2f); stringBuilder.AppendLine($" --- Region {key2} ({value2.Count} tri) ---"); stringBuilder.AppendLine($" Y range: [{num2:F2}, {num3:F2}] ΔY={num3 - num2:F2}m"); stringBuilder.AppendLine($" Area: {num4:F2}m² MaxEdge: {num5:F2}m"); stringBuilder.AppendLine($" Cell: gx={num13} gz={num14} hb={num15} " + $"(X[{(float)num13 * 3f:F0},{(float)(num13 + 1) * 3f:F0}] " + $"Z[{(float)num14 * 3f:F0},{(float)(num14 + 1) * 3f:F0}])"); if (flag) { float num16 = (num2 + num3) * 0.5f; stringBuilder.AppendLine($" Above terrain: {num16 - num:F2}m"); } bool flag2 = CellValidator.HasGroundBelow(val4); stringBuilder.AppendLine($" GroundBelow: {flag2}"); if (NavMesh.FindClosestEdge(val4, ref val5, val3)) { stringBuilder.AppendLine($" EdgeDist: {((NavMeshHit)(ref val5)).distance:F3}m"); } bool flag3 = CellValidator.IsSurfaceWideEnough(val4, val3); stringBuilder.AppendLine($" SurfaceWide: {flag3}"); if (regionGraph != null) { string text = regionGraph.PointToRegionId(val4); stringBuilder.AppendLine(" GraphLookup: " + (text ?? "(unresolved)")); } foreach (RegionBuilder.CachedTriangle item6 in value2) { Vector3 val6 = (item6.V0 + item6.V1 + item6.V2) / 3f; stringBuilder.AppendLine($" Tri: ({item6.V0.x:F2},{item6.V0.y:F2},{item6.V0.z:F2}) " + $"({item6.V1.x:F2},{item6.V1.y:F2},{item6.V1.z:F2}) " + $"({item6.V2.x:F2},{item6.V2.y:F2},{item6.V2.z:F2}) " + $"cen=({val6.x:F2},{val6.y:F2},{val6.z:F2})"); } } stringBuilder.AppendLine(" --- Edge sharing ---"); List list3 = new List(dictionary2.Keys); bool flag4 = false; for (int j = 0; j < list3.Count; j++) { for (int k = j + 1; k < list3.Count; k++) { int num17 = 0; foreach (var item7 in dictionary2[list3[j]]) { Vector3 item = item7.Item1; foreach (var item8 in dictionary2[list3[k]]) { Vector3 item2 = item8.Item1; if (Vector3.Distance(item, item2) < 0.01f) { num17++; } } } if (num17 >= 2) { stringBuilder.AppendLine($" {list3[j]} <-> {list3[k]}: {num17} shared vertices (CONNECTED)"); flag4 = true; } else if (num17 == 1) { stringBuilder.AppendLine(" " + list3[j] + " <-> " + list3[k] + ": 1 shared vertex (TOUCHING, no shared edge)"); flag4 = true; } } } if (!flag4) { stringBuilder.AppendLine(" No shared edges or vertices between nearby regions"); } string text2 = stringBuilder.ToString(); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)text2); } Console instance3 = Console.instance; if (instance3 != null) { instance3.Print(text2); } } [RegisterCleanup] public static void Cleanup() { if ((Object)(object)s_instance != (Object)null) { Object.Destroy((Object)(object)((Component)s_instance).gameObject); s_instance = null; } } } public static class VillagerAgentType { private const int AgentTypeValue = 31; private static int s_humanoidAgentTypeID = -1; public static AgentType AgentType => (AgentType)31; public static bool IsRegistered { get; private set; } public static int UnityAgentTypeID { get; private set; } public static NavMeshBuildSettings BuildSettings { get; private set; } public static bool TryGetSlope(out float slope) { if (!TryGetEffectiveSettings(out var settings)) { slope = 0f; return false; } slope = ((NavMeshBuildSettings)(ref settings)).agentSlope; return true; } public static bool TryGetClimb(out float climb) { if (!TryGetEffectiveSettings(out var settings)) { climb = 0f; return false; } climb = ((NavMeshBuildSettings)(ref settings)).agentClimb; return true; } public static bool TryGetEffectiveSettings(out NavMeshBuildSettings settings) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) int num = (IsRegistered ? UnityAgentTypeID : ResolveValheimHumanoidAgentTypeID()); if (num == 0) { settings = default(NavMeshBuildSettings); return false; } settings = NavMesh.GetSettingsByID(num); return true; } public static bool EnsureRegistered() { if (IsRegistered) { return true; } Pathfinding instance = Pathfinding.instance; if ((Object)(object)instance == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[VillagerAgentType] Pathfinding.instance is null; deferring registration"); } return false; } try { BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic; FieldInfo field = typeof(Pathfinding).GetField("m_agentSettings", bindingAttr); MethodInfo method = typeof(Pathfinding).GetMethod("AddAgent", bindingAttr); if (field == null || method == null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)"[VillagerAgentType] Could not find m_agentSettings or AddAgent via reflection"); } return false; } if (!(field.GetValue(instance) is IList { Count: >=2 } list)) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)"[VillagerAgentType] m_agentSettings is null or too small"); } return false; } if (list.Count > 31 && list[31] != null) { CaptureAgentSlot(list[31]); IsRegistered = true; ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)($"[VillagerAgentType] Re-captured agent slot {31} " + $"(agentTypeID={UnityAgentTypeID}, settings cloned from Humanoid)")); } return true; } object obj = list[1]; object obj2 = method.Invoke(instance, new object[2] { (object)(AgentType)31, obj }); if (obj2 == null) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogError((object)"[VillagerAgentType] AddAgent returned null"); } return false; } CaptureAgentSlot(obj2); IsRegistered = true; ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogInfo((object)($"[VillagerAgentType] Registered custom agent type {31} " + $"(agentTypeID={UnityAgentTypeID}, settings cloned from Humanoid verbatim)")); } return true; } catch (Exception arg) { ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogError((object)$"[VillagerAgentType] Registration failed: {arg}"); } return false; } } private static void CaptureAgentSlot(object agentSettings) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) FieldInfo field = agentSettings.GetType().GetField("m_build"); if (!(field == null)) { NavMeshBuildSettings buildSettings = (NavMeshBuildSettings)field.GetValue(agentSettings); UnityAgentTypeID = ((NavMeshBuildSettings)(ref buildSettings)).agentTypeID; BuildSettings = buildSettings; } } public static int ResolveValheimHumanoidAgentTypeID() { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if (s_humanoidAgentTypeID >= 0) { return s_humanoidAgentTypeID; } try { Pathfinding instance = Pathfinding.instance; if ((Object)(object)instance == (Object)null) { return 0; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic; FieldInfo field = typeof(Pathfinding).GetField("m_agentSettings", bindingAttr); if (field == null) { return 0; } if (!(field.GetValue(instance) is IList list)) { return 0; } Type? nestedType = typeof(Pathfinding).GetNestedType("AgentSettings", BindingFlags.NonPublic); FieldInfo fieldInfo = nestedType?.GetField("m_agentType"); FieldInfo fieldInfo2 = nestedType?.GetField("m_build"); if (fieldInfo == null || fieldInfo2 == null) { return 0; } foreach (object item in list) { if (item != null && (int)fieldInfo.GetValue(item) == 1) { NavMeshBuildSettings val = (NavMeshBuildSettings)fieldInfo2.GetValue(item); s_humanoidAgentTypeID = ((NavMeshBuildSettings)(ref val)).agentTypeID; return s_humanoidAgentTypeID; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[VillagerAgentType] Failed to resolve Humanoid agentTypeID: " + ex.Message)); } } return 0; } } public class VillagerWaypoint { public const string DefaultStrategyId = "default"; public Vector3 Position { get; } public string StrategyId { get; } public string Label { get; } public bool Active { get; set; } = true; public VillagerWaypoint(Vector3 position, string strategyId, string label = null) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Position = position; StrategyId = (string.IsNullOrEmpty(strategyId) ? "default" : strategyId); Label = label ?? ""; } public static VillagerWaypoint WithDefault(Vector3 position, string label = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return new VillagerWaypoint(position, "default", label); } } } namespace ValheimVillages.Villager.AI.Navigation { public static class BakeAuditCommand { private const float Radius = 1.5f; private const float CharacterRadius = 3f; [DevCommand("Audit bake collider coverage at a position (defaults to player). Usage: vv_bake_audit [x z [y]]", Name = "vv_bake_audit")] public static void Audit(ConsoleEventArgs args) { //IL_0021: 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) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if (TryResolvePosition(args, out var pos, out var source)) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"[BakeAudit] pos=({pos.x:F2}, {pos.y:F2}, {pos.z:F2}) source={source} radius={1.5f:F1}m"); stringBuilder.AppendLine($"--- agent-body waist probe ---\n IsAgentBodyBlocked(pos)={NavMeshBakeManager.IsAgentBodyBlocked(pos)}"); ReportNavMeshSample(stringBuilder, pos); ReportRuntimePhysics(stringBuilder, pos, out var hits); ReportBakeSources(stringBuilder, pos, out HashSet sourceMatches, out List<(int, string, Bounds)> phantomMatches); ReportCrossReference(stringBuilder, hits, sourceMatches, phantomMatches); ReportPhantomCoverage(stringBuilder, pos, phantomMatches); ReportCharacterOverlap(stringBuilder, pos); string text = stringBuilder.ToString(); Console instance = Console.instance; if (instance != null) { instance.Print(text); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } } } [DevCommand("Compare a NavMesh path on the villager (slot 31) bake vs Valheim's Humanoid agent. Usage: vv_pathcompare ", Name = "vv_pathcompare")] public static void PathCompare(ConsoleEventArgs args) { //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0145: 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_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (args?.Args == null || args.Args.Length < 5 || !float.TryParse(args.Args[1], NumberStyles.Float, invariantCulture, out var result) || !float.TryParse(args.Args[2], NumberStyles.Float, invariantCulture, out var result2) || !float.TryParse(args.Args[3], NumberStyles.Float, invariantCulture, out var result3) || !float.TryParse(args.Args[4], NumberStyles.Float, invariantCulture, out var result4)) { Console instance = Console.instance; if (instance != null) { instance.Print("Usage: vv_pathcompare "); } return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"[PathCompare] from=({result:F1},{result2:F1}) to=({result3:F1},{result4:F1})"); AppendAgentPath(stringBuilder, "raw slot31", VillagerAgentType.UnityAgentTypeID, result, result2, result3, result4); AppendAgentPath(stringBuilder, "raw Humanoid", VillagerAgentType.ResolveValheimHumanoidAgentTypeID(), result, result2, result3, result4); NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = VillagerAgentType.UnityAgentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; NavMeshHit val3 = default(NavMeshHit); float num = (NavMesh.SamplePosition(new Vector3(result, 40f, result2), ref val3, 8f, val2) ? ((NavMeshHit)(ref val3)).position.y : 37.4f); List list = new List(); bool flag = VillagerMovement.TryFindCompletePath(new Vector3(result, num, result2), new Vector3(result3, num, result4), list); float num2 = 0f; for (int i = 1; i < list.Count; i++) { num2 += Vector3.Distance(list[i - 1], list[i]); } float num3 = Vector3.Distance(new Vector3(result, num, result2), new Vector3(result3, num, result4)); stringBuilder.AppendLine($" HNA corridor (villager): complete={flag} corners={list.Count} " + $"len={num2:F1}m straight={num3:F1}m " + $"detour={((num3 > 0.01f) ? (num2 / num3) : 1f):F2}x"); string text = stringBuilder.ToString(); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(text); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } } private static void AppendAgentPath(StringBuilder sb, string label, int agentTypeId, float fx, float fz, float tx, float tz) { //IL_0002: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = agentTypeId; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; NavMeshHit val3 = default(NavMeshHit); bool flag = NavMesh.SamplePosition(new Vector3(fx, 40f, fz), ref val3, 8f, val2); NavMeshHit val4 = default(NavMeshHit); bool flag2 = NavMesh.SamplePosition(new Vector3(tx, 40f, tz), ref val4, 8f, val2); if (!flag || !flag2) { sb.AppendLine($" {label} (id={agentTypeId}): sample fail (from={flag}, to={flag2})"); return; } NavMeshPath val5 = new NavMeshPath(); NavMesh.CalculatePath(((NavMeshHit)(ref val3)).position, ((NavMeshHit)(ref val4)).position, val2, val5); Vector3[] corners = val5.corners; float num = 0f; for (int i = 1; i < corners.Length; i++) { num += Vector3.Distance(corners[i - 1], corners[i]); } float num2 = Vector3.Distance(((NavMeshHit)(ref val3)).position, ((NavMeshHit)(ref val4)).position); sb.AppendLine($" {label} (id={agentTypeId}): status={val5.status} corners={corners.Length} " + $"len={num:F1}m straight={num2:F1}m " + $"detour={((num2 > 0.01f) ? (num / num2) : 1f):F2}x " + $"fromSnap=({((NavMeshHit)(ref val3)).position.x:F1},{((NavMeshHit)(ref val3)).position.y:F1},{((NavMeshHit)(ref val3)).position.z:F1}) " + $"toSnap=({((NavMeshHit)(ref val4)).position.x:F1},{((NavMeshHit)(ref val4)).position.y:F1},{((NavMeshHit)(ref val4)).position.z:F1})"); } private static bool TryResolvePosition(ConsoleEventArgs args, out Vector3 pos, out string source) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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_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_0066: Unknown result type (might be due to invalid IL or missing references) if (args?.Args != null && args.Args.Length >= 3) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (!float.TryParse(args.Args[1], NumberStyles.Float, invariantCulture, out var result) || !float.TryParse(args.Args[2], NumberStyles.Float, invariantCulture, out var result2)) { Console instance = Console.instance; if (instance != null) { instance.Print("Usage: vv_bake_audit (no args = player pos) | vv_bake_audit [y]"); } pos = default(Vector3); source = ""; return false; } pos = new Vector3(result, MeshProbe.ResolveY(result, result2, args, 3, invariantCulture), result2); source = "args"; return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Component)localPlayer).transform == (Object)null) { Console instance2 = Console.instance; if (instance2 != null) { instance2.Print("No local player; pass coords instead: vv_bake_audit [y]"); } pos = default(Vector3); source = ""; return false; } pos = ((Component)localPlayer).transform.position; source = "player"; return true; } private static void ReportNavMeshSample(StringBuilder sb, Vector3 pos) { //IL_000e: 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_002a: 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_0033: 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_006b: 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_0097: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("--- NavMesh sample at this position ---"); NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = VillagerAgentType.UnityAgentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; NavMeshHit val3 = default(NavMeshHit); if (NavMesh.SamplePosition(pos, ref val3, 2f, val2)) { sb.AppendLine($" slot 31 ({VillagerAgentType.UnityAgentTypeID}): HIT at " + $"({((NavMeshHit)(ref val3)).position.x:F2},{((NavMeshHit)(ref val3)).position.y:F2},{((NavMeshHit)(ref val3)).position.z:F2}) " + $"dist={Vector3.Distance(((NavMeshHit)(ref val3)).position, pos):F2}m"); NavMeshHit val4 = default(NavMeshHit); if (NavMesh.FindClosestEdge(pos, ref val4, val2)) { sb.AppendLine($" slot 31 closest edge: ({((NavMeshHit)(ref val4)).position.x:F2},{((NavMeshHit)(ref val4)).position.y:F2},{((NavMeshHit)(ref val4)).position.z:F2}) " + $"dist={((NavMeshHit)(ref val4)).distance:F2}m"); } } else { sb.AppendLine(" slot 31: MISS within 2m"); } int num = VillagerAgentType.ResolveValheimHumanoidAgentTypeID(); val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = num; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val5 = val; NavMeshHit val6 = default(NavMeshHit); if (NavMesh.SamplePosition(pos, ref val6, 2f, val5)) { sb.AppendLine($" Humanoid ({num}): HIT at " + $"({((NavMeshHit)(ref val6)).position.x:F2},{((NavMeshHit)(ref val6)).position.y:F2},{((NavMeshHit)(ref val6)).position.z:F2}) " + $"dist={Vector3.Distance(((NavMeshHit)(ref val6)).position, pos):F2}m"); } else { sb.AppendLine($" Humanoid ({num}): MISS within 2m"); } } private static void ReportRuntimePhysics(StringBuilder sb, Vector3 pos, out List hits) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_002e: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine($"--- Runtime physics (Physics.OverlapBox, half-extent {1.5f:F1}m, all layers) ---"); Collider[] array = Physics.OverlapBox(pos, Vector3.one * 1.5f, Quaternion.identity, -1, (QueryTriggerInteraction)1); hits = new List(array.Length); Collider[] array2 = array; foreach (Collider val in array2) { if (!((Object)(object)val == (Object)null)) { hits.Add(val); } } if (hits.Count == 0) { sb.AppendLine(" (none)"); return; } hits.Sort(delegate(Collider a, Collider b) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0022: 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_002b: Unknown result type (might be due to invalid IL or missing references) Bounds bounds2 = a.bounds; float num = Vector3.Distance(((Bounds)(ref bounds2)).center, pos); bounds2 = b.bounds; return num.CompareTo(Vector3.Distance(((Bounds)(ref bounds2)).center, pos)); }); foreach (Collider hit in hits) { GameObject gameObject = ((Component)hit).gameObject; string text = (((Object)(object)gameObject.transform.root != (Object)null) ? ((Object)gameObject.transform.root).name : "(no root)"); string text2 = LayerMask.LayerToName(gameObject.layer); if (string.IsNullOrEmpty(text2)) { text2 = "(unnamed)"; } Bounds bounds = hit.bounds; string arg = ""; MeshCollider val2 = (MeshCollider)(object)((hit is MeshCollider) ? hit : null); if (val2 != null) { Mesh sharedMesh = val2.sharedMesh; arg = (((Object)(object)sharedMesh != (Object)null) ? $" mesh[readable={sharedMesh.isReadable},convex={val2.convex},tris={(sharedMesh.isReadable ? (sharedMesh.triangles.Length / 3) : (-1))}]" : " mesh[null]"); } sb.AppendLine($" '{((Object)gameObject).name}' root='{text}' layer={gameObject.layer}:{text2} " + $"colliderType={((object)hit).GetType().Name} bounds=center({((Bounds)(ref bounds)).center.x:F1},{((Bounds)(ref bounds)).center.y:F1},{((Bounds)(ref bounds)).center.z:F1}) " + $"size({((Bounds)(ref bounds)).size.x:F2},{((Bounds)(ref bounds)).size.y:F2},{((Bounds)(ref bounds)).size.z:F2}) " + $"dist={Vector3.Distance(((Bounds)(ref bounds)).center, pos):F2}m{arg}"); } } private static void ReportBakeSources(StringBuilder sb, Vector3 pos, out HashSet sourceMatches, out List<(int idx, string category, Bounds bounds)> phantomMatches) { //IL_0068: 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_0073: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("--- Bake sources whose bounds overlap this point ---"); sourceMatches = new HashSet(); phantomMatches = new List<(int, string, Bounds)>(); IReadOnlyList terrainSources = NavMeshBakeManager.TerrainSources; IReadOnlyList pieceSources = NavMeshBakeManager.PieceSources; int piecePhantomCount = NavMeshBakeManager.PiecePhantomCount; int lastDoorPhantoms = NavMeshBakeManager.LastDoorPhantoms; int lastBedPhantoms = NavMeshBakeManager.LastBedPhantoms; sb.AppendLine($" TerrainSources={terrainSources.Count} PieceSources={pieceSources.Count} (phantoms={piecePhantomCount})"); Bounds val = default(Bounds); ((Bounds)(ref val))..ctor(pos, Vector3.one * 3f); int num = 0; for (int i = 0; i < terrainSources.Count; i++) { if (TryGetSourceBounds(terrainSources[i], out var bounds) && ((Bounds)(ref bounds)).Intersects(val)) { num++; NavMeshBuildSource val2 = terrainSources[i]; string text = (((Object)(object)((NavMeshBuildSource)(ref val2)).component != (Object)null) ? ((Object)((NavMeshBuildSource)(ref val2)).component.gameObject).name : "(synth)"); int num2 = (((Object)(object)((NavMeshBuildSource)(ref val2)).component != (Object)null) ? ((NavMeshBuildSource)(ref val2)).component.gameObject.layer : (-1)); sb.AppendLine($" terrain[#{i}] shape={((NavMeshBuildSource)(ref val2)).shape} area={((NavMeshBuildSource)(ref val2)).area} comp='{text}' " + $"layer={num2} bounds=center({((Bounds)(ref bounds)).center.x:F1},{((Bounds)(ref bounds)).center.y:F1},{((Bounds)(ref bounds)).center.z:F1}) " + $"size({((Bounds)(ref bounds)).size.x:F2},{((Bounds)(ref bounds)).size.y:F2},{((Bounds)(ref bounds)).size.z:F2})"); if ((Object)(object)((NavMeshBuildSource)(ref val2)).component != (Object)null) { sourceMatches.Add(((NavMeshBuildSource)(ref val2)).component.gameObject); } } } int num3 = pieceSources.Count - piecePhantomCount; int num4 = 0; for (int j = 0; j < num3; j++) { if (TryGetSourceBounds(pieceSources[j], out var bounds2) && ((Bounds)(ref bounds2)).Intersects(val)) { num4++; NavMeshBuildSource val3 = pieceSources[j]; string text2 = (((Object)(object)((NavMeshBuildSource)(ref val3)).component != (Object)null) ? ((Object)((NavMeshBuildSource)(ref val3)).component.gameObject).name : "(synth)"); int num5 = (((Object)(object)((NavMeshBuildSource)(ref val3)).component != (Object)null) ? ((NavMeshBuildSource)(ref val3)).component.gameObject.layer : (-1)); sb.AppendLine($" piece[#{j}] shape={((NavMeshBuildSource)(ref val3)).shape} area={((NavMeshBuildSource)(ref val3)).area} comp='{text2}' " + $"layer={num5} bounds=center({((Bounds)(ref bounds2)).center.x:F1},{((Bounds)(ref bounds2)).center.y:F1},{((Bounds)(ref bounds2)).center.z:F1}) " + $"size({((Bounds)(ref bounds2)).size.x:F2},{((Bounds)(ref bounds2)).size.y:F2},{((Bounds)(ref bounds2)).size.z:F2})"); if ((Object)(object)((NavMeshBuildSource)(ref val3)).component != (Object)null) { sourceMatches.Add(((NavMeshBuildSource)(ref val3)).component.gameObject); } } } for (int k = num3; k < pieceSources.Count; k++) { if (TryGetSourceBounds(pieceSources[k], out var bounds3) && ((Bounds)(ref bounds3)).Intersects(val)) { int num6 = k - num3; string item = ((num6 < lastDoorPhantoms) ? "door" : ((num6 >= lastDoorPhantoms + lastBedPhantoms) ? "outside_cell" : "bed")); phantomMatches.Add((k, item, bounds3)); } } sb.AppendLine($" → terrain matches: {num}, real piece matches: {num4}, phantom matches: {phantomMatches.Count}"); } private static void ReportCrossReference(StringBuilder sb, List runtimeHits, HashSet sourceMatches, List<(int idx, string category, Bounds bounds)> _phantomMatches) { //IL_0026: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("--- Cross-reference: runtime collider → bake source ---"); if (runtimeHits.Count == 0) { sb.AppendLine(" (no runtime colliders to cross-reference)"); return; } NavMeshBuildSettings settingsByID = NavMesh.GetSettingsByID(VillagerAgentType.UnityAgentTypeID); float voxelSize = ((NavMeshBuildSettings)(ref settingsByID)).voxelSize; int mask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); int mask2 = LayerMask.GetMask(new string[1] { "terrain" }); foreach (Collider runtimeHit in runtimeHits) { GameObject gameObject = ((Component)runtimeHit).gameObject; bool flag = ((1 << gameObject.layer) & (mask | mask2)) != 0; float[] array = new float[3]; Bounds bounds = runtimeHit.bounds; array[0] = ((Bounds)(ref bounds)).size.x; bounds = runtimeHit.bounds; array[1] = ((Bounds)(ref bounds)).size.y; bounds = runtimeHit.bounds; array[2] = ((Bounds)(ref bounds)).size.z; float num = Mathf.Max(array); bool flag2 = num < voxelSize * 2f; if (sourceMatches.Contains(gameObject)) { sb.AppendLine($" [OK] '{((Object)gameObject).name}' (layer {gameObject.layer}) - captured in bake"); } else if (!flag) { sb.AppendLine($" [MISS] '{((Object)gameObject).name}' (layer {gameObject.layer}:{LayerMask.LayerToName(gameObject.layer)}) - " + "layer NOT in bake mask (piece=" + LayerMaskToString(mask) + ", terrain=" + LayerMaskToString(mask2) + ")"); } else if (flag2) { sb.AppendLine($" [MISS] '{((Object)gameObject).name}' (layer {gameObject.layer}) - sub-voxel " + $"(maxSize {num:F2}m < {voxelSize * 2f:F2}m = 2x voxel); likely voxelized away"); } else { sb.AppendLine($" [MISS] '{((Object)gameObject).name}' (layer {gameObject.layer}) - in mask, not sub-voxel, " + "but absent from bake (collider inactive at bake time, or spawned/enabled after partition)"); } } } private static void ReportPhantomCoverage(StringBuilder sb, Vector3 pos, List<(int idx, string category, Bounds bounds)> phantomMatches) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("--- Phantom blockers covering this position ---"); if (phantomMatches.Count == 0) { sb.AppendLine(" (none)"); return; } foreach (var phantomMatch in phantomMatches) { var (num, text, val) = phantomMatch; sb.AppendLine($" phantom[#{num}] category={text} bounds=center({((Bounds)(ref val)).center.x:F1},{((Bounds)(ref val)).center.y:F1},{((Bounds)(ref val)).center.z:F1}) " + $"size({((Bounds)(ref val)).size.x:F2},{((Bounds)(ref val)).size.y:F2},{((Bounds)(ref val)).size.z:F2}) dist={Vector3.Distance(((Bounds)(ref val)).center, pos):F2}m"); } } private static void ReportCharacterOverlap(StringBuilder sb, Vector3 pos) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine($"--- Characters within {3f:F1}m (NEVER in bake; runtime obstacles) ---"); int mask = LayerMask.GetMask(new string[4] { "character", "character_net", "character_noenv", "character_trigger" }); Collider[] array = Physics.OverlapSphere(pos, 3f, mask, (QueryTriggerInteraction)1); if (array == null || array.Length == 0) { sb.AppendLine(" (none)"); return; } HashSet hashSet = new HashSet(); Collider[] array2 = array; foreach (Collider val in array2) { if (!((Object)(object)val == (Object)null)) { GameObject val2 = (((Object)(object)((Component)val).transform.root != (Object)null) ? ((Component)((Component)val).transform.root).gameObject : ((Component)val).gameObject); if (hashSet.Add(val2)) { float num = Vector3.Distance(val2.transform.position, pos); sb.AppendLine($" '{((Object)val2).name}' at ({val2.transform.position.x:F1},{val2.transform.position.y:F1},{val2.transform.position.z:F1}) " + $"dist={num:F2}m"); } } } } private static bool TryGetSourceBounds(NavMeshBuildSource src, out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_001e: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_005a: 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_006e: 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) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) bounds = default(Bounds); NavMeshBuildSourceShape shape = ((NavMeshBuildSource)(ref src)).shape; Matrix4x4 transform; if ((int)shape != 0) { if ((int)shape == 2) { Vector3 val = ((NavMeshBuildSource)(ref src)).size * 0.5f; Vector3[] array = (Vector3[])(object)new Vector3[8]; int num = 0; for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { int num2 = num++; transform = ((NavMeshBuildSource)(ref src)).transform; array[num2] = ((Matrix4x4)(ref transform)).MultiplyPoint3x4(new Vector3((float)i * val.x, (float)j * val.y, (float)k * val.z)); } } } Vector3 val2 = array[0]; Vector3 val3 = array[0]; for (int l = 1; l < 8; l++) { val2 = Vector3.Min(val2, array[l]); val3 = Vector3.Max(val3, array[l]); } bounds = new Bounds((val2 + val3) * 0.5f, val3 - val2); return true; } return false; } Object sourceObject = ((NavMeshBuildSource)(ref src)).sourceObject; Mesh val4 = (Mesh)(object)((sourceObject is Mesh) ? sourceObject : null); if ((Object)(object)val4 == (Object)null) { return false; } Bounds bounds2 = val4.bounds; Vector3 extents = ((Bounds)(ref bounds2)).extents; Vector3[] array2 = (Vector3[])(object)new Vector3[8]; int num3 = 0; for (int m = -1; m <= 1; m += 2) { for (int n = -1; n <= 1; n += 2) { for (int num4 = -1; num4 <= 1; num4 += 2) { int num5 = num3++; transform = ((NavMeshBuildSource)(ref src)).transform; array2[num5] = ((Matrix4x4)(ref transform)).MultiplyPoint3x4(((Bounds)(ref bounds2)).center + new Vector3((float)m * extents.x, (float)n * extents.y, (float)num4 * extents.z)); } } } Vector3 val5 = array2[0]; Vector3 val6 = array2[0]; for (int num6 = 1; num6 < 8; num6++) { val5 = Vector3.Min(val5, array2[num6]); val6 = Vector3.Max(val6, array2[num6]); } bounds = new Bounds((val5 + val6) * 0.5f, val6 - val5); return true; } private static string LayerMaskToString(int mask) { List list = new List(); for (int i = 0; i < 32; i++) { if ((mask & (1 << i)) != 0) { string text = LayerMask.LayerToName(i); list.Add(string.IsNullOrEmpty(text) ? $"#{i}" : text); } } if (list.Count != 0) { return string.Join("|", list); } return "(empty)"; } } [Flags] public enum BfsEdgeKind { None = 0, InPassEdge = 1, CrossVert = 2, CrossProx = 4, Pass3Step = 8 } public struct BfsEdgeMeta { public BfsEdgeKind Kinds; public Vector3? RepresentativePos; public float ProxMinDist; } public static class BfsAdjacencyStore { public static Dictionary> Adjacency { get; private set; } = new Dictionary>(); public static HashSet Seeds { get; private set; } = new HashSet(); public static Dictionary EdgeMeta { get; private set; } = new Dictionary(); public static string EdgeKey(string a, string b) { if (string.CompareOrdinal(a, b) <= 0) { return a + "|" + b; } return b + "|" + a; } public static void Set(Dictionary> adjacency, HashSet seeds, Dictionary edgeMeta) { Adjacency = adjacency ?? new Dictionary>(); Seeds = seeds ?? new HashSet(); EdgeMeta = edgeMeta ?? new Dictionary(); } public static List PathToSeed(string targetRegionId) { if (string.IsNullOrEmpty(targetRegionId)) { return null; } if (Adjacency == null || Adjacency.Count == 0) { return null; } if (Seeds == null || Seeds.Count == 0) { return null; } Dictionary dictionary = new Dictionary { { targetRegionId, null } }; Queue queue = new Queue(); queue.Enqueue(targetRegionId); while (queue.Count > 0) { string text = queue.Dequeue(); if (Seeds.Contains(text)) { List list = new List(); string value = text; while (value != null) { list.Add(value); dictionary.TryGetValue(value, out value); } list.Reverse(); return list; } if (!Adjacency.TryGetValue(text, out var value2)) { continue; } foreach (string item in value2) { if (!dictionary.ContainsKey(item)) { dictionary[item] = text; queue.Enqueue(item); } } } return null; } [RegisterCleanup] public static void Clear() { Adjacency = new Dictionary>(); Seeds = new HashSet(); EdgeMeta = new Dictionary(); } } internal static class BfsTraceCommand { [DevCommand("Highlight BFS path from region (or player) to anchor seed. Args: [regionId | off]", Name = "vv_bfs_trace")] public static void Trace(ConsoleEventArgs args) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_0323: 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) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) string text = null; if (args?.Args != null && args.Args.Length >= 2) { text = args.Args[1]; } if (!string.IsNullOrEmpty(text) && (text.Equals("off", StringComparison.OrdinalIgnoreCase) || text.Equals("clear", StringComparison.OrdinalIgnoreCase) || text == "0")) { PathDebugRenderer.HighlightedRegions.Clear(); Console instance = Console.instance; if (instance != null) { instance.Print("[vv_bfs_trace] highlight cleared"); } return; } string text2 = text; if (string.IsNullOrEmpty(text2)) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Console instance2 = Console.instance; if (instance2 != null) { instance2.Print("[vv_bfs_trace] no player and no region arg"); } return; } RegionGraph regionGraph = VillageRegistry.GraphAt(((Component)localPlayer).transform.position); if (regionGraph == null) { Console instance3 = Console.instance; if (instance3 != null) { instance3.Print("[vv_bfs_trace] no RegionGraph available"); } return; } text2 = regionGraph.PointToRegionId(((Component)localPlayer).transform.position); if (string.IsNullOrEmpty(text2)) { Console instance4 = Console.instance; if (instance4 != null) { instance4.Print("[vv_bfs_trace] PointToRegionId unresolved at player " + $"({((Component)localPlayer).transform.position.x:F1},{((Component)localPlayer).transform.position.y:F1},{((Component)localPlayer).transform.position.z:F1})"); } return; } } List list = BfsAdjacencyStore.PathToSeed(text2); if (list == null) { Console instance5 = Console.instance; if (instance5 != null) { instance5.Print("[vv_bfs_trace] no BFS path from " + text2 + " back to any seed " + $"(adjacency size={BfsAdjacencyStore.Adjacency.Count}, " + $"seeds={BfsAdjacencyStore.Seeds.Count})"); } return; } PathDebugRenderer.HighlightedRegions.Clear(); foreach (string item in list) { PathDebugRenderer.HighlightedRegions.Add(item); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("[vv_bfs_trace] ").Append(text2).Append(" -> seed: "); stringBuilder.Append(list.Count).Append(" hops ["); for (int i = 0; i < list.Count; i++) { if (i > 0) { stringBuilder.Append(" -> "); } stringBuilder.Append(list[i]); } stringBuilder.Append("]"); Console instance6 = Console.instance; if (instance6 != null) { instance6.Print(stringBuilder.ToString()); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)stringBuilder.ToString()); } List cachedTriangles = RegionBuilder.CachedTriangles; if (cachedTriangles == null) { return; } Dictionary dictionary = new Dictionary(list.Count); Bounds value2 = default(Bounds); foreach (RegionBuilder.CachedTriangle item2 in cachedTriangles) { if (Enumerable.Contains(list, item2.RegionId)) { if (dictionary.TryGetValue(item2.RegionId, out var value)) { ((Bounds)(ref value)).Encapsulate(item2.V0); ((Bounds)(ref value)).Encapsulate(item2.V1); ((Bounds)(ref value)).Encapsulate(item2.V2); dictionary[item2.RegionId] = value; } else { ((Bounds)(ref value2))..ctor(item2.V0, Vector3.zero); ((Bounds)(ref value2)).Encapsulate(item2.V1); ((Bounds)(ref value2)).Encapsulate(item2.V2); dictionary[item2.RegionId] = value2; } } } for (int j = 0; j < list.Count; j++) { string text3 = list[j]; string text4 = ""; if (j > 0) { string key = BfsAdjacencyStore.EdgeKey(list[j - 1], text3); text4 = ((!BfsAdjacencyStore.EdgeMeta.TryGetValue(key, out var value3)) ? " via [?]" : (" via [" + FormatEdgeMeta(value3) + "]")); } if (!dictionary.TryGetValue(text3, out var value4)) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[vv_bfs_trace] " + text3 + ": (no cached tris)" + text4)); } continue; } Vector3 center = ((Bounds)(ref value4)).center; Vector3 size = ((Bounds)(ref value4)).size; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)($"[vv_bfs_trace] {text3}: centroid=({center.x:F1},{center.y:F1},{center.z:F1}) " + $"size=({size.x:F1}x{size.y:F1}x{size.z:F1}) " + $"y=[{((Bounds)(ref value4)).min.y:F2}..{((Bounds)(ref value4)).max.y:F2}]{text4}")); } } } private static string FormatEdgeMeta(BfsEdgeMeta meta) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) List list = new List(3); if ((meta.Kinds & BfsEdgeKind.InPassEdge) != BfsEdgeKind.None) { list.Add("InPassEdge"); } if ((meta.Kinds & BfsEdgeKind.CrossVert) != BfsEdgeKind.None) { if (meta.RepresentativePos.HasValue) { Vector3 value = meta.RepresentativePos.Value; list.Add($"CrossVert @ ({value.x:F1},{value.y:F1},{value.z:F1})"); } else { list.Add("CrossVert"); } } if ((meta.Kinds & BfsEdgeKind.CrossProx) != BfsEdgeKind.None) { if (meta.RepresentativePos.HasValue) { Vector3 value2 = meta.RepresentativePos.Value; list.Add($"CrossProx @ ({value2.x:F1},{value2.y:F1},{value2.z:F1}) d={meta.ProxMinDist:F2}m"); } else { list.Add($"CrossProx d={meta.ProxMinDist:F2}m"); } } if ((meta.Kinds & BfsEdgeKind.Pass3Step) != BfsEdgeKind.None) { list.Add("Pass3Step"); } if (list.Count != 0) { return string.Join(" | ", list); } return "None"; } } public static class BoundaryDump { private static readonly string OutputPath = Path.Combine(Paths.ConfigPath, "vv_dumps", "hna_boundary_dump.json"); [DevCommand("Dump region-graph boundary cells + the derived patrol route to JSON for offline pipeline testing", Name = "vv_hna_boundary_dump")] public static void Dump() { //IL_002e: 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_003d: 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_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) if (!VillageRegistry.IsAnyAvailable) { Console instance = Console.instance; if (instance != null) { instance.Print("Region graph not available. Spawn a patroller or run vv_repartition first."); } return; } List allAnchorPositions = VillagerAIManager.GetAllAnchorPositions(); Vector3 val = ((allAnchorPositions != null && allAnchorPositions.Count > 0) ? allAnchorPositions[0] : Vector3.zero); RegionGraph regionGraph = VillageRegistry.GraphAt(val); if (regionGraph == null || !regionGraph.IsAvailable) { Console instance2 = Console.instance; if (instance2 != null) { instance2.Print("No graph near anchor position."); } return; } List<(string, Vector3, Vector3)> boundaryCells = regionGraph.GetBoundaryCells(); if (boundaryCells.Count == 0) { Console instance3 = Console.instance; if (instance3 != null) { instance3.Print("No boundary cells found."); } return; } List list = PatrolRouteBuilder.Build(boundaryCells); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{\n"); stringBuilder.Append($" \"cellSize\": {3f:F2},\n"); stringBuilder.Append($" \"regionCount\": {regionGraph.RegionCount},\n"); stringBuilder.Append($" \"anchorPosition\": [{val.x:F2}, {val.y:F2}, {val.z:F2}],\n"); stringBuilder.Append(" \"boundaryCells\": [\n"); for (int i = 0; i < boundaryCells.Count; i++) { (string, Vector3, Vector3) tuple = boundaryCells[i]; Vector3 item = tuple.Item2; Vector3 item2 = tuple.Item3; stringBuilder.Append(" {"); stringBuilder.Append($" \"center\": [{item.x:F2}, {item.y:F2}, {item.z:F2}],"); stringBuilder.Append($" \"outwardDir\": [{item2.x:F3}, {item2.y:F3}, {item2.z:F3}] "); stringBuilder.Append((i < boundaryCells.Count - 1) ? "},\n" : "}\n"); } stringBuilder.Append(" ],\n"); stringBuilder.Append(" \"route\": [\n"); for (int j = 0; j < list.Count; j++) { Vector3 val2 = list[j]; stringBuilder.Append($" [{val2.x:F2}, {val2.y:F2}, {val2.z:F2}]"); stringBuilder.Append((j < list.Count - 1) ? ",\n" : "\n"); } stringBuilder.Append(" ]\n"); stringBuilder.Append("}\n"); File.WriteAllText(OutputPath, stringBuilder.ToString()); Console instance4 = Console.instance; if (instance4 != null) { instance4.Print($"Boundary dump: {boundaryCells.Count} cells -> {list.Count} route waypoints -> {OutputPath}"); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Region] Boundary dump: {boundaryCells.Count} cells -> {list.Count} waypoints -> {OutputPath}"); } } } public class DoorHandler : MonoBehaviour { private const float DoorCloseBlockRadius = 3f; private readonly List m_nearbyDoors = new List(); private readonly Dictionary m_pendingCloseDoors = new Dictionary(); private Character m_character; private float m_lastDoorScanTime; private ZNetView m_znetView; private const float DoorCrossLookahead = 3f; private void Awake() { m_character = ((Component)this).GetComponent(); m_znetView = ((Component)this).GetComponent(); } private void Update() { ProcessPendingDoorClosures(); if (Time.time - m_lastDoorScanTime > 0.5f) { m_lastDoorScanTime = Time.time; ScanForNearbyDoors(); } } private void OnDestroy() { foreach (KeyValuePair pendingCloseDoor in m_pendingCloseDoors) { if ((Object)(object)pendingCloseDoor.Key != (Object)null) { CloseDoor(pendingCloseDoor.Key); } } m_pendingCloseDoors.Clear(); } public Door GetBlockingDoor(Vector3 moveDirection) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0039: 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_0046: Unknown result type (might be due to invalid IL or missing references) //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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00ac: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) if (m_nearbyDoors.Count == 0) { return null; } Vector3 position = ((Component)this).transform.position; Vector3 val = moveDirection; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { return null; } Vector3 b = position + ((Vector3)(ref val)).normalized * 3f; foreach (Door nearbyDoor in m_nearbyDoors) { if (!((Object)(object)nearbyDoor == (Object)null) && IsDoorClosed(nearbyDoor) && IsPlayerBuiltDoor(nearbyDoor)) { Vector3 position2 = ((Component)nearbyDoor).transform.position; Vector3 val2 = position2 - position; if (!(((Vector3)(ref val2)).sqrMagnitude > 9f) && SegmentCrossesDoor(position, b, position2, ((Component)nearbyDoor).transform.forward, DoorwayHalfWidth(nearbyDoor))) { return nearbyDoor; } } } return null; } private static float DoorwayHalfWidth(Door door) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0067: Unknown result type (might be due to invalid IL or missing references) float num = 0f; Collider[] componentsInChildren = ((Component)door).GetComponentsInChildren(true); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.isTrigger) { BoxCollider val2 = (BoxCollider)(object)((val is BoxCollider) ? val : null); if (val2 != null) { Vector3 lossyScale = ((Component)val2).transform.lossyScale; num = Mathf.Max(num, Mathf.Max(Mathf.Abs(val2.size.x * lossyScale.x), Mathf.Abs(val2.size.z * lossyScale.z))); } } } if (num <= 0f) { num = 1.2f; } return num * 0.5f + 0.3f; } private static bool SegmentCrossesDoor(Vector3 a, Vector3 b, Vector3 doorMidpoint, Vector3 doorForward, float doorwayHalfWidth) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_004e: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) float num = Vector3.Dot(a - doorMidpoint, doorForward); float num2 = Vector3.Dot(b - doorMidpoint, doorForward); if (num >= 0f == num2 >= 0f) { return false; } float num3 = num - num2; if (Mathf.Abs(num3) < 1E-05f) { return false; } float num4 = num / num3; Vector3 val = Vector3.Lerp(a, b, num4); float num5 = val.x - doorMidpoint.x; float num6 = val.z - doorMidpoint.z; return num5 * num5 + num6 * num6 <= doorwayHalfWidth * doorwayHalfWidth; } public void OpenDoor(Door door) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_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_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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)door == (Object)null) { return; } ZNetView doorZNetView = GetDoorZNetView(door); if (!((Object)(object)doorZNetView == (Object)null) && doorZNetView.GetZDO() != null && IsDoorClosed(door)) { Vector3 val = ((Component)this).transform.position - ((Component)door).transform.position; Vector3 normalized = ((Vector3)(ref val)).normalized; bool flag = Vector3.Dot(((Component)door).transform.forward, normalized) < 0f; int num = (flag ? 1 : (-1)); Dictionary dictionary = new Dictionary(); val = ((Component)this).transform.position; dictionary.Add("npcPos", ((Vector3)(ref val)).ToString("F2")); val = ((Component)door).transform.position; dictionary.Add("doorPos", ((Vector3)(ref val)).ToString("F2")); val = ((Component)door).transform.forward; dictionary.Add("doorFwd", ((Vector3)(ref val)).ToString("F2")); dictionary.Add("userDir", ((Vector3)(ref normalized)).ToString("F2")); dictionary.Add("dot", Vector3.Dot(((Component)door).transform.forward, normalized)); dictionary.Add("forward", flag); dictionary.Add("openState", num); DebugLog.Append("DoorHandler.cs:open", "open_door", dictionary, "direction", "run1"); doorZNetView.GetZDO().Set(ZDOVars.s_state, num, false); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)$"NPC opened door at {((Component)door).transform.position} (state={num})"); } ScheduleClose(door); } } private void ScheduleClose(Door door) { float value = Time.time + 1.5f; if (m_pendingCloseDoors.ContainsKey(door)) { m_pendingCloseDoors[door] = value; } else { m_pendingCloseDoors.Add(door, value); } } private void ProcessPendingDoorClosures() { if (m_pendingCloseDoors.Count == 0) { return; } List list = new List(); List list2 = new List(); foreach (Door item in new List(m_pendingCloseDoors.Keys)) { if (m_pendingCloseDoors.TryGetValue(item, out var value) && !(Time.time < value)) { if ((Object)(object)item == (Object)null) { list.Add(item); } else if (IsSafeToCLoseDoor(item)) { CloseDoor(item); list.Add(item); } else { list2.Add(item); } } } foreach (Door item2 in list2) { m_pendingCloseDoors[item2] = Time.time + 0.5f; } foreach (Door item3 in list) { m_pendingCloseDoors.Remove(item3); } } private bool IsSafeToCLoseDoor(Door door) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(((Component)door).transform.position, 3f); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && (Object)(object)((Component)val).GetComponentInParent() != (Object)null) { return false; } } return true; } private void CloseDoor(Door door) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)door == (Object)null) { return; } ZNetView doorZNetView = GetDoorZNetView(door); if (!((Object)(object)doorZNetView == (Object)null) && doorZNetView.GetZDO() != null) { doorZNetView.GetZDO().Set(ZDOVars.s_state, 0, false); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)$"NPC closed door at {((Component)door).transform.position}"); } } } private void ScanForNearbyDoors() { //IL_0011: 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) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) m_nearbyDoors.Clear(); Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 6f); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { Door componentInParent = ((Component)val).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && !m_nearbyDoors.Contains(componentInParent)) { m_nearbyDoors.Add(componentInParent); } } } if (m_nearbyDoors.Count > 0) { Dictionary dictionary = new Dictionary(); Vector3 position = ((Component)this).transform.position; dictionary.Add("npcPos", ((Vector3)(ref position)).ToString("F2")); dictionary.Add("doorsFound", m_nearbyDoors.Count); dictionary.Add("scanRadius", 6f); DebugLog.Append("DoorHandler.cs:scan", "scan_result", dictionary, "H4", "run1"); } } private bool IsDoorClosed(Door door) { if ((Object)(object)door == (Object)null) { return false; } ZNetView doorZNetView = GetDoorZNetView(door); if ((Object)(object)doorZNetView == (Object)null || doorZNetView.GetZDO() == null) { return false; } return doorZNetView.GetZDO().GetInt(ZDOVars.s_state, 0) == 0; } private ZNetView GetDoorZNetView(Door door) { if ((Object)(object)door == (Object)null) { return null; } return ((Component)door).GetComponent(); } private bool IsPlayerBuiltDoor(Door door) { if ((Object)(object)door == (Object)null) { return false; } return (Object)(object)((Component)door).GetComponent() != (Object)null; } } public static class MeshProbe { private const float SampleRadius = 5f; private const float ColliderRadius = 1f; internal static float ResolveY(float x, float z, ConsoleEventArgs args, int yIndex, CultureInfo inv) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (args?.Args != null && args.Args.Length > yIndex && float.TryParse(args.Args[yIndex], NumberStyles.Float, inv, out var result)) { return result; } if (!((Object)(object)ZoneSystem.instance != (Object)null)) { return 0f; } return ZoneSystem.instance.GetGroundHeight(new Vector3(x, 0f, z)); } [DevCommand("Probe NavMesh + colliders at the player's position (or pass x z [y] to override)", Name = "vv_probe")] public static void Probe(ConsoleEventArgs args) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) Vector3 position = default(Vector3); bool flag; if (args?.Args != null && args.Args.Length >= 3) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (!float.TryParse(args.Args[1], NumberStyles.Float, invariantCulture, out var result) || !float.TryParse(args.Args[2], NumberStyles.Float, invariantCulture, out var result2)) { Console instance = Console.instance; if (instance != null) { instance.Print("Usage: vv_probe (no args = player pos) | vv_probe [y]"); } return; } ((Vector3)(ref position))..ctor(result, ResolveY(result, result2, args, 3, invariantCulture), result2); flag = false; } else { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Component)localPlayer).transform == (Object)null) { Console instance2 = Console.instance; if (instance2 != null) { instance2.Print("No local player; pass coords instead: vv_probe [y]"); } return; } position = ((Component)localPlayer).transform.position; flag = true; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"[vv_probe] pos=({position.x:F2}, {position.y:F2}, {position.z:F2}) " + "source=" + (flag ? "player" : "args")); stringBuilder.AppendLine($"--- agent slot 31 (agentTypeID={VillagerAgentType.UnityAgentTypeID}, registered={VillagerAgentType.IsRegistered}) ---"); ReportNavMeshSample(stringBuilder, position, VillagerAgentType.UnityAgentTypeID); int num = VillagerAgentType.ResolveValheimHumanoidAgentTypeID(); stringBuilder.AppendLine($"--- Humanoid (agentTypeID={num}) ---"); ReportNavMeshSample(stringBuilder, position, num); stringBuilder.AppendLine($"--- colliders within {1f:F1}m ---"); ReportColliders(stringBuilder, position); stringBuilder.AppendLine("--- capsule-hit colliders (would trigger rej_blocked) ---"); ReportCapsuleHits(stringBuilder, position); stringBuilder.AppendLine("--- RegionBuilder.CachedTriangles within 2m ---"); ReportCachedTriangles(stringBuilder, position); stringBuilder.AppendLine("--- NavMesh bake sources (within 5m) ---"); ReportBakeSources(stringBuilder, position); stringBuilder.AppendLine("--- raw extracted triangles (within 5m, pre-filter) ---"); ReportRawExtracted(stringBuilder, position); stringBuilder.AppendLine("--- filter trace: upward-facing triangles within 3m ---"); ReportFilterTrace(stringBuilder, position); stringBuilder.AppendLine("--- RegionGraph at this point ---"); ReportRegionGraph(stringBuilder, position); stringBuilder.AppendLine("--- Pass 1 flood reachability at this cell ---"); ReportFloodReachability(stringBuilder, position); string text = stringBuilder.ToString(); Console instance3 = Console.instance; if (instance3 != null) { instance3.Print(text); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } } private static void ReportNavMeshSample(StringBuilder sb, Vector3 pos, int agentTypeID) { //IL_0002: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = agentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; NavMeshHit val3 = default(NavMeshHit); if (NavMesh.SamplePosition(pos, ref val3, 5f, val2)) { float num = Vector3.Distance(((NavMeshHit)(ref val3)).position, pos); sb.AppendLine($" SamplePosition: HIT at ({((NavMeshHit)(ref val3)).position.x:F2}, {((NavMeshHit)(ref val3)).position.y:F2}, {((NavMeshHit)(ref val3)).position.z:F2}) " + $"dist={num:F2}m"); } else { sb.AppendLine($" SamplePosition: MISS (no triangle within {5f:F1}m)"); } NavMeshHit val4 = default(NavMeshHit); if (NavMesh.FindClosestEdge(pos, ref val4, val2)) { float num2 = Vector3.Distance(((NavMeshHit)(ref val4)).position, pos); sb.AppendLine($" FindClosestEdge: at ({((NavMeshHit)(ref val4)).position.x:F2}, {((NavMeshHit)(ref val4)).position.y:F2}, {((NavMeshHit)(ref val4)).position.z:F2}) " + $"dist={num2:F2}m"); } else { sb.AppendLine(" FindClosestEdge: no edge found"); } } private static void ReportColliders(StringBuilder sb, Vector3 pos) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_008d: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(pos, 1f, -1, (QueryTriggerInteraction)1); if (array == null || array.Length == 0) { sb.AppendLine(" (none — this point has NO collider, no geometry to bake)"); return; } Array.Sort(array, delegate(Collider a, Collider b) { //IL_0002: 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_000d: 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_0017: 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) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = a.ClosestPoint(pos) - pos; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; val2 = b.ClosestPoint(pos) - pos; float sqrMagnitude2 = ((Vector3)(ref val2)).sqrMagnitude; return sqrMagnitude.CompareTo(sqrMagnitude2); }); int num = Mathf.Min(array.Length, 8); for (int num2 = 0; num2 < num; num2++) { Collider val = array[num2]; string text = LayerMask.LayerToName(((Component)val).gameObject.layer); if (string.IsNullOrEmpty(text)) { text = "(unnamed)"; } float num3 = Vector3.Distance(val.ClosestPoint(pos), pos); sb.AppendLine($" [layer={((Component)val).gameObject.layer}:{text}] {((Object)((Component)val).gameObject).name} " + $"({((object)val).GetType().Name}) dist={num3:F2}m"); } if (array.Length > 8) { sb.AppendLine($" ... and {array.Length - 8} more"); } } private static void ReportCapsuleHits(StringBuilder sb, Vector3 pos) { //IL_0024: 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_002f: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); Vector3 val = pos + Vector3.up * 0.55f; Vector3 val2 = pos + Vector3.up * 1.3499999f; Collider[] array = Physics.OverlapCapsule(val, val2, 0.3f, mask, (QueryTriggerInteraction)1); if (array == null || array.Length == 0) { sb.AppendLine(" (capsule clear — no rej_blocked at this position)"); return; } sb.AppendLine($" capsule p0=({val.x:F2},{val.y:F2},{val.z:F2}) " + $"p1=({val2.x:F2},{val2.y:F2},{val2.z:F2}) r={0.3f:F2}"); foreach (Collider val3 in array) { if (!((Object)(object)val3 == (Object)null)) { string text = LayerMask.LayerToName(((Component)val3).gameObject.layer); if (string.IsNullOrEmpty(text)) { text = "(unnamed)"; } string text2 = "(no Piece)"; Piece componentInParent = ((Component)val3).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { text2 = ((Object)((Component)componentInParent).gameObject).name; } Bounds bounds = val3.bounds; sb.AppendLine(" HIT [" + text + "] go=" + ((Object)((Component)val3).gameObject).name + " prefab=" + text2 + " type=" + ((object)val3).GetType().Name + " " + $"bounds_y=[{((Bounds)(ref bounds)).min.y:F2}..{((Bounds)(ref bounds)).max.y:F2}] " + $"yAbovePos={((Bounds)(ref bounds)).max.y - pos.y:F2}m"); } } } private static void ReportCachedTriangles(StringBuilder sb, Vector3 pos) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) List cachedTriangles = RegionBuilder.CachedTriangles; if (cachedTriangles == null || cachedTriangles.Count == 0) { sb.AppendLine(" CachedTriangles is empty — RegionBuilder has not run, or last run produced 0 triangles"); return; } sb.AppendLine($" (total in cache: {cachedTriangles.Count})"); float num = float.MaxValue; Vector3 val = Vector3.zero; string text = ""; int num2 = 0; int num3 = 0; int num4 = 0; foreach (RegionBuilder.CachedTriangle item in cachedTriangles) { Vector3 val2 = (item.V0 + item.V1 + item.V2) / 3f; float num5 = Vector3.Distance(val2, pos); if (num5 < num) { num = num5; val = val2; text = item.RegionId ?? "(none)"; } if (num5 <= 2f) { num3++; } if (num5 <= 5f) { num4++; } if (Mathf.Abs(val2.y - pos.y) <= 2f && Mathf.Sqrt((val2.x - pos.x) * (val2.x - pos.x) + (val2.z - pos.z) * (val2.z - pos.z)) <= 10f) { num2++; } } sb.AppendLine($" closest cached: ({val.x:F2}, {val.y:F2}, {val.z:F2}) dist={num:F2}m region={text}"); sb.AppendLine($" within 2m: {num3} within 5m: {num4} same-altitude (±2m Y) within 10m XZ: {num2}"); if (num3 == 0) { sb.AppendLine(" → RegionBuilder filter rejected this surface (see [Region] triangulation rej_* counters)"); } } private static void ReportBakeSources(StringBuilder sb, Vector3 pos) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0069: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected I4, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList lastSources = NavMeshBakeManager.LastSources; if (lastSources == null || lastSources.Count == 0) { sb.AppendLine(" No baked sources cached"); return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; float num9 = 2f; foreach (NavMeshBuildSource item in lastSources) { NavMeshBuildSource current = item; Matrix4x4 transform = ((NavMeshBuildSource)(ref current)).transform; Vector3 val = ((Matrix4x4)(ref transform)).MultiplyPoint3x4(Vector3.zero); if (Vector3.Distance(val, pos) > 5f) { continue; } num++; NavMeshBuildSourceShape shape = ((NavMeshBuildSource)(ref current)).shape; switch ((int)shape) { case 2: num2++; if (Mathf.Abs(val.y - pos.y) <= num9) { num8++; } break; case 0: num3++; break; case 3: num4++; break; case 4: num5++; break; case 5: num6++; break; default: num7++; break; } } sb.AppendLine($" {num} source(s) within {5f:F0}m " + $"(Mesh={num3} Box={num2} Sphere={num4} Capsule={num5} ModBox={num6} Other={num7})"); sb.AppendLine($" Box sources at this altitude (±{num9:F0}m Y): {num8}"); } private static void ReportRawExtracted(StringBuilder sb, Vector3 pos) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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) //IL_007a: 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_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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) var (array, array2, _) = NavMeshBakeManager.ExtractBakedTriangles(); if (array == null || array.Length == 0) { sb.AppendLine(" Extractor produced 0 vertices"); return; } int num = array2.Length / 3; int num2 = 0; int num3 = 0; int num4 = 0; float num5 = 2f; for (int i = 0; i < num; i++) { Vector3 val = array[array2[i * 3]]; Vector3 val2 = array[array2[i * 3 + 1]]; Vector3 val3 = array[array2[i * 3 + 2]]; Vector3 val4 = (val + val2 + val3) / 3f; if (!(Vector3.Distance(val4, pos) > 5f)) { num2++; Vector3 val5 = Vector3.Cross(val2 - val, val3 - val); if (((Vector3)(ref val5)).normalized.y >= 0.5f) { num3++; } if (Mathf.Abs(val4.y - pos.y) <= num5) { num4++; } } } sb.AppendLine($" total extracted: {num}; within {5f:F0}m: {num2} " + $"(upward-facing: {num3}, at this altitude ±{num5:F0}m: {num4})"); } private static void ReportFilterTrace(StringBuilder sb, Vector3 pos) { //IL_0026: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: 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_0309: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) var (array, array2, _) = NavMeshBakeManager.ExtractBakedTriangles(); if (array == null || array.Length == 0) { sb.AppendLine(" No extracted triangles"); return; } float num = pos.x - 40f; float num2 = pos.x + 40f; float num3 = pos.z - 40f; float num4 = pos.z + 40f; List list = VillagerAIManager.GetAllAnchorPositions() ?? new List(); NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = VillagerAgentType.UnityAgentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; int num5 = array2.Length / 3; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = 0; int num10 = 0; int num11 = 0; int num12 = 0; int num13 = 0; int num14 = 0; int mask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); NavMeshHit val8 = default(NavMeshHit); NavMeshHit val9 = default(NavMeshHit); NavMeshHit val10 = default(NavMeshHit); for (int i = 0; i < num5; i++) { Vector3 val3 = array[array2[i * 3]]; Vector3 val4 = array[array2[i * 3 + 1]]; Vector3 val5 = array[array2[i * 3 + 2]]; Vector3 val6 = (val3 + val4 + val5) / 3f; if (Vector3.Distance(val6, pos) > 3f) { continue; } Vector3 val7 = Vector3.Cross(val4 - val3, val5 - val3); Vector3 normalized = ((Vector3)(ref val7)).normalized; if (normalized.y < 0.5f) { continue; } num6++; bool flag = val6.x >= num && val6.x <= num2 && val6.z >= num3 && val6.z <= num4; if (flag) { num7++; } bool flag2 = false; foreach (Vector3 item in list) { float num15 = val6.x - item.x; float num16 = val6.z - item.z; if (num15 * num15 + num16 * num16 <= 900f) { flag2 = true; break; } } if (flag2) { num8++; } bool flag3 = NavMesh.SamplePosition(val6, ref val8, 0.5f, val2) && Vector3.Distance(((NavMeshHit)(ref val8)).position, val6) <= 0.5f; bool flag4 = NavMesh.SamplePosition(val6, ref val9, 1f, val2) && Vector3.Distance(((NavMeshHit)(ref val9)).position, val6) <= 1f; bool flag5 = NavMesh.SamplePosition(val6, ref val10, 2f, val2) && Vector3.Distance(((NavMeshHit)(ref val10)).position, val6) <= 2f; if (flag3) { num9++; } if (flag4) { num10++; } if (flag5) { num11++; } bool flag6 = normalized.y >= 0.891007f; if (flag6) { num12++; } Vector3 val11 = val6 + Vector3.up * 0.55f; Vector3 val12 = val6 + Vector3.up * 1.3499999f; bool flag7 = !Physics.CheckCapsule(val11, val12, 0.3f, mask); if (flag7) { num13++; } if (num14 < 8) { string text = (flag3 ? $"HIT@{Vector3.Distance(((NavMeshHit)(ref val8)).position, val6):F2}" : "miss"); string text2 = (flag4 ? $"HIT@{Vector3.Distance(((NavMeshHit)(ref val9)).position, val6):F2}" : "miss"); string text3 = (flag5 ? $"HIT@{Vector3.Distance(((NavMeshHit)(ref val10)).position, val6):F2}" : "miss"); sb.AppendLine($" tri@({val6.x:F2},{val6.y:F2},{val6.z:F2}) " + "bounds=" + (flag ? "Y" : "n") + " dist=" + (flag2 ? "Y" : "n") + " agent[0.5]=" + text + " [1.0]=" + text2 + " [2.0]=" + text3 + " steep=" + (flag6 ? "Y" : "n") + " capsule=" + (flag7 ? "Y" : "BLOCKED")); num14++; } } if (num6 == 0) { sb.AppendLine($" No upward-facing triangles within {3f:F1}m"); return; } sb.AppendLine($" totals (of {num6}): " + $"bounds={num7} dist={num8} agent[0.5]={num9} agent[1.0]={num10} agent[2.0]={num11} " + $"steep_ok={num12} capsule_ok={num13}"); sb.AppendLine($" anchors in scene: {list.Count}"); } private static void ReportRegionGraph(StringBuilder sb, Vector3 pos) { //IL_0000: 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_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0326: 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) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) RegionGraph regionGraph = VillageRegistry.GraphAt(pos); if (regionGraph == null) { sb.AppendLine(" No RegionGraph available (none built/restored yet)"); return; } string text = regionGraph.PointToRegionId(pos); sb.AppendLine(" PointToRegionId: " + (text ?? "(unresolved)")); if (!string.IsNullOrEmpty(text)) { int num = 0; float num2 = 0f; float num3 = float.MaxValue; float num4 = float.MinValue; List cachedTriangles = RegionBuilder.CachedTriangles; if (cachedTriangles != null) { foreach (RegionBuilder.CachedTriangle item in cachedTriangles) { if (!(item.RegionId != text)) { num++; float num5 = num2; Vector3 val = Vector3.Cross(item.V1 - item.V0, item.V2 - item.V0); num2 = num5 + ((Vector3)(ref val)).magnitude * 0.5f; float num6 = Mathf.Min(item.V0.y, Mathf.Min(item.V1.y, item.V2.y)); float num7 = Mathf.Max(item.V0.y, Mathf.Max(item.V1.y, item.V2.y)); if (num6 < num3) { num3 = num6; } if (num7 > num4) { num4 = num7; } } } } int num8 = 0; IReadOnlyList linksFromRegion = regionGraph.GetLinksFromRegion(text); if (linksFromRegion != null) { num8 = linksFromRegion.Count; } SurfaceKind regionKind = regionGraph.GetRegionKind(text); sb.AppendLine($" Resolved region {text}: kind={regionKind}, tris={num}, " + string.Format("area={0:F2}m², Y=[{1}, ", num2, (num > 0) ? num3.ToString("F2") : "?") + string.Format("{0}], links={1}", (num > 0) ? num4.ToString("F2") : "?", num8)); if (linksFromRegion != null && num8 > 0) { foreach (RegionLink item2 in linksFromRegion) { string toRegionId = item2.ToRegionId; SurfaceKind regionKind2 = regionGraph.GetRegionKind(toRegionId); string text2 = (regionGraph.IsValidRegion(toRegionId) ? "alive" : "DROPPED"); sb.AppendLine($" link -> {toRegionId} ({regionKind2}, {item2.LinkType}, {text2}) " + $"at ({item2.PositionEnd.x:F1}, {item2.PositionEnd.y:F1}, {item2.PositionEnd.z:F1})"); } } } float num9 = float.MaxValue; Vector3 val2 = Vector3.zero; string text3 = ""; List allRegionCenters = regionGraph.Diagnostics.GetAllRegionCenters(); int num10 = 0; foreach (Vector3 item3 in allRegionCenters) { float num11 = Vector3.Distance(item3, pos); if (num11 < num9) { num9 = num11; val2 = item3; text3 = $"#{num10}"; } num10++; } if (allRegionCenters.Count == 0) { sb.AppendLine(" No centroids in graph"); return; } sb.AppendLine(" Closest centroid " + text3 + ": " + $"({val2.x:F2}, {val2.y:F2}, {val2.z:F2}) " + $"dist3d={num9:F2}m " + $"(graph has {regionGraph.RegionCount} regions, {regionGraph.LinkCount} links)"); } private static void ReportFloodReachability(StringBuilder sb, Vector3 pos) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!RubberBandPrune.HasSnapshot || RubberBandPrune.LastOutsideCells == null || RubberBandPrune.LastXzMaxY == null || RubberBandPrune.LastCell <= 0f) { sb.AppendLine(" No RubberBandPrune snapshot — run vv_repartition first"); return; } float lastCell = RubberBandPrune.LastCell; int lastPieceMask = RubberBandPrune.LastPieceMask; int num = Mathf.FloorToInt(pos.x / lastCell); int num2 = Mathf.FloorToInt(pos.z / lastCell); long num3 = RubberBandPrune.DiagnoseXzKey(num, num2); bool flag = RubberBandPrune.LastOutsideCells.Contains(num3); bool flag2 = RubberBandPrune.LastXzMaxY.ContainsKey(num3); float num4 = RubberBandPrune.DiagnoseCellY(num, num2); sb.AppendLine($" cell gx={num} gz={num2} Y={num4:F2} " + "populated=" + (flag2 ? "yes" : "no") + " in_outsideCells=" + (flag ? "YES" : "NO")); sb.AppendLine($" bake bounds gx=[{RubberBandPrune.LastGxMin}..{RubberBandPrune.LastGxMax}] " + $"gz=[{RubberBandPrune.LastGzMin}..{RubberBandPrune.LastGzMax}] " + $"cell={lastCell:F2}m pieceMask=0x{lastPieceMask:X}"); string[] array = new string[4] { "E ", "W ", "N ", "S " }; int[] array2 = new int[4] { 1, -1, 0, 0 }; int[] array3 = new int[4] { 0, 0, 1, -1 }; string[] array4 = new string[4] { "NE", "NW", "SE", "SW" }; int[] array5 = new int[4] { 1, -1, 1, -1 }; int[] array6 = new int[4] { 1, 1, -1, -1 }; sb.AppendLine(" 4-connected neighbors (used by Pass 1):"); for (int i = 0; i < 4; i++) { ReportNeighbor(sb, array[i], num, num2, array2[i], array3[i], lastCell, lastPieceMask); } sb.AppendLine(" 8-connected diagonal neighbors (NOT used by Pass 1 today):"); for (int j = 0; j < 4; j++) { ReportNeighbor(sb, array4[j], num, num2, array5[j], array6[j], lastCell, lastPieceMask); } } private static void ReportNeighbor(StringBuilder sb, string label, int gx, int gz, int dx, int dz, float cell, int mask) { int num = gx + dx; int num2 = gz + dz; long num3 = RubberBandPrune.DiagnoseXzKey(num, num2); bool flag = RubberBandPrune.LastOutsideCells.Contains(num3); bool flag2 = RubberBandPrune.LastXzMaxY.ContainsKey(num3); float yA = RubberBandPrune.DiagnoseCellY(gx, gz); float num4 = RubberBandPrune.DiagnoseCellY(num, num2); string hitNames; bool flag3 = RubberBandPrune.Diagnose(gx, gz, num, num2, yA, num4, cell, mask, out hitNames); sb.AppendLine($" {label} gx={num} gz={num2} Y={num4:F2} " + "populated=" + (flag2 ? "y" : "n") + " outside=" + (flag ? "YES" : "no ") + " WallBlocks=" + (flag3 ? "TRUE" : "false") + (flag3 ? (" hits=[" + hitNames + "]") : "")); } } public static class NavMeshBakeManager { public struct BakeResult { public bool Success; public int SourceCount; public int DoorsBlocked; public int DoorPiecesDropped; public int BedsBlocked; public int OutsideCellsBlocked; public int OutsideCellsCount; public float DurationMs; public string FailureReason; public int TerrainSourceCount; public int PieceSourceCount; public float TerrainDurationMs; public float PieceDurationMs; } private const string HolderName = "VV_NavMeshBakeHolder"; private static NavMeshBakeHolder s_holder; private static readonly List s_terrainSources = new List(); private static readonly List s_pieceSources = new List(); private static int s_piecePhantomCount; private static int s_lastDoorPhantoms; private static int s_lastBedPhantoms; private static int s_lastOutsidePhantoms; private static readonly int s_terrainMask = LayerMask.GetMask(new string[1] { "terrain" }); private static readonly int s_pieceMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); private const float NavMeshBakeMaxSlopeDegrees = 27f; private const float NavMeshBakeMaxClimb = 0.2f; private static readonly int s_bodyBlockMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); private static readonly Collider[] s_bodyBlockBuf = (Collider[])(object)new Collider[16]; private const float SubdivFaceMinNormalY = 0.5f; public static IReadOnlyList TerrainSources => s_terrainSources; public static IReadOnlyList PieceSources => s_pieceSources; public static int PiecePhantomCount => s_piecePhantomCount; public static int LastDoorPhantoms => s_lastDoorPhantoms; public static int LastBedPhantoms => s_lastBedPhantoms; public static int LastOutsidePhantoms => s_lastOutsidePhantoms; private static NavMeshBakeHolder Holder { get { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s_holder != (Object)null) { return s_holder; } GameObject val = GameObject.Find("VV_NavMeshBakeHolder"); if ((Object)(object)val != (Object)null) { NavMeshBakeHolder navMeshBakeHolder = val.GetComponent(); if ((Object)(object)navMeshBakeHolder == (Object)null) { MonoBehaviour[] components = val.GetComponents(); foreach (MonoBehaviour val2 in components) { if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name == "NavMeshBakeHolder") { Object.DestroyImmediate((Object)(object)val2); } } navMeshBakeHolder = val.AddComponent(); } s_holder = navMeshBakeHolder; return s_holder; } GameObject val3 = new GameObject("VV_NavMeshBakeHolder"); Object.DontDestroyOnLoad((Object)val3); ((Object)val3).hideFlags = (HideFlags)1; s_holder = val3.AddComponent(); return s_holder; } } public static bool HasBakedData => Holder.HasAny; public static IReadOnlyList LastSources { get { List list = new List(s_terrainSources.Count + s_pieceSources.Count); list.AddRange(s_terrainSources); list.AddRange(s_pieceSources); return list; } } public static BakeResult BakeVillage(Bounds bounds) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) BakeResult result = default(BakeResult); Stopwatch stopwatch = Stopwatch.StartNew(); if (!VillagerAgentType.IsRegistered) { result.FailureReason = "agent_not_registered"; stopwatch.Stop(); result.DurationMs = (float)stopwatch.Elapsed.TotalMilliseconds; return result; } Holder.RemoveAll(); NavMeshBuildSettings buildSettings = VillagerAgentType.BuildSettings; ((NavMeshBuildSettings)(ref buildSettings)).agentRadius = ((NavMeshBuildSettings)(ref buildSettings)).agentRadius + 0.025f; ((NavMeshBuildSettings)(ref buildSettings)).agentSlope = 27f; ((NavMeshBuildSettings)(ref buildSettings)).agentClimb = 0.2f; Stopwatch stopwatch2 = Stopwatch.StartNew(); List list = new List(); NavMeshBuilder.CollectSources(bounds, s_terrainMask, (NavMeshCollectGeometry)1, 0, new List(), list); s_terrainSources.Clear(); s_terrainSources.AddRange(list); result.TerrainSourceCount = list.Count; stopwatch2.Stop(); result.TerrainDurationMs = (float)stopwatch2.Elapsed.TotalMilliseconds; Stopwatch stopwatch3 = Stopwatch.StartNew(); List list2 = new List(); NavMeshBuilder.CollectSources(bounds, s_pieceMask, (NavMeshCollectGeometry)1, 0, new List(), list2); int doorPiecesDropped = list2.RemoveAll((NavMeshBuildSource s) => (Object)(object)((NavMeshBuildSource)(ref s)).component != (Object)null && (Object)(object)((NavMeshBuildSource)(ref s)).component.GetComponentInParent() != (Object)null); result.DoorPiecesDropped = doorPiecesDropped; result.DoorsBlocked = 0; list2.RemoveAll((NavMeshBuildSource s) => (Object)(object)((NavMeshBuildSource)(ref s)).component != (Object)null && (Object)(object)((NavMeshBuildSource)(ref s)).component.GetComponentInParent() != (Object)null); int num = (result.BedsBlocked = AddBedBlockers(list2, bounds)); HashSet hashSet = RubberBandPrune.ComputeOutsideCellsForBake(bounds); int num2 = (result.OutsideCellsBlocked = AddOutsideCellBlockers(list2, hashSet, bounds)); result.OutsideCellsCount = hashSet.Count; s_pieceSources.Clear(); s_pieceSources.AddRange(list2); s_piecePhantomCount = num + num2; s_lastDoorPhantoms = 0; s_lastBedPhantoms = num; s_lastOutsidePhantoms = num2; result.PieceSourceCount = list2.Count; List list3 = new List(list.Count + list2.Count); list3.AddRange(list); list3.AddRange(list2); if (list3.Count > 0) { NavMeshData val = NavMeshBuilder.BuildNavMeshData(buildSettings, list3, bounds, Vector3.zero, Quaternion.identity); if ((Object)(object)val != (Object)null) { Holder.SetCombined(NavMesh.AddNavMeshData(val)); } } stopwatch3.Stop(); result.PieceDurationMs = (float)stopwatch3.Elapsed.TotalMilliseconds; result.SourceCount = result.TerrainSourceCount + result.PieceSourceCount; if (result.SourceCount == 0) { result.FailureReason = "no_sources_collected"; stopwatch.Stop(); result.DurationMs = (float)stopwatch.Elapsed.TotalMilliseconds; return result; } result.Success = Holder.HasAny; if (!result.Success) { result.FailureReason = "build_returned_null"; } stopwatch.Stop(); result.DurationMs = (float)stopwatch.Elapsed.TotalMilliseconds; return result; } public static (Vector3[] vertices, int[] indices, int[] triangleLayers) ExtractBakedTriangles() { var (array, array2, array3) = ExtractBakedTriangles(SurfaceKind.Terrain); var (array4, array5, array6) = ExtractBakedTriangles(SurfaceKind.Piece); if (array.Length == 0) { return (vertices: array4, indices: array5, triangleLayers: array6); } if (array4.Length == 0) { return (vertices: array, indices: array2, triangleLayers: array3); } Vector3[] array7 = (Vector3[])(object)new Vector3[array.Length + array4.Length]; Array.Copy(array, 0, array7, 0, array.Length); Array.Copy(array4, 0, array7, array.Length, array4.Length); int[] array8 = new int[array2.Length + array5.Length]; Array.Copy(array2, 0, array8, 0, array2.Length); for (int i = 0; i < array5.Length; i++) { array8[array2.Length + i] = array5[i] + array.Length; } int[] array9 = new int[array3.Length + array6.Length]; Array.Copy(array3, 0, array9, 0, array3.Length); Array.Copy(array6, 0, array9, array3.Length, array6.Length); return (vertices: array7, indices: array8, triangleLayers: array9); } public static (Vector3[] vertices, int[] indices, int[] triangleLayers) ExtractBakedTriangles(SurfaceKind kind) { return ExtractBakedTriangles(kind, float.NegativeInfinity, float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity); } public static (Vector3[] vertices, int[] indices, int[] triangleLayers) ExtractBakedTriangles(SurfaceKind kind, float minX, float minZ, float maxX, float maxZ) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Invalid comparison between Unknown and I4 //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) List list = ((kind == SurfaceKind.Terrain) ? s_terrainSources : s_pieceSources); int num = ((kind == SurfaceKind.Piece) ? s_piecePhantomCount : 0); if (list.Count == 0) { return (vertices: Array.Empty(), indices: Array.Empty(), triangleLayers: Array.Empty()); } List list2 = new List(list.Count * 32); List list3 = new List(list.Count * 96); List list4 = new List(list.Count * 32); int num2 = 0; int num3 = 0; int num4 = list.Count - num; for (int i = 0; i < num4; i++) { NavMeshBuildSource val = list[i]; int layer = (((Object)(object)((NavMeshBuildSource)(ref val)).component != (Object)null) ? ((NavMeshBuildSource)(ref val)).component.gameObject.layer : (-1)); NavMeshBuildSourceShape shape = ((NavMeshBuildSource)(ref val)).shape; if ((int)shape != 0) { if ((int)shape == 2) { AppendBox(list2, list3, list4, layer, ((NavMeshBuildSource)(ref val)).transform, ((NavMeshBuildSource)(ref val)).size, minX, minZ, maxX, maxZ, kind == SurfaceKind.Piece); } else { num3++; } continue; } Object sourceObject = ((NavMeshBuildSource)(ref val)).sourceObject; Mesh val2 = (Mesh)(object)((sourceObject is Mesh) ? sourceObject : null); if ((Object)(object)val2 == (Object)null) { num3++; } else if (!val2.isReadable) { num2++; } else { AppendMesh(list2, list3, list4, layer, ((NavMeshBuildSource)(ref val)).transform, val2, minX, minZ, maxX, maxZ); } } if (num2 > 0 || num3 > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)($"[NavMeshBake] extract({kind}): {num2} unreadable mesh(es) skipped, " + $"{num3} non-Mesh/Box source(s) skipped")); } } if (kind == SurfaceKind.Terrain) { WeldCoincidentVertices(list2, list3); } return (vertices: list2.ToArray(), indices: list3.ToArray(), triangleLayers: list4.ToArray()); } private static void WeldCoincidentVertices(List verts, List idx) { //IL_0032: 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_004b: Unknown result type (might be due to invalid IL or missing references) if (verts.Count == 0 || idx.Count == 0) { return; } Dictionary dictionary = new Dictionary(verts.Count); int[] array = new int[verts.Count]; for (int i = 0; i < verts.Count; i++) { Vector3 val = verts[i]; long num = Mathf.RoundToInt(val.x / 0.05f); long num2 = Mathf.RoundToInt(val.y / 0.05f); long num3 = Mathf.RoundToInt(val.z / 0.05f); long key = (((num + 1048576) & 0x1FFFFF) << 42) | (((num2 + 1048576) & 0x1FFFFF) << 21) | ((num3 + 1048576) & 0x1FFFFF); if (dictionary.TryGetValue(key, out var value)) { array[i] = value; continue; } dictionary[key] = i; array[i] = i; } int num4 = 0; for (int j = 0; j < idx.Count; j++) { int num5 = idx[j]; int num6 = array[num5]; if (num6 != num5) { idx[j] = num6; num4++; } } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[NavMeshBake] terrain weld: {num4} index refs re-pointed across " + $"{verts.Count - dictionary.Count} merged vertex positions " + $"({verts.Count} total verts, {dictionary.Count} unique positions)")); } } private static int AddDoorBlockers(List sources, Bounds bounds) { //IL_0037: 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_0054: 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_0063: 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) //IL_0087: 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_00a2: Unknown result type (might be due to invalid IL or missing references) int num = 0; Door[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (Door val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)null) && ((Bounds)(ref bounds)).Contains(((Component)val).transform.position)) { Matrix4x4 transform = Matrix4x4.TRS(((Component)val).transform.position, ((Component)val).transform.rotation, Vector3.one); NavMeshBuildSource item = default(NavMeshBuildSource); ((NavMeshBuildSource)(ref item)).shape = (NavMeshBuildSourceShape)2; ((NavMeshBuildSource)(ref item)).size = new Vector3(1.2f, 2f, 0.3f); ((NavMeshBuildSource)(ref item)).transform = transform; ((NavMeshBuildSource)(ref item)).area = 1; sources.Add(item); num++; } } return num; } internal static bool IsAgentBodyBlocked(Vector3 surfacePos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0031: Unknown result type (might be due to invalid IL or missing references) Vector3 val = surfacePos + Vector3.up * 1f; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(0.9f, 0.3f, 0.9f); int num = Physics.OverlapBoxNonAlloc(val, val2, s_bodyBlockBuf, Quaternion.identity, s_bodyBlockMask, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider val3 = s_bodyBlockBuf[i]; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Component)val3).GetComponentInParent() != (Object)null)) { return true; } } return false; } private static int AddBedBlockers(List sources, Bounds bounds) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) int num = 0; Bed[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (Bed val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)null) && ((Bounds)(ref bounds)).Contains(((Component)val).transform.position)) { Collider componentInChildren = ((Component)val).GetComponentInChildren(); if (!((Object)(object)componentInChildren == (Object)null)) { Bounds bounds2 = componentInChildren.bounds; float num2 = ((Bounds)(ref bounds2)).min.y - 0.6f; float num3 = ((Bounds)(ref bounds2)).max.y + 0.4f; NavMeshBuildSource item = default(NavMeshBuildSource); ((NavMeshBuildSource)(ref item)).shape = (NavMeshBuildSourceShape)5; ((NavMeshBuildSource)(ref item)).size = new Vector3(((Bounds)(ref bounds2)).size.x + 0.2f, num3 - num2, ((Bounds)(ref bounds2)).size.z + 0.2f); ((NavMeshBuildSource)(ref item)).transform = Matrix4x4.TRS(new Vector3(((Bounds)(ref bounds2)).center.x, (num2 + num3) * 0.5f, ((Bounds)(ref bounds2)).center.z), Quaternion.identity, Vector3.one); ((NavMeshBuildSource)(ref item)).area = 1; sources.Add(item); num++; } } } return num; } private static int AddOutsideCellBlockers(List sources, HashSet outsideCells, Bounds bounds) { //IL_0015: 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_00b7: 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) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) if (outsideCells == null || outsideCells.Count == 0) { return 0; } float num = 1f; float num2 = ((Bounds)(ref bounds)).size.y + 4f; float y = ((Bounds)(ref bounds)).center.y; List list = RubberBandPrune.DecomposeToRectangles(outsideCells); foreach (RubberBandPrune.CellRect item2 in list) { float num3 = (float)(item2.Gx1 - item2.Gx0 + 1) * num; float num4 = (float)(item2.Gz1 - item2.Gz0 + 1) * num; float num5 = (float)(item2.Gx0 + item2.Gx1 + 1) * 0.5f * num; float num6 = (float)(item2.Gz0 + item2.Gz1 + 1) * 0.5f * num; NavMeshBuildSource item = default(NavMeshBuildSource); ((NavMeshBuildSource)(ref item)).shape = (NavMeshBuildSourceShape)5; ((NavMeshBuildSource)(ref item)).size = new Vector3(num3 + 0.4f, num2, num4 + 0.4f); ((NavMeshBuildSource)(ref item)).transform = Matrix4x4.TRS(new Vector3(num5, y, num6), Quaternion.identity, Vector3.one); ((NavMeshBuildSource)(ref item)).area = 1; sources.Add(item); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[NavMeshBake] OutsideCellBlockers: {outsideCells.Count} cells -> " + $"{list.Count} ModifierBox rectangles")); } return list.Count; } private static void AppendMesh(List verts, List idx, List triLayers, int layer, Matrix4x4 t, Mesh mesh, float minX, float minZ, float maxX, float maxZ) { //IL_002e: 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_0038: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) Vector3[] vertices; int[] triangles; try { vertices = mesh.vertices; triangles = mesh.triangles; } catch { return; } Vector3[] array = (Vector3[])(object)new Vector3[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { array[i] = ((Matrix4x4)(ref t)).MultiplyPoint3x4(vertices[i]); } int[] array2 = new int[vertices.Length]; for (int j = 0; j < array2.Length; j++) { array2[j] = -1; } for (int k = 0; k < triangles.Length; k += 3) { int num = triangles[k]; int num2 = triangles[k + 1]; int num3 = triangles[k + 2]; Vector3 val = array[num]; Vector3 val2 = array[num2]; Vector3 val3 = array[num3]; float num4 = (val.x + val2.x + val3.x) * (1f / 3f); float num5 = (val.z + val2.z + val3.z) * (1f / 3f); if (!(num4 < minX) && !(num4 > maxX) && !(num5 < minZ) && !(num5 > maxZ)) { if (array2[num] < 0) { array2[num] = verts.Count; verts.Add(val); } if (array2[num2] < 0) { array2[num2] = verts.Count; verts.Add(val2); } if (array2[num3] < 0) { array2[num3] = verts.Count; verts.Add(val3); } idx.Add(array2[num]); idx.Add(array2[num2]); idx.Add(array2[num3]); triLayers.Add(layer); } } } private static void AppendBox(List verts, List idx, List triLayers, int layer, Matrix4x4 t, Vector3 size, float minX, float minZ, float maxX, float maxZ, bool subdivide) { //IL_0002: 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_000c: 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_0017: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0173: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Matrix4x4)(ref t)).MultiplyPoint3x4(Vector3.zero); if (!(val.x < minX) && !(val.x > maxX) && !(val.z < minZ) && !(val.z > maxZ)) { Vector3 val2 = size * 0.5f; Vector3 uLocal = default(Vector3); ((Vector3)(ref uLocal))..ctor(2f * val2.x, 0f, 0f); Vector3 vLocal = default(Vector3); ((Vector3)(ref vLocal))..ctor(0f, 2f * val2.y, 0f); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(0f, 0f, 2f * val2.z); AppendBoxFace(verts, idx, triLayers, layer, t, new Vector3(0f - val2.x, val2.y, 0f - val2.z), uLocal, val3, Vector3.up, subdivide); AppendBoxFace(verts, idx, triLayers, layer, t, new Vector3(0f - val2.x, 0f - val2.y, 0f - val2.z), uLocal, val3, Vector3.down, subdivide); AppendBoxFace(verts, idx, triLayers, layer, t, new Vector3(0f - val2.x, 0f - val2.y, val2.z), uLocal, vLocal, Vector3.forward, subdivide); AppendBoxFace(verts, idx, triLayers, layer, t, new Vector3(0f - val2.x, 0f - val2.y, 0f - val2.z), uLocal, vLocal, Vector3.back, subdivide); AppendBoxFace(verts, idx, triLayers, layer, t, new Vector3(val2.x, 0f - val2.y, 0f - val2.z), val3, vLocal, Vector3.right, subdivide); AppendBoxFace(verts, idx, triLayers, layer, t, new Vector3(0f - val2.x, 0f - val2.y, 0f - val2.z), val3, vLocal, Vector3.left, subdivide); } } private static void AppendBoxFace(List verts, List idx, List triLayers, int layer, Matrix4x4 t, Vector3 originLocal, Vector3 uLocal, Vector3 vLocal, Vector3 axisLocal, bool subdivide) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Matrix4x4)(ref t)).MultiplyVector(axisLocal); Vector3 normalized = ((Vector3)(ref val)).normalized; int num = 1; int num2 = 1; if (subdivide && normalized.y >= 0.5f) { float num3 = 1f; val = ((Matrix4x4)(ref t)).MultiplyVector(uLocal); float magnitude = ((Vector3)(ref val)).magnitude; val = ((Matrix4x4)(ref t)).MultiplyVector(vLocal); float magnitude2 = ((Vector3)(ref val)).magnitude; num = Mathf.Max(1, Mathf.CeilToInt(magnitude / num3)); num2 = Mathf.Max(1, Mathf.CeilToInt(magnitude2 / num3)); } int count = verts.Count; for (int i = 0; i <= num2; i++) { float num4 = (float)i / (float)num2; for (int j = 0; j <= num; j++) { float num5 = (float)j / (float)num; verts.Add(((Matrix4x4)(ref t)).MultiplyPoint3x4(originLocal + uLocal * num5 + vLocal * num4)); } } int num6 = num + 1; for (int k = 0; k < num2; k++) { for (int l = 0; l < num; l++) { int num7 = count + k * num6 + l; int num8 = num7 + 1; int num9 = num7 + num6; int num10 = num9 + 1; if (Vector3.Dot(Vector3.Cross(verts[num8] - verts[num7], verts[num10] - verts[num7]), normalized) >= 0f) { idx.Add(num7); idx.Add(num8); idx.Add(num10); idx.Add(num7); idx.Add(num10); idx.Add(num9); } else { idx.Add(num7); idx.Add(num10); idx.Add(num8); idx.Add(num7); idx.Add(num9); idx.Add(num10); } triLayers.Add(layer); triLayers.Add(layer); } } } [RegisterCleanup] public static void Clear() { Holder.RemoveAll(); s_terrainSources.Clear(); s_pieceSources.Clear(); s_piecePhantomCount = 0; s_lastDoorPhantoms = 0; s_lastBedPhantoms = 0; s_lastOutsidePhantoms = 0; } } internal class NavMeshBakeHolder : MonoBehaviour { private NavMeshDataInstance m_combined; internal bool HasAny => ((NavMeshDataInstance)(ref m_combined)).valid; private void OnDestroy() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (((NavMeshDataInstance)(ref m_combined)).valid) { ((NavMeshDataInstance)(ref m_combined)).Remove(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NavMeshBakeHolder] OnDestroy: removed orphaned NavMesh instance"); } } m_combined = default(NavMeshDataInstance); } internal void SetCombined(NavMeshDataInstance instance) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) RemoveAll(); m_combined = instance; } internal void RemoveAll() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (((NavMeshDataInstance)(ref m_combined)).valid) { ((NavMeshDataInstance)(ref m_combined)).Remove(); } m_combined = default(NavMeshDataInstance); } } internal static class PlayerAvoidanceObstacle { private const float Radius = 0.5f; private const float Height = 1.8f; private static NavMeshObstacle s_obstacle; private static Player s_player; internal static void Tick() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { s_obstacle = null; s_player = null; return; } if ((Object)(object)s_obstacle == (Object)null || (Object)(object)s_player != (Object)(object)localPlayer) { s_player = localPlayer; s_obstacle = ((Component)localPlayer).GetComponent() ?? ((Component)localPlayer).gameObject.AddComponent(); s_obstacle.carving = false; s_obstacle.shape = (NavMeshObstacleShape)0; s_obstacle.radius = 0.5f; s_obstacle.height = 1.8f; s_obstacle.center = new Vector3(0f, 0.9f, 0f); } Vector3 velocity = ((Character)localPlayer).GetVelocity(); velocity.y = 0f; s_obstacle.velocity = velocity; } } internal static class RegionBuilder { internal struct CachedTriangle { public Vector3 V0; public Vector3 V1; public Vector3 V2; public string RegionId; public SurfaceKind Kind; public int Layer; } internal struct BuildResult { public HashSet RegionIds; public Dictionary Centroids; public List Links; public Dictionary LookupGrid; public List<(string id, Vector3 center, Vector3 outDir)> BoundaryCells; public List Triangles; public SurfaceKind Kind; public Dictionary> Adjacency; public Dictionary> RegionVertexPositions; public Dictionary RegionBounds; public Dictionary> RegionVertexList; } private const float SubdivCellSize = 3f; private const float HeightBandSize = 2f; private const float AgentFilterRadius = 0.5f; private const float MaxBelowTerrain = 1.5f; private const float MinRegionArea = 0.25f; private const float MinCentroidEdgeDist = 0f; private const float CoplanarMergeMaxDeltaY = 1.5f; private const float EnclosurePlaneDeltaY = 0.2f; private const float EnclosureMaxBelow = 0.5f; private const float MinWalkableNormalY = 0.891007f; private const float CapsuleRadius = 0.2f; private const float CapsuleHeight = 1.4f; private const float CapsuleLift = 0.25f; private const float PieceWaistProbeLift = 1f; private const float PieceWaistProbeRadius = 0.1f; private const float TerrainIsolatedMaxArea = 16f; private static readonly int s_blockMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); internal const float QuantumStep = 0.25f; internal static List CachedTriangles { get; set; } = new List(); [RegisterCleanup] public static void ClearCachedState() { CachedTriangles.Clear(); } internal static void CombineTerrainAndPiece(BuildResult terrainResult, BuildResult pieceResult, out HashSet combinedRegionIds, out Dictionary combinedCentroids, out List combinedLinks, out Dictionary combinedLookup, out List<(string, Vector3, Vector3)> combinedBoundary, out List combinedTriangles, out Dictionary kindMap) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: 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_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) //IL_050c: Unknown result type (might be due to invalid IL or missing references) //IL_051f: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Unknown result type (might be due to invalid IL or missing references) //IL_052d: Unknown result type (might be due to invalid IL or missing references) //IL_0540: Unknown result type (might be due to invalid IL or missing references) //IL_0547: Unknown result type (might be due to invalid IL or missing references) //IL_054e: Unknown result type (might be due to invalid IL or missing references) //IL_0561: Unknown result type (might be due to invalid IL or missing references) //IL_0568: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_05dd: Unknown result type (might be due to invalid IL or missing references) //IL_05e4: Unknown result type (might be due to invalid IL or missing references) //IL_05eb: Unknown result type (might be due to invalid IL or missing references) //IL_05f2: Unknown result type (might be due to invalid IL or missing references) //IL_05f9: Unknown result type (might be due to invalid IL or missing references) //IL_0600: Unknown result type (might be due to invalid IL or missing references) //IL_0615: Unknown result type (might be due to invalid IL or missing references) //IL_0617: Unknown result type (might be due to invalid IL or missing references) //IL_0619: Unknown result type (might be due to invalid IL or missing references) combinedRegionIds = new HashSet(terrainResult.RegionIds); combinedRegionIds.UnionWith(pieceResult.RegionIds); combinedCentroids = new Dictionary(terrainResult.Centroids); foreach (KeyValuePair centroid in pieceResult.Centroids) { combinedCentroids[centroid.Key] = centroid.Value; } combinedLinks = new List(terrainResult.Links.Count + pieceResult.Links.Count); combinedLinks.AddRange(terrainResult.Links); combinedLinks.AddRange(pieceResult.Links); combinedLookup = new Dictionary(terrainResult.LookupGrid); foreach (KeyValuePair item2 in pieceResult.LookupGrid) { combinedLookup[item2.Key] = item2.Value; } float num = 1f; Dictionary> pieceYsByXz = new Dictionary>(); foreach (CachedTriangle triangle in pieceResult.Triangles) { Vector3 v = triangle.V0; Vector3 v2 = triangle.V1; Vector3 v3 = triangle.V2; float num2 = Mathf.Min(v.x, Mathf.Min(v2.x, v3.x)); float num3 = Mathf.Max(v.x, Mathf.Max(v2.x, v3.x)); float num4 = Mathf.Min(v.z, Mathf.Min(v2.z, v3.z)); float num5 = Mathf.Max(v.z, Mathf.Max(v2.z, v3.z)); int num6 = Mathf.FloorToInt(num2 / num); int num7 = Mathf.FloorToInt(num3 / num); int num8 = Mathf.FloorToInt(num4 / num); int num9 = Mathf.FloorToInt(num5 / num); for (int i = num6; i <= num7; i++) { for (int j = num8; j <= num9; j++) { float px = ((float)i + 0.5f) * num; float pz = ((float)j + 0.5f) * num; if (PointInTri2D(px, pz, v.x, v.z, v2.x, v2.z, v3.x, v3.z)) { float item = InterpHeight(px, pz, v, v2, v3); long key = (long)i * 1000003L + j; if (!pieceYsByXz.TryGetValue(key, out var value)) { value = (pieceYsByXz[key] = new List()); } value.Add(item); } } } } List list2 = new List(); bool flag = (Object)(object)ZoneSystem.instance != (Object)null; foreach (KeyValuePair item3 in terrainResult.LookupGrid) { RegionGraph.UnpackLookup(item3.Key, out var gx, out var gz, out var _); float num10 = ((float)gx + 0.5f) * num; float num11 = ((float)gz + 0.5f) * num; float terrainYAtCell = (flag ? ZoneSystem.instance.GetGroundHeight(new Vector3(num10, 0f, num11)) : 0f); if (IsTerrainFlushWithPieceAtCell(gx, gz, terrainYAtCell)) { list2.Add(item3.Key); } } HashSet regionIds = terrainResult.RegionIds; foreach (long item4 in list2) { if (combinedLookup.TryGetValue(item4, out var value2) && regionIds.Contains(value2)) { combinedLookup.Remove(item4); } } combinedBoundary = new List<(string, Vector3, Vector3)>(terrainResult.BoundaryCells.Count + pieceResult.BoundaryCells.Count); combinedBoundary.AddRange(terrainResult.BoundaryCells); combinedBoundary.AddRange(pieceResult.BoundaryCells); kindMap = new Dictionary(combinedRegionIds.Count); foreach (string regionId in terrainResult.RegionIds) { kindMap[regionId] = SurfaceKind.Terrain; } foreach (string regionId2 in pieceResult.RegionIds) { kindMap[regionId2] = SurfaceKind.Piece; } combinedTriangles = new List(terrainResult.Triangles.Count + pieceResult.Triangles.Count); HashSet hashSet = new HashSet(); int num12 = 0; foreach (CachedTriangle triangle2 in terrainResult.Triangles) { Vector3 v4 = triangle2.V0; Vector3 v5 = triangle2.V1; Vector3 v6 = triangle2.V2; float num13 = Mathf.Min(v4.x, Mathf.Min(v5.x, v6.x)); float num14 = Mathf.Max(v4.x, Mathf.Max(v5.x, v6.x)); float num15 = Mathf.Min(v4.z, Mathf.Min(v5.z, v6.z)); float num16 = Mathf.Max(v4.z, Mathf.Max(v5.z, v6.z)); int num17 = Mathf.FloorToInt(num13 / num); int num18 = Mathf.FloorToInt(num14 / num); int num19 = Mathf.FloorToInt(num15 / num); int num20 = Mathf.FloorToInt(num16 / num); bool flag2 = false; bool flag3 = false; for (int k = num17; k <= num18; k++) { if (flag2) { break; } for (int l = num19; l <= num20; l++) { if (flag2) { break; } float px2 = ((float)k + 0.5f) * num; float pz2 = ((float)l + 0.5f) * num; if (PointInTri2D(px2, pz2, v4.x, v4.z, v5.x, v5.z, v6.x, v6.z)) { flag3 = true; float terrainYAtCell2 = InterpHeight(px2, pz2, v4, v5, v6); if (!IsTerrainFlushWithPieceAtCell(k, l, terrainYAtCell2)) { flag2 = true; } } } } if (flag3 && !flag2) { num12++; continue; } combinedTriangles.Add(triangle2); if (!string.IsNullOrEmpty(triangle2.RegionId)) { hashSet.Add(triangle2.RegionId); } } combinedTriangles.AddRange(pieceResult.Triangles); CachedTriangles = combinedTriangles; int num21 = 0; int num22 = 0; HashSet hashSet2 = new HashSet(); foreach (string regionId3 in terrainResult.RegionIds) { if (!hashSet.Contains(regionId3)) { hashSet2.Add(regionId3); } } if (hashSet2.Count > 0) { num21 = hashSet2.Count; foreach (string item5 in hashSet2) { combinedRegionIds.Remove(item5); combinedCentroids.Remove(item5); kindMap.Remove(item5); } for (int num23 = combinedLinks.Count - 1; num23 >= 0; num23--) { RegionLink regionLink = combinedLinks[num23]; if (hashSet2.Contains(regionLink.FromRegionId) || hashSet2.Contains(regionLink.ToRegionId)) { combinedLinks.RemoveAt(num23); num22++; } } for (int num24 = combinedBoundary.Count - 1; num24 >= 0; num24--) { if (hashSet2.Contains(combinedBoundary[num24].Item1)) { combinedBoundary.RemoveAt(num24); } } } DebugLog.Event("RegionPartition", "shadow_suppression", ("terrain_cells", terrainResult.LookupGrid.Count), ("piece_cells", pieceResult.LookupGrid.Count), ("shadowed_cells_dropped", list2.Count), ("shadowed_tris_dropped", num12), ("cascaded_regions_dropped", num21), ("cascaded_links_dropped", num22), ("combined_cells", combinedLookup.Count)); bool IsTerrainFlushWithPieceAtCell(int num25, int num26, float num27) { long key2 = (long)num25 * 1000003L + num26; if (!pieceYsByXz.TryGetValue(key2, out var value3)) { return false; } for (int m = 0; m < value3.Count; m++) { if (Mathf.Abs(value3[m] - num27) < 0.3f) { return true; } } return false; } } internal static BuildResult BuildFromTriangulation(SurfaceKind kind, float minX, float minZ, float maxX, float maxZ, List anchors) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_034b: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_05a3: Unknown result type (might be due to invalid IL or missing references) //IL_05ab: Unknown result type (might be due to invalid IL or missing references) //IL_05b0: Unknown result type (might be due to invalid IL or missing references) //IL_05ba: Unknown result type (might be due to invalid IL or missing references) //IL_05bf: Unknown result type (might be due to invalid IL or missing references) //IL_05c0: Unknown result type (might be due to invalid IL or missing references) //IL_05ca: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_05d4: Unknown result type (might be due to invalid IL or missing references) //IL_05d6: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_05ec: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Unknown result type (might be due to invalid IL or missing references) //IL_07c2: Unknown result type (might be due to invalid IL or missing references) //IL_07c7: Unknown result type (might be due to invalid IL or missing references) //IL_07da: Unknown result type (might be due to invalid IL or missing references) //IL_090b: Unknown result type (might be due to invalid IL or missing references) //IL_0910: Unknown result type (might be due to invalid IL or missing references) //IL_0a4d: Unknown result type (might be due to invalid IL or missing references) //IL_092e: Unknown result type (might be due to invalid IL or missing references) //IL_093d: Unknown result type (might be due to invalid IL or missing references) //IL_094c: Unknown result type (might be due to invalid IL or missing references) //IL_095f: Unknown result type (might be due to invalid IL or missing references) //IL_0965: Unknown result type (might be due to invalid IL or missing references) //IL_096c: Unknown result type (might be due to invalid IL or missing references) //IL_0971: Unknown result type (might be due to invalid IL or missing references) //IL_0976: Unknown result type (might be due to invalid IL or missing references) //IL_09ab: Unknown result type (might be due to invalid IL or missing references) //IL_09af: Unknown result type (might be due to invalid IL or missing references) //IL_09a4: Unknown result type (might be due to invalid IL or missing references) //IL_09b4: Unknown result type (might be due to invalid IL or missing references) //IL_09cc: Unknown result type (might be due to invalid IL or missing references) //IL_0c4e: Unknown result type (might be due to invalid IL or missing references) //IL_0c53: Unknown result type (might be due to invalid IL or missing references) //IL_0c57: Unknown result type (might be due to invalid IL or missing references) //IL_0c97: Unknown result type (might be due to invalid IL or missing references) //IL_0c99: Unknown result type (might be due to invalid IL or missing references) //IL_0c9e: Unknown result type (might be due to invalid IL or missing references) //IL_0c77: Unknown result type (might be due to invalid IL or missing references) //IL_0c86: Unknown result type (might be due to invalid IL or missing references) //IL_0cd1: Unknown result type (might be due to invalid IL or missing references) //IL_0f6f: Unknown result type (might be due to invalid IL or missing references) //IL_0f74: Unknown result type (might be due to invalid IL or missing references) //IL_0f80: Unknown result type (might be due to invalid IL or missing references) //IL_0f85: Unknown result type (might be due to invalid IL or missing references) //IL_0f91: Unknown result type (might be due to invalid IL or missing references) //IL_0f96: Unknown result type (might be due to invalid IL or missing references) //IL_0fa4: Unknown result type (might be due to invalid IL or missing references) //IL_0fa6: Unknown result type (might be due to invalid IL or missing references) //IL_0fad: Unknown result type (might be due to invalid IL or missing references) //IL_0faf: Unknown result type (might be due to invalid IL or missing references) //IL_0fb6: Unknown result type (might be due to invalid IL or missing references) //IL_0fb8: Unknown result type (might be due to invalid IL or missing references) //IL_0ff0: Unknown result type (might be due to invalid IL or missing references) //IL_0ff7: Unknown result type (might be due to invalid IL or missing references) //IL_0ffe: Unknown result type (might be due to invalid IL or missing references) //IL_1011: Unknown result type (might be due to invalid IL or missing references) //IL_1018: Unknown result type (might be due to invalid IL or missing references) //IL_101f: Unknown result type (might be due to invalid IL or missing references) //IL_1110: Unknown result type (might be due to invalid IL or missing references) //IL_1121: Unknown result type (might be due to invalid IL or missing references) //IL_1132: Unknown result type (might be due to invalid IL or missing references) //IL_1150: Unknown result type (might be due to invalid IL or missing references) //IL_1161: Unknown result type (might be due to invalid IL or missing references) //IL_1172: Unknown result type (might be due to invalid IL or missing references) //IL_1190: Unknown result type (might be due to invalid IL or missing references) //IL_11a1: Unknown result type (might be due to invalid IL or missing references) //IL_11b2: Unknown result type (might be due to invalid IL or missing references) //IL_1046: Unknown result type (might be due to invalid IL or missing references) //IL_1048: Unknown result type (might be due to invalid IL or missing references) //IL_104f: Unknown result type (might be due to invalid IL or missing references) //IL_1051: Unknown result type (might be due to invalid IL or missing references) //IL_105a: Unknown result type (might be due to invalid IL or missing references) //IL_105c: Unknown result type (might be due to invalid IL or missing references) //IL_0e1d: Unknown result type (might be due to invalid IL or missing references) //IL_0e25: Unknown result type (might be due to invalid IL or missing references) //IL_0e2a: Unknown result type (might be due to invalid IL or missing references) //IL_0e32: Unknown result type (might be due to invalid IL or missing references) //IL_0e37: Unknown result type (might be due to invalid IL or missing references) //IL_0e41: Unknown result type (might be due to invalid IL or missing references) //IL_0e46: Unknown result type (might be due to invalid IL or missing references) //IL_0e4b: Unknown result type (might be due to invalid IL or missing references) //IL_0e53: Unknown result type (might be due to invalid IL or missing references) //IL_0e58: Unknown result type (might be due to invalid IL or missing references) //IL_0e60: Unknown result type (might be due to invalid IL or missing references) //IL_0e65: Unknown result type (might be due to invalid IL or missing references) //IL_0e6f: Unknown result type (might be due to invalid IL or missing references) //IL_0e74: Unknown result type (might be due to invalid IL or missing references) //IL_0ea0: Unknown result type (might be due to invalid IL or missing references) //IL_0ea2: Unknown result type (might be due to invalid IL or missing references) //IL_0ea9: Unknown result type (might be due to invalid IL or missing references) //IL_0eab: Unknown result type (might be due to invalid IL or missing references) BuildResult result = new BuildResult { RegionIds = new HashSet(), Centroids = new Dictionary(), Links = new List(), LookupGrid = new Dictionary(), BoundaryCells = new List<(string, Vector3, Vector3)>(), Triangles = new List(), Kind = kind, Adjacency = new Dictionary>(), RegionVertexPositions = new Dictionary>(), RegionBounds = new Dictionary(), RegionVertexList = new Dictionary>() }; if (anchors == null || anchors.Count == 0) { return result; } int agentTypeID = (VillagerAgentType.IsRegistered ? VillagerAgentType.UnityAgentTypeID : VillagerAgentType.ResolveValheimHumanoidAgentTypeID()); NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = agentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; var (array, array2, array3) = NavMeshBakeManager.ExtractBakedTriangles(kind, minX, minZ, maxX, maxZ); if (array == null || array2 == null || array2.Length < 3) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[Region] No baked sources to extract triangles from (kind={kind}) — has NavMeshBakeManager.BakeVillage run?"); } return result; } int num = array2.Length / 3; List list = new List(); Vector3[] array4 = (Vector3[])(object)new Vector3[num]; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; NavMeshHit val10 = default(NavMeshHit); for (int i = 0; i < num; i++) { Vector3 val3 = array[array2[i * 3]]; Vector3 val4 = array[array2[i * 3 + 1]]; Vector3 val5 = array[array2[i * 3 + 2]]; Vector3 val6 = (array4[i] = (val3 + val4 + val5) / 3f); Vector3 val7 = Vector3.Cross(val4 - val3, val5 - val3); Vector3 normalized = ((Vector3)(ref val7)).normalized; if (normalized.y < 0.5f) { num2++; continue; } if (normalized.y < 0.891007f) { num6++; continue; } if (val6.x < minX || val6.x > maxX || val6.z < minZ || val6.z > maxZ) { num3++; continue; } if (kind == SurfaceKind.Terrain) { Vector3 val8 = val6 + Vector3.up * 0.45f; Vector3 val9 = val6 + Vector3.up * 1.4499999f; if (Physics.CheckCapsule(val8, val9, 0.2f, s_blockMask)) { num7++; continue; } } else if (Physics.CheckSphere(val6 + Vector3.up * 1f, 0.1f, s_blockMask, (QueryTriggerInteraction)1)) { num7++; continue; } if (!NavMesh.SamplePosition(val6, ref val10, 0.5f, val2) || Vector3.Distance(((NavMeshHit)(ref val10)).position, val6) > 0.5f) { num4++; } else if (IsAnyVertexBelowTerrain(val3, val4, val5)) { num5++; } else { list.Add(i); } } List list2 = new List(list.Count); HashSet<(int, int, int)> hashSet = new HashSet<(int, int, int)>(); foreach (int item3 in list) { Vector3 val11 = array4[item3]; (int, int, int) item = (Mathf.RoundToInt(val11.x * 100f), Mathf.RoundToInt(val11.y * 100f), Mathf.RoundToInt(val11.z * 100f)); if (hashSet.Add(item)) { list2.Add(item3); } } int num8 = list.Count - list2.Count; DebugLog.Event("Region", "triangulation", ("kind", kind), ("total", num), ("filtered", list.Count), ("accepted", list2.Count), ("rej_normal", num2), ("rej_bounds", num3), ("rej_agent", num4), ("rej_terrain", num5), ("rej_steep", num6), ("rej_blocked", num7), ("rej_dedup", num8)); if (list2.Count == 0) { return result; } Dictionary> dictionary = new Dictionary>(); foreach (int item4 in list2) { int num9 = array2[item4 * 3]; int num10 = array2[item4 * 3 + 1]; int num11 = array2[item4 * 3 + 2]; AddEdge(dictionary, num9, num10, item4); AddEdge(dictionary, num10, num11, item4); AddEdge(dictionary, num11, num9, item4); } int num12 = 0; if (kind == SurfaceKind.Terrain) { List list3 = new List(); foreach (KeyValuePair> item5 in dictionary) { long key = item5.Key; int num13 = (int)(key >> 32); int num14 = (int)(key & 0xFFFFFFFFu); Vector3 val12 = (array[num13] + array[num14]) * 0.5f; Vector3 val13 = val12 + Vector3.up * 0.45f; Vector3 val14 = val12 + Vector3.up * 1.4499999f; if (Physics.CheckCapsule(val13, val14, 0.2f, s_blockMask)) { list3.Add(key); } } foreach (long item6 in list3) { dictionary.Remove(item6); } num12 = list3.Count; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)($"[Region] Edge-midpoint capsule break (kind={kind}): " + $"removed {num12}/{num12 + dictionary.Count} edges " + $"({100f * (float)num12 / (float)Mathf.Max(1, num12 + dictionary.Count):F1}%)")); } } int[] array5 = new int[num]; int[] rank = new int[num]; foreach (int item7 in list2) { array5[item7] = item7; } foreach (List value15 in dictionary.Values) { for (int j = 0; j < value15.Count; j++) { for (int k = j + 1; k < value15.Count; k++) { Union(array5, rank, value15[j], value15[k]); } } } Dictionary> dictionary2 = new Dictionary>(); foreach (int item8 in list2) { int root = Find(array5, item8); Vector3 val15 = array4[item8]; int gx = Mathf.FloorToInt(val15.x / 3f); int gz = Mathf.FloorToInt(val15.z / 3f); int hb = Mathf.FloorToInt(val15.y / 2f); long key2 = PackGroup(root, gx, gz, hb); if (!dictionary2.TryGetValue(key2, out var value)) { value = (dictionary2[key2] = new List()); } value.Add(item8); } ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[Region] Components → {dictionary2.Count} regions (kind={kind}, subdiv {3f}m)"); } int num15 = 0; string arg = ((kind == SurfaceKind.Terrain) ? "t" : "p"); Dictionary dictionary3 = new Dictionary(); Dictionary dictionary4 = new Dictionary(); foreach (KeyValuePair> item9 in dictionary2) { string text = $"{arg}{num15++}"; List value2 = item9.Value; if (value2.Count > 0) { dictionary4[text] = Find(array5, value2[0]); } float num16 = 0f; Vector3 val16 = Vector3.zero; foreach (int item10 in value2) { float num17 = TriArea(array[array2[item10 * 3]], array[array2[item10 * 3 + 1]], array[array2[item10 * 3 + 2]]); num16 += num17; val16 += array4[item10] * num17; } Vector3 value3 = ((num16 > 0.001f) ? (val16 / num16) : array4[value2[0]]); result.RegionIds.Add(text); result.Centroids[text] = value3; foreach (int item11 in value2) { dictionary3[item11] = text; } } MergeCoplanarRegions(list2, array2, array, array4, dictionary3, result, dictionary4); PruneSmallRegions(list2, array2, array, dictionary3, result); PruneNarrowRegions(list2, array2, array, dictionary3, result, val2); PruneEnclosedRegions(list2, array2, array, dictionary3, result); if (kind == SurfaceKind.Terrain) { PruneIsolatedSmallTerrain(list2, array2, array, dictionary, dictionary3, result); } foreach (string regionId in result.RegionIds) { result.Adjacency[regionId] = new HashSet(); } foreach (List value16 in dictionary.Values) { string text2 = null; HashSet hashSet2 = null; foreach (int item12 in value16) { if (!dictionary3.TryGetValue(item12, out var value4)) { continue; } if (text2 == null) { text2 = value4; } else if (!(value4 == text2)) { if (hashSet2 == null) { hashSet2 = new HashSet { text2 }; } hashSet2.Add(value4); } } if (hashSet2 == null) { continue; } List list5 = new List(hashSet2); for (int l = 0; l < list5.Count; l++) { for (int m = l + 1; m < list5.Count; m++) { if (result.Adjacency.TryGetValue(list5[l], out var value5)) { value5.Add(list5[m]); } if (result.Adjacency.TryGetValue(list5[m], out var value6)) { value6.Add(list5[l]); } } } } foreach (int item13 in list2) { if (!dictionary3.TryGetValue(item13, out var value7)) { continue; } if (!result.RegionVertexPositions.TryGetValue(value7, out var value8)) { value8 = new HashSet(); result.RegionVertexPositions[value7] = value8; } for (int n = 0; n < 3; n++) { Vector3 val17 = array[array2[item13 * 3 + n]]; value8.Add(PackQuantizedPos(val17)); if (result.RegionBounds.TryGetValue(value7, out var value9)) { ((Bounds)(ref value9)).Encapsulate(val17); result.RegionBounds[value7] = value9; } else { result.RegionBounds[value7] = new Bounds(val17, Vector3.zero); } if (!result.RegionVertexList.TryGetValue(value7, out var value10)) { value10 = new List(); result.RegionVertexList[value7] = value10; } value10.Add(val17); } } HashSet hashSet3 = new HashSet(); foreach (KeyValuePair> item14 in dictionary) { List value11 = item14.Value; for (int num18 = 0; num18 < value11.Count; num18++) { for (int num19 = num18 + 1; num19 < value11.Count; num19++) { if (dictionary3.TryGetValue(value11[num18], out var value12) && dictionary3.TryGetValue(value11[num19], out var value13) && !(value12 == value13)) { string item2 = ((string.CompareOrdinal(value12, value13) < 0) ? (value12 + "|" + value13) : (value13 + "|" + value12)); if (hashSet3.Add(item2)) { int num20 = array2[value11[num18] * 3]; int num21 = array2[value11[num18] * 3 + 1]; int num22 = array2[value11[num18] * 3 + 2]; int num23 = array2[value11[num19] * 3]; int num24 = array2[value11[num19] * 3 + 1]; int num25 = array2[value11[num19] * 3 + 2]; Vector3 positionStart = (array[num20] + array[num21] + array[num22]) / 3f; Vector3 positionEnd = (array[num23] + array[num24] + array[num25]) / 3f; result.Links.Add(new RegionLink { FromRegionId = value12, ToRegionId = value13, LinkType = RegionLinkType.Slope, PositionStart = positionStart, PositionEnd = positionEnd }); } } } } } DetectBoundary(dictionary, dictionary3, array2, array, result); BuildLookupGrid(list2, array2, array, dictionary3, result); List triangles = result.Triangles; triangles.Capacity = list2.Count; float num26 = float.MaxValue; float num27 = float.MinValue; float num28 = 0f; foreach (int item15 in list2) { if (dictionary3.TryGetValue(item15, out var value14)) { Vector3 val18 = array[array2[item15 * 3]]; Vector3 val19 = array[array2[item15 * 3 + 1]]; Vector3 val20 = array[array2[item15 * 3 + 2]]; triangles.Add(new CachedTriangle { V0 = val18, V1 = val19, V2 = val20, RegionId = value14, Kind = kind, Layer = ((array3 != null && item15 < array3.Length) ? array3[item15] : (-1)) }); float num29 = Mathf.Min(val18.y, Mathf.Min(val19.y, val20.y)); float num30 = Mathf.Max(val18.y, Mathf.Max(val19.y, val20.y)); if (num29 < num26) { num26 = num29; } if (num30 > num27) { num27 = num30; } float num31 = Vector3.Distance(val18, val19); float num32 = Vector3.Distance(val19, val20); float num33 = Vector3.Distance(val20, val18); float num34 = Mathf.Max(num31, Mathf.Max(num32, num33)); if (num34 > num28) { num28 = num34; } } } if (triangles.Count > 0) { CachedTriangle cachedTriangle = triangles[0]; ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)($"[Region] TriCache (kind={kind}): {triangles.Count} tris, " + $"Y range [{num26:F1}, {num27:F1}], max edge {num28:F1}m. " + $"Sample tri: ({cachedTriangle.V0.x:F1},{cachedTriangle.V0.y:F1},{cachedTriangle.V0.z:F1}) " + $"({cachedTriangle.V1.x:F1},{cachedTriangle.V1.y:F1},{cachedTriangle.V1.z:F1}) " + $"({cachedTriangle.V2.x:F1},{cachedTriangle.V2.y:F1},{cachedTriangle.V2.z:F1})")); } } ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)($"[Region] Built {result.RegionIds.Count} regions (kind={kind}), " + $"{result.Links.Count} links, {result.LookupGrid.Count} lookup cells, " + $"{result.BoundaryCells.Count} boundary regions")); } return result; } internal static void CollectDoorLinks(RegionGraph graph, float minX, float minZ, float maxX, float maxZ, List links) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) Door[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); if (array == null || graph == null) { return; } float num = 1.8000001f; int num2 = 0; Door[] array2 = array; foreach (Door val in array2) { if ((Object)(object)val == (Object)null) { continue; } Vector3 position = ((Component)val).transform.position; if (position.x < minX - 3f || position.x > maxX + 3f || position.z < minZ - 3f || position.z > maxZ + 3f || (Object)(object)((Component)val).GetComponentInParent() == (Object)null) { continue; } Vector3 forward = ((Component)val).transform.forward; forward.y = 0f; if (!(((Vector3)(ref forward)).sqrMagnitude < 0.01f)) { ((Vector3)(ref forward)).Normalize(); Vector3 val2 = position - forward * num; Vector3 val3 = position + forward * num; string text = graph.PointToRegionId(val2); string text2 = graph.PointToRegionId(val3); if (text != null && text2 != null && !(text == text2)) { num2++; links.Add(new RegionLink { FromRegionId = text, ToRegionId = text2, LinkType = RegionLinkType.Door, PositionStart = val2, PositionEnd = val3 }); } } } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Region] Door links: {num2} added"); } } private static void MergeCoplanarRegions(List accepted, int[] idx, Vector3[] verts, Vector3[] triCentroids, Dictionary triToRegion, BuildResult result, Dictionary regionToComponentRoot) { //IL_0127: 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_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0485: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_04b4: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04c5: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_050c: Unknown result type (might be due to invalid IL or missing references) //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); foreach (int item in accepted) { if (triToRegion.TryGetValue(item, out var value)) { float y = verts[idx[item * 3]].y; float y2 = verts[idx[item * 3 + 1]].y; float y3 = verts[idx[item * 3 + 2]].y; float num = Mathf.Min(y, Mathf.Min(y2, y3)); float num2 = Mathf.Max(y, Mathf.Max(y2, y3)); if (dictionary.TryGetValue(value, out var value2)) { dictionary[value] = (Mathf.Min(num, value2.Item1), Mathf.Max(num2, value2.Item2)); } else { dictionary[value] = (num, num2); } } } Dictionary<(int, int, int), HashSet> dictionary2 = new Dictionary<(int, int, int), HashSet>(); foreach (int item2 in accepted) { if (!triToRegion.TryGetValue(item2, out var value3)) { continue; } for (int i = 0; i < 3; i++) { Vector3 val = verts[idx[item2 * 3 + i]]; (int, int, int) key = (Mathf.RoundToInt(val.x / 0.05f), Mathf.RoundToInt(val.y / 0.05f), Mathf.RoundToInt(val.z / 0.05f)); if (!dictionary2.TryGetValue(key, out var value4)) { value4 = (dictionary2[key] = new HashSet()); } value4.Add(value3); } } Dictionary dictionary3 = new Dictionary(); foreach (string regionId in result.RegionIds) { dictionary3[regionId] = regionId; } foreach (HashSet value12 in dictionary2.Values) { if (value12.Count < 2) { continue; } List list = new List(value12); for (int j = 0; j < list.Count; j++) { for (int k = j + 1; k < list.Count; k++) { string text = FindRoot(dictionary3, list[j]); string text2 = FindRoot(dictionary3, list[k]); if (!(text == text2) && (result.Kind != SurfaceKind.Terrain || !regionToComponentRoot.TryGetValue(text, out var value5) || !regionToComponentRoot.TryGetValue(text2, out var value6) || value5 == value6) && dictionary.TryGetValue(text, out var value7) && dictionary.TryGetValue(text2, out var value8)) { float num3 = Mathf.Min(value7.Item1, value8.Item1); float num4 = Mathf.Max(value7.Item2, value8.Item2); if (!(num4 - num3 > 1.5f)) { dictionary3[text2] = text; dictionary[text] = (num3, num4); } } } } } int num5 = 0; foreach (int item3 in accepted) { if (triToRegion.TryGetValue(item3, out var value9)) { string text3 = FindRoot(dictionary3, value9); if (text3 != value9) { triToRegion[item3] = text3; num5++; } } } if (num5 == 0) { return; } result.RegionIds.Clear(); result.Centroids.Clear(); Dictionary> dictionary4 = new Dictionary>(); foreach (int item4 in accepted) { if (triToRegion.TryGetValue(item4, out var value10)) { if (!dictionary4.TryGetValue(value10, out var value11)) { value11 = (dictionary4[value10] = new List()); } value11.Add(item4); } } foreach (KeyValuePair> item5 in dictionary4) { string key2 = item5.Key; result.RegionIds.Add(key2); float num6 = 0f; Vector3 val2 = Vector3.zero; foreach (int item6 in item5.Value) { float num7 = TriArea(verts[idx[item6 * 3]], verts[idx[item6 * 3 + 1]], verts[idx[item6 * 3 + 2]]); num6 += num7; val2 += triCentroids[item6] * num7; } result.Centroids[key2] = ((num6 > 0.001f) ? (val2 / num6) : triCentroids[item5.Value[0]]); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Region] Coplanar merge: {num5} tris reassigned, " + $"{dictionary4.Count} regions after merge")); } } private static void PruneSmallRegions(List accepted, int[] idx, Vector3[] verts, Dictionary triToRegion, BuildResult result) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0139: Unknown result type (might be due to invalid IL or missing references) Dictionary regionArea = new Dictionary(); foreach (int item in accepted) { if (triToRegion.TryGetValue(item, out var value)) { float num = TriArea(verts[idx[item * 3]], verts[idx[item * 3 + 1]], verts[idx[item * 3 + 2]]); if (regionArea.TryGetValue(value, out var value2)) { regionArea[value] = value2 + num; } else { regionArea[value] = num; } } } HashSet hashSet = new HashSet(); foreach (KeyValuePair item2 in regionArea) { if (item2.Value < 0.25f) { hashSet.Add(item2.Key); } } if (hashSet.Count == 0) { return; } Dictionary dictionary = new Dictionary(); foreach (string item3 in hashSet) { if (result.Centroids.TryGetValue(item3, out var value3)) { dictionary[item3] = value3; } } foreach (string item4 in hashSet) { result.RegionIds.Remove(item4); result.Centroids.Remove(item4); } List list = new List(); foreach (KeyValuePair item5 in triToRegion) { if (hashSet.Contains(item5.Value)) { list.Add(item5.Key); } } foreach (int item6 in list) { triToRegion.Remove(item6); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Region] Area pruning: dropped {hashSet.Count} regions < {0.25f}m², " + $"{result.RegionIds.Count} regions remaining")); } DebugLog.List("RegionPrune", "area_dropped", ((IEnumerable>)dictionary).Select((Func, object>)((KeyValuePair kv) => $"{kv.Key}:{kv.Value.x:F1},{kv.Value.y:F1},{kv.Value.z:F1}:area={regionArea[kv.Key]:F2}"))); } private static void PruneNarrowRegions(List accepted, int[] idx, Vector3[] verts, Dictionary triToRegion, BuildResult result, NavMeshQueryFilter filter) { //IL_0030: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00dd: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); NavMeshHit val = default(NavMeshHit); foreach (string regionId in result.RegionIds) { if (result.Centroids.TryGetValue(regionId, out var value) && NavMesh.FindClosestEdge(value, ref val, filter) && ((NavMeshHit)(ref val)).distance < 0f) { hashSet.Add(regionId); } } if (hashSet.Count == 0) { return; } List list = new List(); NavMeshHit val2 = default(NavMeshHit); foreach (string item in hashSet) { if (result.Centroids.TryGetValue(item, out var value2)) { NavMesh.FindClosestEdge(value2, ref val2, filter); list.Add($"{item}:{value2.x:F1},{value2.y:F1},{value2.z:F1}:edge={((NavMeshHit)(ref val2)).distance:F3}"); } } foreach (string item2 in hashSet) { result.RegionIds.Remove(item2); result.Centroids.Remove(item2); } List list2 = new List(); foreach (KeyValuePair item3 in triToRegion) { if (hashSet.Contains(item3.Value)) { list2.Add(item3.Key); } } foreach (int item4 in list2) { triToRegion.Remove(item4); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Region] Narrow pruning: dropped {hashSet.Count} regions " + $"(edge dist < {0f}m), " + $"{result.RegionIds.Count} regions remaining")); } DebugLog.List("RegionPrune", "narrow_dropped", list); } private static void PruneEnclosedRegions(List accepted, int[] idx, Vector3[] verts, Dictionary triToRegion, BuildResult result) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0055: 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_005d: 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_0077: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); foreach (int item in accepted) { if (triToRegion.TryGetValue(item, out var value)) { Vector3 val = verts[idx[item * 3]]; Vector3 val2 = verts[idx[item * 3 + 1]]; Vector3 val3 = verts[idx[item * 3 + 2]]; float num = Mathf.Min(val.x, Mathf.Min(val2.x, val3.x)); float num2 = Mathf.Max(val.x, Mathf.Max(val2.x, val3.x)); float num3 = Mathf.Min(val.z, Mathf.Min(val2.z, val3.z)); float num4 = Mathf.Max(val.z, Mathf.Max(val2.z, val3.z)); float num5 = Mathf.Min(val.y, Mathf.Min(val2.y, val3.y)); float num6 = Mathf.Max(val.y, Mathf.Max(val2.y, val3.y)); if (dictionary.TryGetValue(value, out var value2)) { dictionary[value] = (Mathf.Min(num5, value2.Item1), Mathf.Max(num6, value2.Item2), Mathf.Min(num, value2.Item3), Mathf.Max(num2, value2.Item4), Mathf.Min(num3, value2.Item5), Mathf.Max(num4, value2.Item6)); } else { dictionary[value] = (num5, num6, num, num2, num3, num4); } } } HashSet hashSet = new HashSet(); List list = new List(dictionary.Keys); for (int i = 0; i < list.Count; i++) { (float, float, float, float, float, float) tuple = dictionary[list[i]]; if (tuple.Item2 - tuple.Item1 >= 0.2f) { continue; } float num7 = (tuple.Item1 + tuple.Item2) * 0.5f; for (int j = 0; j < list.Count; j++) { if (i == j || hashSet.Contains(list[j])) { continue; } (float, float, float, float, float, float) tuple2 = dictionary[list[j]]; if (!(tuple2.Item2 - tuple2.Item1 >= 0.2f)) { float num8 = (tuple2.Item1 + tuple2.Item2) * 0.5f; if (!(num7 > num8) && !(num8 - num7 > 0.5f) && !(tuple.Item3 > tuple2.Item3) && !(tuple.Item4 < tuple2.Item4) && !(tuple.Item5 > tuple2.Item5) && !(tuple.Item6 < tuple2.Item6)) { hashSet.Add(list[j]); } } } } if (hashSet.Count == 0) { return; } List list2 = new List(); foreach (string item2 in hashSet) { if (result.Centroids.TryGetValue(item2, out var value3)) { list2.Add($"{item2}:{value3.x:F1},{value3.y:F1},{value3.z:F1}"); } } foreach (string item3 in hashSet) { result.RegionIds.Remove(item3); result.Centroids.Remove(item3); } List list3 = new List(); foreach (KeyValuePair item4 in triToRegion) { if (hashSet.Contains(item4.Value)) { list3.Add(item4.Key); } } foreach (int item5 in list3) { triToRegion.Remove(item5); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Region] Enclosure pruning: dropped {hashSet.Count} regions enclosed by " + $"larger coplanar regions, {result.RegionIds.Count} remaining")); } DebugLog.List("RegionPrune", "enclosed_dropped", list2); } private static string FindRoot(Dictionary parent, string id) { while (parent[id] != id) { parent[id] = parent[parent[id]]; id = parent[id]; } return id; } internal static long PackQuantizedPos(Vector3 v) { //IL_0000: 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_0025: Unknown result type (might be due to invalid IL or missing references) long num = Mathf.RoundToInt(v.x / 0.25f); long num2 = Mathf.RoundToInt(v.y / 0.25f); long num3 = Mathf.RoundToInt(v.z / 0.25f); return (((num + 1048576) & 0x1FFFFF) << 42) | (((num2 + 1048576) & 0x1FFFFF) << 21) | ((num3 + 1048576) & 0x1FFFFF); } private static void PruneIsolatedSmallTerrain(List accepted, int[] idx, Vector3[] verts, Dictionary> edgeToTris, Dictionary triToRegion, BuildResult result) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); foreach (List value5 in edgeToTris.Values) { string text = null; foreach (int item in value5) { if (triToRegion.TryGetValue(item, out var value)) { if (text == null) { text = value; } else if (value != text) { hashSet.Add(text); hashSet.Add(value); } } } } Dictionary dictionary = new Dictionary(); foreach (int item2 in accepted) { if (triToRegion.TryGetValue(item2, out var value2)) { float num = TriArea(verts[idx[item2 * 3]], verts[idx[item2 * 3 + 1]], verts[idx[item2 * 3 + 2]]); if (dictionary.TryGetValue(value2, out var value3)) { dictionary[value2] = value3 + num; } else { dictionary[value2] = num; } } } HashSet hashSet2 = new HashSet(); List list = new List(); foreach (KeyValuePair item3 in dictionary) { if (!(item3.Value >= 16f) && !hashSet.Contains(item3.Key)) { hashSet2.Add(item3.Key); if (result.Centroids.TryGetValue(item3.Key, out var value4)) { list.Add($"{item3.Key}:{value4.x:F1},{value4.y:F1},{value4.z:F1}:area={item3.Value:F2}"); } } } if (hashSet2.Count == 0) { return; } foreach (string item4 in hashSet2) { result.RegionIds.Remove(item4); result.Centroids.Remove(item4); } List list2 = new List(); foreach (KeyValuePair item5 in triToRegion) { if (hashSet2.Contains(item5.Value)) { list2.Add(item5.Key); } } foreach (int item6 in list2) { triToRegion.Remove(item6); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Region] Isolated terrain pruning: dropped {hashSet2.Count} regions " + $"(<{16f}m², no shared edges), " + $"{result.RegionIds.Count} regions remaining")); } DebugLog.List("RegionPrune", "isolated_terrain_dropped", list); } private static bool IsAnyVertexBelowTerrain(Vector3 v0, Vector3 v1, Vector3 v2) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!IsVertexBelowTerrain(v0) && !IsVertexBelowTerrain(v1)) { return IsVertexBelowTerrain(v2); } return true; } private static bool IsVertexBelowTerrain(Vector3 v) { //IL_0014: 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_003a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } float groundHeight = ZoneSystem.instance.GetGroundHeight(new Vector3(v.x, 0f, v.z)); if (groundHeight == 0f) { return false; } return v.y < groundHeight - 1.5f; } private static long EdgeKey(int a, int b) { if (a >= b) { return ((long)b << 32) | (uint)a; } return ((long)a << 32) | (uint)b; } private static void AddEdge(Dictionary> map, int v1, int v2, int tri) { long key = EdgeKey(v1, v2); if (!map.TryGetValue(key, out var value)) { value = (map[key] = new List(2)); } value.Add(tri); } private static int Find(int[] parent, int x) { while (parent[x] != x) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; } private static void Union(int[] parent, int[] rank, int a, int b) { int num = Find(parent, a); int num2 = Find(parent, b); if (num != num2) { if (rank[num] < rank[num2]) { parent[num] = num2; return; } if (rank[num] > rank[num2]) { parent[num2] = num; return; } parent[num2] = num; rank[num]++; } } private static long PackGroup(int root, int gx, int gz, int hb) { return ((long)root * 1000003L + gx) * 1000003 * 1000003 + (long)gz * 1000003L + hb; } private static float TriArea(Vector3 a, Vector3 b, Vector3 c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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) Vector3 val = Vector3.Cross(b - a, c - a); return ((Vector3)(ref val)).magnitude * 0.5f; } internal static bool PointInTri2D(float px, float pz, float ax, float az, float bx, float bz, float cx, float cz) { float num = (px - bx) * (az - bz) - (ax - bx) * (pz - bz); float num2 = (px - cx) * (bz - cz) - (bx - cx) * (pz - cz); float num3 = (px - ax) * (cz - az) - (cx - ax) * (pz - az); if (num < 0f || num2 < 0f || num3 < 0f) { if (!(num > 0f) && !(num2 > 0f)) { return !(num3 > 0f); } return false; } return true; } internal static float InterpHeight(float px, float pz, Vector3 a, Vector3 b, Vector3 c) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00d6: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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) float num = (b.z - c.z) * (a.x - c.x) + (c.x - b.x) * (a.z - c.z); if (Mathf.Abs(num) < 0.0001f) { return (a.y + b.y + c.y) / 3f; } float num2 = ((b.z - c.z) * (px - c.x) + (c.x - b.x) * (pz - c.z)) / num; float num3 = ((c.z - a.z) * (px - c.x) + (a.x - c.x) * (pz - c.z)) / num; return num2 * a.y + num3 * b.y + (1f - num2 - num3) * c.y; } private static void DetectBoundary(Dictionary> edgeToTris, Dictionary triToRegion, int[] idx, Vector3[] verts, BuildResult result) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0146: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_017c: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) Vector3 val5 = default(Vector3); foreach (KeyValuePair> edgeToTri in edgeToTris) { List value = edgeToTri.Value; int num = 0; int num2 = -1; string text = null; foreach (int item2 in value) { if (triToRegion.TryGetValue(item2, out var value2)) { num++; num2 = item2; text = value2; } } if (num != 1 || text == null || num2 < 0) { continue; } int num3 = (int)(edgeToTri.Key >> 32); int num4 = (int)(edgeToTri.Key & 0xFFFFFFFFu); if (num3 >= 0 && num4 >= 0 && num3 < verts.Length && num4 < verts.Length) { Vector3 val = verts[num3]; Vector3 val2 = verts[num4]; Vector3 val3 = (val + val2) * 0.5f; Vector3 val4 = (verts[idx[num2 * 3]] + verts[idx[num2 * 3 + 1]] + verts[idx[num2 * 3 + 2]]) / 3f; ((Vector3)(ref val5))..ctor(0f - (val2.z - val.z), 0f, val2.x - val.x); if (val5.x * (val3.x - val4.x) + val5.z * (val3.z - val4.z) < 0f) { val5 = -val5; } Vector3 item = ((((Vector3)(ref val5)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref val5)).normalized : Vector3.forward); result.BoundaryCells.Add((text, val3, item)); } } } private static void BuildLookupGrid(List accepted, int[] indices, Vector3[] verts, Dictionary triToRegion, BuildResult result) { //IL_002e: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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) //IL_0053: 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_0061: 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_007b: 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_0095: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_0168: Unknown result type (might be due to invalid IL or missing references) float num = 1f; foreach (int item in accepted) { if (!triToRegion.TryGetValue(item, out var value)) { continue; } Vector3 val = verts[indices[item * 3]]; Vector3 val2 = verts[indices[item * 3 + 1]]; Vector3 val3 = verts[indices[item * 3 + 2]]; float num2 = Mathf.Min(val.x, Mathf.Min(val2.x, val3.x)); float num3 = Mathf.Max(val.x, Mathf.Max(val2.x, val3.x)); float num4 = Mathf.Min(val.z, Mathf.Min(val2.z, val3.z)); float num5 = Mathf.Max(val.z, Mathf.Max(val2.z, val3.z)); int num6 = Mathf.FloorToInt(num2 / num); int num7 = Mathf.FloorToInt(num3 / num); int num8 = Mathf.FloorToInt(num4 / num); int num9 = Mathf.FloorToInt(num5 / num); for (int i = num6; i <= num7; i++) { for (int j = num8; j <= num9; j++) { float px = ((float)i + 0.5f) * num; float pz = ((float)j + 0.5f) * num; if (PointInTri2D(px, pz, val.x, val.z, val2.x, val2.z, val3.x, val3.z)) { int hb = RegionGraph.HeightBucket(InterpHeight(px, pz, val, val2, val3)); long key = RegionGraph.PackLookup(i, j, hb); result.LookupGrid[key] = value; } } } } } } public static class RegionDebugVisualization { private const string LinkTorchPrefabName = "piece_groundtorch_mist"; private const string RegionTorchPrefabName = "piece_groundtorch_wood"; [DevCommand("Remove ALL persisted torch markers from the world", Name = "vv_hna_cleanup")] public static void CleanupPersistedMarkers() { if ((Object)(object)ZNetScene.instance == (Object)null) { Console instance = Console.instance; if (instance != null) { instance.Print("ZNetScene not available. Load into a world first."); } return; } string text = "piece_groundtorch_mist(Clone)"; string text2 = "piece_groundtorch_wood(Clone)"; ZNetView[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); int num = 0; ZNetView[] array2 = array; foreach (ZNetView val in array2) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } string name = ((Object)((Component)val).gameObject).name; if (name != text && name != text2 && name != "piece_groundtorch_mist" && name != "piece_groundtorch_wood") { continue; } if (val.IsValid()) { if (!val.IsOwner()) { ZDO zDO = val.GetZDO(); if (zDO != null) { zDO.SetOwner(ZDOMan.GetSessionID()); } } ZNetScene.instance.Destroy(((Component)val).gameObject); } else { Object.Destroy((Object)(object)((Component)val).gameObject); } num++; } Console instance2 = Console.instance; if (instance2 != null) { instance2.Print($"Cleaned up {num} torch marker(s). Save to persist."); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Region] Torch cleanup: {num} removed"); } } } public enum SurfaceKind { Terrain, Piece } public enum RegionLinkType { Door, Stair, Slope } public struct RegionLink { public string FromRegionId; public string ToRegionId; public RegionLinkType LinkType; public Vector3 PositionStart; public Vector3 PositionEnd; } public class RegionGraph { public readonly struct DiagnosticsAccess { private readonly RegionGraph m_g; public int LookupGridCellCount { get { if (m_g == null || !m_g.m_initialized) { return 0; } return m_g.m_lookupGrid.Count; } } public int BoundaryCellCount { get { if (m_g == null || !m_g.m_initialized) { return 0; } return m_g.m_boundaryCells.Count; } } internal DiagnosticsAccess(RegionGraph g) { m_g = g; } public List GetAllRegionCenters() { //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_003e: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (m_g == null || !m_g.m_initialized) { return list; } foreach (Vector3 value in m_g.m_regionCentroids.Values) { list.Add(value); } return list; } public List GetLookupCellCenters() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (m_g == null || !m_g.m_initialized) { return list; } float num = 0.5f; float num2 = 1f; foreach (long key in m_g.m_lookupGrid.Keys) { UnpackLookup(key, out var gx, out var gz, out var hb); list.Add(new Vector3((float)gx * 1f + num, (float)hb * 2f + num2, (float)gz * 1f + num)); } return list; } public bool TryGetLookupGridBounds(out float minX, out float maxX, out float minZ, out float maxZ) { minX = (maxX = (minZ = (maxZ = 0f))); if (m_g == null || !m_g.m_initialized || m_g.m_lookupGrid.Count == 0) { return false; } minX = (minZ = float.PositiveInfinity); maxX = (maxZ = float.NegativeInfinity); float num = 0.5f; foreach (long key in m_g.m_lookupGrid.Keys) { UnpackLookup(key, out var gx, out var gz, out var _); float num2 = (float)gx * 1f + num; float num3 = (float)gz * 1f + num; if (num2 < minX) { minX = num2; } if (num2 > maxX) { maxX = num2; } if (num3 < minZ) { minZ = num3; } if (num3 > maxZ) { maxZ = num3; } } return true; } public bool TryGetBoundaryCellsBounds(out float minX, out float maxX, out float minZ, out float maxZ) { //IL_0073: 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_0079: 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_0084: 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) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) minX = (maxX = (minZ = (maxZ = 0f))); if (m_g == null || !m_g.m_initialized || m_g.m_boundaryCells.Count == 0) { return false; } minX = (minZ = float.PositiveInfinity); maxX = (maxZ = float.NegativeInfinity); foreach (var boundaryCell in m_g.m_boundaryCells) { Vector3 item = boundaryCell.center; if (item.x < minX) { minX = item.x; } if (item.x > maxX) { maxX = item.x; } if (item.z < minZ) { minZ = item.z; } if (item.z > maxZ) { maxZ = item.z; } } return true; } } public const float CellSize = 3f; internal const float HeightBucketSize = 2f; internal const float LookupCellSize = 1f; private float m_originX; private float m_originZ; private readonly HashSet m_regionIds = new HashSet(); private readonly List m_links = new List(); private bool m_initialized; private readonly Dictionary m_regionCentroids = new Dictionary(); private readonly Dictionary m_lookupGrid = new Dictionary(); private readonly List<(string id, Vector3 center, Vector3 outDir)> m_boundaryCells = new List<(string, Vector3, Vector3)>(); private readonly Dictionary m_regionKinds = new Dictionary(); private readonly List m_gates = new List(); private readonly HashSet m_outsideCellsXz = new HashSet(); private readonly HashSet m_anchorReachableCellsXz = new HashSet(); private readonly HashSet m_prunedPieceKeys = new HashSet(); private bool m_hasClassification; public bool IsAvailable { get { if (m_initialized) { return m_regionIds.Count > 0; } return false; } } public int RegionCount => m_regionIds.Count; public int LinkCount => m_links.Count; public string RegisteredVillageKey { get; internal set; } public DiagnosticsAccess Diagnostics => new DiagnosticsAccess(this); public bool HasClassification { get { if (m_initialized) { return m_hasClassification; } return false; } } internal IReadOnlyCollection OutsideCellsXz => m_outsideCellsXz; internal IReadOnlyCollection AnchorReachableCellsXz => m_anchorReachableCellsXz; internal IReadOnlyCollection PrunedPieceKeys => m_prunedPieceKeys; public void SetGraph(HashSet regionIds, List links, Dictionary regionCentroids, Dictionary lookupGrid, List<(string id, Vector3 center, Vector3 outDir)> boundaryCells = null, Dictionary regionKinds = null) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0168: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) ClearInternal(); if (regionIds != null) { foreach (string regionId in regionIds) { m_regionIds.Add(regionId); } } if (links != null) { m_links.AddRange(links); } if (regionCentroids != null) { foreach (KeyValuePair regionCentroid in regionCentroids) { m_regionCentroids[regionCentroid.Key] = regionCentroid.Value; } } if (lookupGrid != null) { foreach (KeyValuePair item in lookupGrid) { m_lookupGrid[item.Key] = item.Value; } } if (boundaryCells != null) { m_boundaryCells.AddRange(boundaryCells); } if (regionKinds != null) { foreach (KeyValuePair regionKind in regionKinds) { m_regionKinds[regionKind.Key] = regionKind.Value; } } if (regionCentroids != null && regionCentroids.Count > 0) { float num = 0f; float num2 = 0f; foreach (Vector3 value in regionCentroids.Values) { num += value.x; num2 += value.z; } m_originX = num / (float)regionCentroids.Count; m_originZ = num2 / (float)regionCentroids.Count; } m_initialized = true; } private void ClearInternal() { m_regionIds.Clear(); m_links.Clear(); m_regionCentroids.Clear(); m_lookupGrid.Clear(); m_boundaryCells.Clear(); m_regionKinds.Clear(); m_gates.Clear(); m_outsideCellsXz.Clear(); m_anchorReachableCellsXz.Clear(); m_prunedPieceKeys.Clear(); m_hasClassification = false; m_initialized = false; } public static bool GetSolidHeightAt(float worldX, float worldZ, out float height) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) height = 0f; if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } float num = default(float); bool solidHeight = ZoneSystem.instance.GetSolidHeight(new Vector3(worldX, 500f, worldZ), ref num, 550); float num2 = default(float); bool solidHeight2 = ZoneSystem.instance.GetSolidHeight(new Vector3(worldX, 0f, worldZ), ref num2, 500); if (solidHeight && solidHeight2) { height = Mathf.Max(num, num2); return true; } if (solidHeight) { height = num; return true; } if (solidHeight2) { height = num2; return true; } return false; } public static int HeightBucket(float y) { return Mathf.FloorToInt(y / 2f); } internal static long PackLookup(int gx, int gz, int hb) { return (long)gx * 1000003L * 1000003 + (long)gz * 1000003L + hb; } internal static long PackXz(int gx, int gz) { return (long)(((ulong)(uint)gx << 32) | (uint)gz); } internal static void UnpackXz(long key, out int gx, out int gz) { gx = (int)(key >> 32); gz = (int)(key & 0xFFFFFFFFu); } public string PointToRegionId(Vector3 worldPosition) { //IL_000a: 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_002e: Unknown result type (might be due to invalid IL or missing references) if (!m_initialized) { return null; } int gx = Mathf.FloorToInt(worldPosition.x / 1f); int gz = Mathf.FloorToInt(worldPosition.z / 1f); int num = HeightBucket(worldPosition.y); for (int i = 0; i <= 1; i++) { if (m_lookupGrid.TryGetValue(PackLookup(gx, gz, num + i), out var value)) { return value; } if (i > 0 && m_lookupGrid.TryGetValue(PackLookup(gx, gz, num - i), out value)) { return value; } } return null; } public bool TryFindNearestLookupCell(Vector3 target, Func validator, out Vector3 worldPos, out string regionId, float maxXzDist = float.MaxValue) { //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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0170: 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_0166: Unknown result type (might be due to invalid IL or missing references) worldPos = Vector3.zero; regionId = null; if (!m_initialized || m_lookupGrid.Count == 0) { return false; } List<(long, Vector3, string, float)> list = new List<(long, Vector3, string, float)>(m_lookupGrid.Count); float num = 0.5f; float num2 = 1f; Vector3 item = default(Vector3); foreach (KeyValuePair item4 in m_lookupGrid) { UnpackLookup(item4.Key, out var gx, out var gz, out var hb); float num3 = (float)gx * 1f + num; float num4 = (float)gz * 1f + num; float num5 = (float)hb * 2f + num2; ((Vector3)(ref item))..ctor(num3, num5, num4); float num6 = num3 - target.x; float num7 = num4 - target.z; list.Add((item4.Key, item, item4.Value, num6 * num6 + num7 * num7)); } list.Sort(((long key, Vector3 pos, string id, float distSq) a, (long key, Vector3 pos, string id, float distSq) b) => a.distSq.CompareTo(b.distSq)); float num8 = ((maxXzDist >= float.MaxValue) ? float.MaxValue : (maxXzDist * maxXzDist)); foreach (var item5 in list) { Vector3 item2 = item5.Item2; string item3 = item5.Item3; if (item5.Item4 > num8) { break; } if (validator == null || validator(item2)) { worldPos = item2; regionId = item3; return true; } } return false; } internal static void UnpackLookup(long key, out int gx, out int gz, out int hb) { long num = (key % 1000003 + 1000003) % 1000003; hb = (int)num; if ((long)hb > 500001L) { hb -= 1000003; } long num2 = (key - hb) / 1000003; long num3 = (num2 % 1000003 + 1000003) % 1000003; gz = (int)num3; if ((long)gz > 500001L) { gz -= 1000003; } gx = (int)((num2 - gz) / 1000003); } public bool IsValidRegion(string regionId) { if (m_initialized && !string.IsNullOrEmpty(regionId)) { return m_regionIds.Contains(regionId); } return false; } public SurfaceKind GetRegionKind(string regionId) { if (m_regionKinds.TryGetValue(regionId, out var value)) { return value; } return SurfaceKind.Piece; } public bool TryGetCellHeight(string cellId, out float height) { //IL_0025: 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) height = 0f; if (!m_initialized || cellId == null) { return false; } if (m_regionCentroids.TryGetValue(cellId, out var value)) { return (height = value.y) == value.y; } return false; } public bool GetOrigin(out float originX, out float originZ) { originX = m_originX; originZ = m_originZ; return m_initialized; } public bool GetCellWorldXZ(string cellId, out float wx, out float wz) { //IL_0031: 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) wx = (wz = 0f); if (!m_initialized || string.IsNullOrEmpty(cellId)) { return false; } if (!m_regionCentroids.TryGetValue(cellId, out var value)) { return false; } wx = value.x; wz = value.z; return true; } public bool GetRegionBounds(string regionId, out float minX, out float maxX, out float minZ, out float maxZ) { //IL_0043: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) minX = (maxX = (minZ = (maxZ = 0f))); if (!m_initialized || string.IsNullOrEmpty(regionId)) { return false; } if (!m_regionCentroids.TryGetValue(regionId, out var value)) { return false; } float num = 1.5f; minX = value.x - num; maxX = value.x + num; minZ = value.z - num; maxZ = value.z + num; return true; } public bool GetRegionSampleHeights(string regionId, out float centerY, out float minY, out float maxY) { //IL_0049: 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) centerY = (minY = (maxY = 0f)); if (!m_initialized || string.IsNullOrEmpty(regionId)) { return false; } if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } if (!m_regionCentroids.TryGetValue(regionId, out var value)) { return false; } float x = value.x; float z = value.z; float num = 1.2f; (float, float)[] obj = new(float, float)[5] { (x, z), (x + num, z), (x - num, z), (x, z + num), (x, z - num) }; minY = float.MaxValue; maxY = float.MinValue; bool result = false; (float, float)[] array = obj; for (int i = 0; i < array.Length; i++) { var (num2, num3) = array[i]; if (GetSolidHeightAt(num2, num3, out var height)) { result = true; if (Mathf.Abs(num2 - x) < 0.01f && Mathf.Abs(num3 - z) < 0.01f) { centerY = height; } if (height < minY) { minY = height; } if (height > maxY) { maxY = height; } } } return result; } public IReadOnlyList GetLinksFromRegion(string regionId) { //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_0098: Unknown result type (might be due to invalid IL or missing references) if (!m_initialized || string.IsNullOrEmpty(regionId)) { return null; } List list = new List(); foreach (RegionLink link in m_links) { if (link.FromRegionId == regionId) { list.Add(link); } else if (link.ToRegionId == regionId) { list.Add(new RegionLink { FromRegionId = link.ToRegionId, ToRegionId = link.FromRegionId, LinkType = link.LinkType, PositionStart = link.PositionEnd, PositionEnd = link.PositionStart }); } } return list; } public IReadOnlyList GetAllLinks() { if (!m_initialized) { return new List(); } return m_links; } internal IEnumerable GetRegionIds() { return m_regionIds; } public void Clear() { ClearInternal(); } public List<(string cellId, Vector3 worldCenter, Vector3 outwardDir)> GetBoundaryCells() { if (!m_initialized) { return new List<(string, Vector3, Vector3)>(); } return new List<(string, Vector3, Vector3)>(m_boundaryCells); } public void SetGates(IEnumerable gates) { m_gates.Clear(); if (gates != null) { m_gates.AddRange(gates); } } public List GetGates() { return new List(m_gates); } public void SetClassification(HashSet outsideXz, HashSet anchorReachableXz, HashSet prunedPieceKeys) { m_outsideCellsXz.Clear(); m_anchorReachableCellsXz.Clear(); m_prunedPieceKeys.Clear(); if (outsideXz != null) { foreach (long item in outsideXz) { m_outsideCellsXz.Add(item); } } if (anchorReachableXz != null) { foreach (long item2 in anchorReachableXz) { m_anchorReachableCellsXz.Add(item2); } } if (prunedPieceKeys != null) { foreach (long prunedPieceKey in prunedPieceKeys) { m_prunedPieceKeys.Add(prunedPieceKey); } } m_hasClassification = m_outsideCellsXz.Count > 0 || m_anchorReachableCellsXz.Count > 0 || m_prunedPieceKeys.Count > 0; } public bool IsOutsideCell(int gx, int gz) { return m_outsideCellsXz.Contains(PackXz(gx, gz)); } public bool IsAnchorReachableCell(int gx, int gz) { return m_anchorReachableCellsXz.Contains(PackXz(gx, gz)); } public bool IsPieceKeyPruned(long lookupKey) { return m_prunedPieceKeys.Contains(lookupKey); } } internal static class RegionGraphPersistence { private const string LinkSectionDelimiter = "||"; private const string ClassSectionDelimiter = "|#|"; private const string V4Header = "v4"; private const int ClassTile = 16; private const int ClassTileCells = 256; private const int ClassMaskBytes = 32; internal static Action LogAction; private static char KindToChar(SurfaceKind k) { if (k != SurfaceKind.Terrain) { return 'P'; } return 'T'; } private static SurfaceKind CharToKind(char c) { if (c != 'T') { return SurfaceKind.Piece; } return SurfaceKind.Terrain; } private static char LinkTypeToChar(RegionLinkType t) { return t switch { RegionLinkType.Door => 'D', RegionLinkType.Stair => 'S', RegionLinkType.Slope => 'L', _ => 'L', }; } private static RegionLinkType CharToLinkType(char c) { return c switch { 'D' => RegionLinkType.Door, 'S' => RegionLinkType.Stair, _ => RegionLinkType.Slope, }; } internal static string Serialize(RegionGraph graph) { if (graph == null || !graph.IsAvailable) { return ""; } return SerializeV4(graph); } private static string SerializeV4(RegionGraph graph) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("v4"); foreach (string regionId in graph.GetRegionIds()) { stringBuilder.Append(';').Append(regionId).Append(':'); if (graph.GetCellWorldXZ(regionId, out var wx, out var wz) && graph.TryGetCellHeight(regionId, out var height)) { stringBuilder.Append(wx.ToString("F2", invariantCulture)).Append(',').Append(height.ToString("F2", invariantCulture)) .Append(',') .Append(wz.ToString("F2", invariantCulture)) .Append(',') .Append(KindToChar(graph.GetRegionKind(regionId))); } else { stringBuilder.Append('?'); } } AppendLinks(stringBuilder, graph); AppendClassification(stringBuilder, graph); return stringBuilder.ToString(); } private static void AppendLinks(StringBuilder sb, RegionGraph graph) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; IReadOnlyList allLinks = graph.GetAllLinks(); if (allLinks == null || allLinks.Count == 0) { return; } sb.Append("||"); for (int i = 0; i < allLinks.Count; i++) { if (i > 0) { sb.Append(';'); } RegionLink regionLink = allLinks[i]; sb.Append(regionLink.FromRegionId).Append(',').Append(regionLink.ToRegionId) .Append(',') .Append(LinkTypeToChar(regionLink.LinkType)) .Append(',') .Append(regionLink.PositionStart.x.ToString("F2", invariantCulture)) .Append(',') .Append(regionLink.PositionStart.y.ToString("F2", invariantCulture)) .Append(',') .Append(regionLink.PositionStart.z.ToString("F2", invariantCulture)) .Append(',') .Append(regionLink.PositionEnd.x.ToString("F2", invariantCulture)) .Append(',') .Append(regionLink.PositionEnd.y.ToString("F2", invariantCulture)) .Append(',') .Append(regionLink.PositionEnd.z.ToString("F2", invariantCulture)); } } internal static bool Restore(RegionGraph graph, string data) { if (graph == null || string.IsNullOrEmpty(data)) { return false; } if (!data.StartsWith("v4")) { LogInfo("[Region] Legacy non-v4 graph in ZDO; purging (caller will wipe + rebuild)"); return false; } return RestoreV4(graph, data); } private static bool RestoreV4(RegionGraph graph, string data) { //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) string text = data; string text2 = null; int num = data.IndexOf("|#|", StringComparison.Ordinal); if (num >= 0) { text = data.Substring(0, num); text2 = data.Substring(num + "|#|".Length); } string text3 = text; string linkSection = null; int num2 = text.IndexOf("||", StringComparison.Ordinal); if (num2 >= 0) { text3 = text.Substring(0, num2); linkSection = text.Substring(num2 + "||".Length); } string[] array = text3.Split(new char[1] { ';' }); if (array.Length < 2) { return false; } CultureInfo invariantCulture = CultureInfo.InvariantCulture; HashSet hashSet = new HashSet(); Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); for (int i = 1; i < array.Length; i++) { string text4 = array[i]; int num3 = text4.IndexOf(':'); if (num3 <= 0) { continue; } string text5 = text4.Substring(0, num3); string text6 = text4.Substring(num3 + 1); hashSet.Add(text5); if (text6 == "?") { continue; } string[] array2 = text6.Split(new char[1] { ',' }); if (array2.Length >= 4 && float.TryParse(array2[0], NumberStyles.Float, invariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, invariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, invariantCulture, out var result3)) { dictionary[text5] = new Vector3(result, result2, result3); if (array2[3].Length > 0) { dictionary2[text5] = CharToKind(array2[3][0]); } } } if (hashSet.Count == 0) { return false; } List list = DeserializeLinks(linkSection); Dictionary dictionary3 = new Dictionary(); foreach (KeyValuePair item in dictionary) { int num4 = Mathf.FloorToInt(item.Value.x / 1f); int num5 = Mathf.FloorToInt(item.Value.z / 1f); int hb = RegionGraph.HeightBucket(item.Value.y); for (int j = -1; j <= 1; j++) { for (int k = -1; k <= 1; k++) { long key = RegionGraph.PackLookup(num4 + j, num5 + k, hb); dictionary3[key] = item.Key; } } } graph.SetGraph(hashSet, list, dictionary, dictionary3, null, dictionary2); if (!string.IsNullOrEmpty(text2)) { RestoreClassification(graph, text2); } LogInfo($"[Region] Restored v4 graph from ZDO: {hashSet.Count} regions, {list.Count} links, " + string.Format("{0} kinded, classification={1}", dictionary2.Count, graph.HasClassification ? "yes" : "no")); return true; } private static void LogInfo(string message) { LogAction?.Invoke(message); } private static void AppendClassification(StringBuilder sb, RegionGraph graph) { if (graph.HasClassification) { sb.Append("|#|"); AppendXzBitmask(sb, graph.OutsideCellsXz); sb.Append('~'); AppendXzBitmask(sb, graph.AnchorReachableCellsXz); sb.Append('~'); AppendPieceKeys(sb, graph.PrunedPieceKeys); } } private static void RestoreClassification(RegionGraph graph, string classSection) { string[] array = classSection.Split(new char[1] { '~' }); HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); HashSet hashSet3 = new HashSet(); if (array.Length != 0) { ParseXzBitmask(array[0], hashSet); } if (array.Length > 1) { ParseXzBitmask(array[1], hashSet2); } if (array.Length > 2) { ParsePieceKeys(array[2], hashSet3); } graph.SetClassification(hashSet, hashSet2, hashSet3); } private static void AppendXzBitmask(StringBuilder sb, IReadOnlyCollection cells) { if (cells == null || cells.Count == 0) { return; } Dictionary dictionary = new Dictionary(); foreach (long cell in cells) { RegionGraph.UnpackXz(cell, out var gx, out var gz); int num = FloorDiv(gx, 16); int num2 = FloorDiv(gz, 16); long key = RegionGraph.PackXz(num, num2); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new byte[32]); } int num3 = gx - num * 16; int num4 = gz - num2 * 16; int num5 = num3 * 16 + num4; value[num5 >> 3] |= (byte)(1 << (num5 & 7)); } CultureInfo invariantCulture = CultureInfo.InvariantCulture; bool flag = true; foreach (KeyValuePair item in dictionary) { RegionGraph.UnpackXz(item.Key, out var gx2, out var gz2); if (!flag) { sb.Append('!'); } flag = false; sb.Append(gx2.ToString(invariantCulture)).Append(',').Append(gz2.ToString(invariantCulture)) .Append(',') .Append(Convert.ToBase64String(item.Value)); } } private static void ParseXzBitmask(string section, HashSet outSet) { if (string.IsNullOrEmpty(section)) { return; } string[] array = section.Split(new char[1] { '!' }); foreach (string text in array) { if (string.IsNullOrEmpty(text)) { continue; } string[] array2 = text.Split(new char[1] { ',' }); if (array2.Length < 3 || !int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { continue; } byte[] array3; try { array3 = Convert.FromBase64String(array2[2]); } catch { continue; } for (int j = 0; j < 256 && j >> 3 < array3.Length; j++) { if ((array3[j >> 3] & (1 << (j & 7))) != 0) { int gx = result * 16 + j / 16; int gz = result2 * 16 + j % 16; outSet.Add(RegionGraph.PackXz(gx, gz)); } } } } private static void AppendPieceKeys(StringBuilder sb, IReadOnlyCollection keys) { if (keys == null || keys.Count == 0) { return; } CultureInfo invariantCulture = CultureInfo.InvariantCulture; bool flag = true; foreach (long key in keys) { RegionGraph.UnpackLookup(key, out var gx, out var gz, out var hb); if (!flag) { sb.Append('!'); } flag = false; sb.Append(gx.ToString(invariantCulture)).Append(',').Append(gz.ToString(invariantCulture)) .Append(',') .Append(hb.ToString(invariantCulture)); } } private static void ParsePieceKeys(string section, HashSet outSet) { if (string.IsNullOrEmpty(section)) { return; } string[] array = section.Split(new char[1] { '!' }); foreach (string text in array) { if (!string.IsNullOrEmpty(text)) { string[] array2 = text.Split(new char[1] { ',' }); if (array2.Length >= 3 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3)) { outSet.Add(RegionGraph.PackLookup(result, result2, result3)); } } } } private static int FloorDiv(int a, int b) { int num = a / b; if (a % b != 0 && a < 0 != b < 0) { num--; } return num; } private static List DeserializeLinks(string linkSection) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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_0161: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (string.IsNullOrEmpty(linkSection)) { return list; } CultureInfo invariantCulture = CultureInfo.InvariantCulture; string[] array = linkSection.Split(new char[1] { ';' }); foreach (string text in array) { if (string.IsNullOrEmpty(text)) { continue; } string[] array2 = text.Split(new char[1] { ',' }); if (array2.Length < 9) { continue; } string text2 = array2[0]; string text3 = array2[1]; if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(text3) && array2[2].Length >= 1) { RegionLinkType linkType = CharToLinkType(array2[2][0]); if (float.TryParse(array2[3], NumberStyles.Float, invariantCulture, out var result) && float.TryParse(array2[4], NumberStyles.Float, invariantCulture, out var result2) && float.TryParse(array2[5], NumberStyles.Float, invariantCulture, out var result3) && float.TryParse(array2[6], NumberStyles.Float, invariantCulture, out var result4) && float.TryParse(array2[7], NumberStyles.Float, invariantCulture, out var result5) && float.TryParse(array2[8], NumberStyles.Float, invariantCulture, out var result6)) { list.Add(new RegionLink { FromRegionId = text2, ToRegionId = text3, LinkType = linkType, PositionStart = new Vector3(result, result2, result3), PositionEnd = new Vector3(result4, result5, result6) }); } } } return list; } } public static class RegistrySeedResolver { private const float CapsuleRadius = 0.3f; private const float CapsuleHeight = 1.4f; private const float CapsuleLift = 0.25f; private const float RaycastUp = 3f; private const float RaycastDown = 8f; private const float HumanoidSnapRadius = 1f; private static readonly float[] SearchRadii = new float[6] { 0f, 1.5f, 2f, 2.5f, 3f, 4f }; private const int Directions = 12; public static bool TryResolveWalkableSeed(Vector3 anchor, out Vector3 seed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0026: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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) //IL_00c9: 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) seed = anchor; int num = VillagerAgentType.ResolveValheimHumanoidAgentTypeID(); NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = num; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; float[] searchRadii = SearchRadii; NavMeshHit val4 = default(NavMeshHit); foreach (float num2 in searchRadii) { int num3 = ((num2 == 0f) ? 1 : 12); Vector3? val3 = null; float num4 = float.MaxValue; for (int j = 0; j < num3; j++) { float num5 = 360f / (float)num3 * (float)j * ((float)Math.PI / 180f); if (!TryGroundPoint(anchor + new Vector3(Mathf.Cos(num5) * num2, 0f, Mathf.Sin(num5) * num2), anchor.y, out var ground) || !CapsuleClear(ground)) { continue; } if (num != 0) { if (!NavMesh.SamplePosition(ground, ref val4, 1f, val2)) { continue; } ground = ((NavMeshHit)(ref val4)).position; } Vector3 val5 = ground - anchor; float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude; if (sqrMagnitude < num4) { num4 = sqrMagnitude; val3 = ground; } } if (val3.HasValue) { seed = val3.Value; return true; } } return false; } private static bool TryGroundPoint(Vector3 xz, float refY, out Vector3 ground) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0040: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) ground = xz; int mask = LayerMask.GetMask(new string[4] { "Default", "static_solid", "piece", "terrain" }); RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Vector3(xz.x, refY + 3f, xz.z), Vector3.down, ref val, 11f, mask, (QueryTriggerInteraction)1)) { ground = ((RaycastHit)(ref val)).point; return true; } if ((Object)(object)ZoneSystem.instance != (Object)null) { ground = new Vector3(xz.x, ZoneSystem.instance.GetGroundHeight(xz), xz.z); return true; } return false; } private static bool CapsuleClear(Vector3 ground) { //IL_0024: 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_002f: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); Vector3 val = ground + Vector3.up * 0.55f; Vector3 val2 = ground + Vector3.up * 1.3499999f; return !Physics.CheckCapsule(val, val2, 0.3f, mask, (QueryTriggerInteraction)1); } } internal static class RubberBandPrune { public readonly struct CellRect { public readonly int Gx0; public readonly int Gz0; public readonly int Gx1; public readonly int Gz1; public CellRect(int gx0, int gz0, int gx1, int gz1) { Gx0 = gx0; Gz0 = gz0; Gx1 = gx1; Gz1 = gz1; } } internal readonly struct GateSeal { public readonly Vector3 Mid; public readonly Vector3 Forward; public readonly float HalfWidth; public GateSeal(Vector3 mid, Vector3 forward, float halfWidth) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Mid = mid; Forward = forward; HalfWidth = halfWidth; } } public struct Stats { public int OutsideTerrainCells; public int Pass2Seeds; public int AnchorReachableTerrainCells; public int Pass3Seeds; public int AnchorReachablePieceKeys; public int Pass3PieceKeysDropped; public int Pass3LinksAdded; public int Pass4BoundaryVertsSnapped; public int Pass4SnapMisses; public int Pass4LinksSnapped; public int Pass5ChainsConsolidated; public int Pass5RegionsConsumed; public int Pass5LinksRemoved; public int RegionsDropped; public int PerimeterSeeds; public int LookupCellsDropped; public int TrianglesDropped; public int StaticSolidTrianglesDropped; } private const float WaistMin = 0.7f; private const float WaistMax = 1.3f; private const long PackK = 1000003L; private const long PackKHalf = 500001L; internal static HashSet LastOutsideCells; internal static Dictionary LastXzMaxY; internal static int LastGxMin; internal static int LastGzMin; internal static int LastGxMax; internal static int LastGzMax; internal static float LastCell; internal static int LastPieceMask; internal static bool HasSnapshot; private static readonly Collider[] s_waistProbeBuf = (Collider[])(object)new Collider[64]; [RegisterCleanup] public static void ClearDiagnosticState() { LastOutsideCells = null; LastXzMaxY = null; LastGxMin = (LastGzMin = (LastGxMax = (LastGzMax = 0))); LastCell = 0f; LastPieceMask = 0; HasSnapshot = false; } public static Stats Apply(HashSet regionIds, Dictionary centroids, Dictionary lookupGrid, List<(string id, Vector3 center, Vector3 outwardDir)> boundaryCells, List links, Dictionary kindMap, List triangles, List anchors, float minX, float minZ, float maxX, float maxZ, out HashSet droppedRegionIds, out List<(string fromRid, string toRid, Vector3 startPos, Vector3 endPos)> pass3DiscoveredEdgeList, out HashSet anchorReachableCellsOut, out HashSet outsideCellsOut, out HashSet prunedPieceKeysOut, out List gateMarkersOut) { //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Unknown result type (might be due to invalid IL or missing references) //IL_071b: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_079c: Unknown result type (might be due to invalid IL or missing references) //IL_07c0: Unknown result type (might be due to invalid IL or missing references) //IL_07c2: Unknown result type (might be due to invalid IL or missing references) //IL_0cd5: Unknown result type (might be due to invalid IL or missing references) //IL_0cda: Unknown result type (might be due to invalid IL or missing references) //IL_0cdc: Unknown result type (might be due to invalid IL or missing references) //IL_0ce1: Unknown result type (might be due to invalid IL or missing references) //IL_0f52: Unknown result type (might be due to invalid IL or missing references) //IL_0f57: Unknown result type (might be due to invalid IL or missing references) //IL_0d66: Unknown result type (might be due to invalid IL or missing references) //IL_0d68: Unknown result type (might be due to invalid IL or missing references) //IL_0d6f: Unknown result type (might be due to invalid IL or missing references) //IL_0d71: Unknown result type (might be due to invalid IL or missing references) //IL_105f: Unknown result type (might be due to invalid IL or missing references) //IL_1063: Unknown result type (might be due to invalid IL or missing references) //IL_0f9e: Unknown result type (might be due to invalid IL or missing references) //IL_0fb1: Unknown result type (might be due to invalid IL or missing references) //IL_0fb6: Unknown result type (might be due to invalid IL or missing references) //IL_0fbb: Unknown result type (might be due to invalid IL or missing references) HashSet dropped = new HashSet(); droppedRegionIds = dropped; pass3DiscoveredEdgeList = new List<(string, string, Vector3, Vector3)>(); anchorReachableCellsOut = new HashSet(); outsideCellsOut = new HashSet(); prunedPieceKeysOut = new HashSet(); gateMarkersOut = new List(); Stats stats = default(Stats); if (regionIds == null || regionIds.Count == 0) { return stats; } if (lookupGrid == null || lookupGrid.Count == 0) { return stats; } int pieceMask = LayerMask.GetMask(new string[1] { "piece" }); if (pieceMask == 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[RubberBand] Skipped: 'piece' layer not found"); } return stats; } int staticSolidLayer = LayerMask.NameToLayer("static_solid"); float cell = 1f; int num = Mathf.FloorToInt(minX / cell) - 1; int num2 = Mathf.FloorToInt(minZ / cell) - 1; int num3 = Mathf.FloorToInt(maxX / cell) + 1; int num4 = Mathf.FloorToInt(maxZ / cell) + 1; Dictionary xzMaxYTerrain = new Dictionary(); Dictionary xzMaxYPiece = new Dictionary(); Dictionary> dictionary = new Dictionary>(); Dictionary> dictionary2 = new Dictionary>(); Dictionary> xzToLookupKeysTerrain = new Dictionary>(); Dictionary> xzToLookupKeysPiece = new Dictionary>(); foreach (KeyValuePair item7 in lookupGrid) { UnpackLookup(item7.Key, out var gx, out var gz, out var _); if (gx < num || gx > num3 || gz < num2 || gz > num4) { continue; } long num5 = XzKey(gx, gz); SurfaceKind value; bool num6 = ((kindMap != null && kindMap.TryGetValue(item7.Value, out value)) ? value : SurfaceKind.Terrain) == SurfaceKind.Piece; Dictionary dictionary3 = (num6 ? xzMaxYPiece : xzMaxYTerrain); Dictionary> dictionary4 = (num6 ? xzToLookupKeysPiece : xzToLookupKeysTerrain); if (centroids.TryGetValue(item7.Value, out var value2)) { if (!dictionary3.TryGetValue(num5, out var value3) || value2.y > value3) { dictionary3[num5] = value2.y; } } else if (!dictionary3.ContainsKey(num5)) { dictionary3[num5] = 0f; } if (!dictionary.TryGetValue(item7.Value, out var value4)) { value4 = new List(4); dictionary[item7.Value] = value4; } value4.Add(num5); if (!dictionary4.TryGetValue(num5, out var value5)) { value5 = (dictionary4[num5] = new List(4)); } value5.Add(item7.Key); if (num6) { if (!dictionary2.TryGetValue(item7.Value, out var value6)) { value6 = new HashSet(); dictionary2[item7.Value] = value6; } value6.Add(item7.Key); } } List gateSeals = GatherGateSeals(minX, minZ, maxX, maxZ); foreach (GateSeal item8 in gateSeals) { gateMarkersOut.Add(item8.Mid); } int perimeterSeedCount; HashSet outsideCells = PerimeterOutsideFlood(num, num2, num3, num4, (int gx4, int gz4) => GetCellY(gx4, gz4, xzMaxYTerrain, cell), (int ax, int az, int bx, int bz, float ya, float yb) => WallBlocks(ax, az, bx, bz, ya, yb, cell, pieceMask) || GateBlocksStep(ax, az, bx, bz, cell, gateSeals), out perimeterSeedCount); stats.PerimeterSeeds = perimeterSeedCount; int[] array = new int[4] { 1, -1, 0, 0 }; int[] array2 = new int[4] { 0, 0, 1, -1 }; foreach (KeyValuePair item9 in xzMaxYTerrain) { if (outsideCells.Contains(item9.Key)) { stats.OutsideTerrainCells++; } } HashSet anchorReachableCells = new HashSet(); Dictionary anchorReachableCellY = new Dictionary(); int seedCount = 0; if (anchors != null && anchors.Count > 0 && (Object)(object)ZoneSystem.instance != (Object)null) { AnchorReachableFlood(num, num2, num3, num4, anchors, outsideCells, cell, 6, (long ck) => xzMaxYTerrain.ContainsKey(ck) || xzMaxYPiece.ContainsKey(ck), (long xzKey, int gx4, int gz4) => SurfaceY(xzKey, gx4, gz4, out var _), (int ax, int az, int bx, int bz, float ya, float yb) => WallBlocks(ax, az, bx, bz, ya, yb, cell, pieceMask), out anchorReachableCells, out anchorReachableCellY, out seedCount, delegate(string msg) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)msg); } }); } stats.Pass2Seeds = seedCount; stats.AnchorReachableTerrainCells = anchorReachableCells.Count; HashSet pieceReachableKeys = new HashSet(); int num7 = 0; HashSet pass3DiscoveredEdges = new HashSet(); List<(string fromRid, string toRid, Vector3 startPos, Vector3 endPos)> pass3EdgePairs = new List<(string, string, Vector3, Vector3)>(); if (xzToLookupKeysPiece.Count > 0 && anchorReachableCells.Count > 0 && (Object)(object)ZoneSystem.instance != (Object)null) { float num8 = cell * 0.5f; HashSet hashSet = new HashSet(); Queue<(long, float, bool, string)> queue = new Queue<(long, float, bool, string)>(); foreach (long item10 in anchorReachableCells) { UnpackXz(item10, out var gx2, out var gz2); float num9 = (float)gx2 * cell + num8; float num10 = (float)gz2 * cell + num8; float value7; float item = (anchorReachableCellY.TryGetValue(item10, out value7) ? value7 : ZoneSystem.instance.GetGroundHeight(new Vector3(num9, 0f, num10))); queue.Enqueue((item10, item, true, null)); } while (queue.Count > 0) { var (num11, num12, flag, text) = queue.Dequeue(); if (flag && !hashSet.Add(num11)) { continue; } UnpackXz(num11, out var gx3, out var gz3); for (int num13 = 0; num13 < 4; num13++) { int num14 = gx3 + array[num13]; int num15 = gz3 + array2[num13]; long num16 = XzKey(num14, num15); if (anchorReachableCells.Contains(num16) && !hashSet.Contains(num16)) { float num17 = (float)num14 * cell + num8; float num18 = (float)num15 * cell + num8; float value8; float num19 = (anchorReachableCellY.TryGetValue(num16, out value8) ? value8 : ZoneSystem.instance.GetGroundHeight(new Vector3(num17, 0f, num18))); if (Mathf.Abs(num19 - num12) <= 1f) { queue.Enqueue((num16, num19, true, null)); } } if (!xzToLookupKeysPiece.TryGetValue(num16, out var value9)) { continue; } string text2 = null; foreach (long item11 in value9) { if (!pieceReachableKeys.Contains(item11) && lookupGrid.TryGetValue(item11, out var value10) && centroids.TryGetValue(value10, out var value11) && !(Mathf.Abs(value11.y - num12) > 1f) && !outsideCells.Contains(num16)) { pieceReachableKeys.Add(item11); queue.Enqueue((num16, value11.y, false, value10)); num7++; string text3 = text ?? TerrainRegionAtCell(num11) ?? PieceAtCellInReachable(num11, num12) ?? text2; ComputePieceStepLinkPositions(num11, num16, num12, value11.y, cell, text3 == text2, out var startPos, out var endPos); RecordPass3Edge(text3, value10, startPos, endPos); text2 = value10; } } } } } stats.Pass3Seeds = num7; stats.AnchorReachablePieceKeys = pieceReachableKeys.Count; pass3DiscoveredEdgeList = pass3EdgePairs; HashSet hashSet2 = new HashSet(); foreach (KeyValuePair> item12 in xzToLookupKeysPiece) { foreach (long item13 in item12.Value) { if (!pieceReachableKeys.Contains(item13)) { hashSet2.Add(item13); } } } prunedPieceKeysOut = hashSet2; if (staticSolidLayer >= 0 && outsideCells.Count > 0 && triangles != null && triangles.Count > 0) { int count = triangles.Count; triangles.RemoveAll(delegate(RegionBuilder.CachedTriangle t) { //IL_0011: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0052: Unknown result type (might be due to invalid IL or missing references) if (t.Layer != staticSolidLayer) { return false; } float num30 = (t.V0.x + t.V1.x + t.V2.x) / 3f; float num31 = (t.V0.z + t.V1.z + t.V2.z) / 3f; int gx4 = Mathf.FloorToInt(num30 / cell); int gz4 = Mathf.FloorToInt(num31 / cell); return outsideCells.Contains(XzKey(gx4, gz4)); }); stats.StaticSolidTrianglesDropped = count - triangles.Count; } int num20 = 0; foreach (KeyValuePair> item14 in xzToLookupKeysTerrain) { if (anchorReachableCells.Contains(item14.Key)) { continue; } foreach (long item15 in item14.Value) { if (lookupGrid.Remove(item15)) { num20++; } } } int num21 = 0; int num22 = 0; foreach (KeyValuePair> item16 in xzToLookupKeysPiece) { foreach (long item17 in item16.Value) { if (!pieceReachableKeys.Contains(item17)) { num22++; if (lookupGrid.Remove(item17)) { num21++; } } } } stats.LookupCellsDropped = num20 + num21; stats.Pass3PieceKeysDropped = num22; if (triangles != null && triangles.Count > 0) { int count2 = triangles.Count; triangles.RemoveAll(delegate(RegionBuilder.CachedTriangle t) { //IL_0001: 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_0018: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) float num30 = (t.V0.x + t.V1.x + t.V2.x) / 3f; float num31 = (t.V0.z + t.V1.z + t.V2.z) / 3f; int gx4 = Mathf.FloorToInt(num30 / cell); int gz4 = Mathf.FloorToInt(num31 / cell); if (((kindMap != null && !string.IsNullOrEmpty(t.RegionId) && kindMap.TryGetValue(t.RegionId, out var value17)) ? value17 : SurfaceKind.Terrain) == SurfaceKind.Piece) { int hb3 = RegionGraph.HeightBucket((t.V0.y + t.V1.y + t.V2.y) / 3f); long item6 = RegionGraph.PackLookup(gx4, gz4, hb3); return !pieceReachableKeys.Contains(item6); } return !anchorReachableCells.Contains(XzKey(gx4, gz4)); }); stats.TrianglesDropped = count2 - triangles.Count; } foreach (string regionId in regionIds) { bool flag2 = false; List value14; if (((kindMap != null && kindMap.TryGetValue(regionId, out var value12)) ? value12 : SurfaceKind.Terrain) == SurfaceKind.Piece) { if (dictionary2.TryGetValue(regionId, out var value13)) { foreach (long item18 in value13) { if (pieceReachableKeys.Contains(item18)) { flag2 = true; break; } } } } else if (dictionary.TryGetValue(regionId, out value14)) { foreach (long item19 in value14) { if (anchorReachableCells.Contains(item19)) { flag2 = true; break; } } } if (!flag2) { dropped.Add(regionId); } } if (dropped.Count > 0) { regionIds.RemoveWhere((string r) => dropped.Contains(r)); foreach (string item20 in dropped) { centroids?.Remove(item20); kindMap?.Remove(item20); } links?.RemoveAll((RegionLink l) => dropped.Contains(l.FromRegionId) || dropped.Contains(l.ToRegionId)); boundaryCells?.RemoveAll(((string id, Vector3 center, Vector3 outwardDir) b) => dropped.Contains(b.id)); } stats.RegionsDropped = dropped.Count; if (links != null && pass3EdgePairs.Count > 0) { HashSet hashSet3 = new HashSet(links.Count); foreach (RegionLink link in links) { hashSet3.Add(CanonicalPair(link.FromRegionId, link.ToRegionId)); } int num23 = 0; foreach (var (text4, text5, positionStart, positionEnd) in pass3EdgePairs) { if (!dropped.Contains(text4) && !dropped.Contains(text5)) { string item2 = CanonicalPair(text4, text5); if (hashSet3.Add(item2) && centroids != null && centroids.ContainsKey(text4) && centroids.ContainsKey(text5)) { links.Add(new RegionLink { FromRegionId = text4, ToRegionId = text5, LinkType = RegionLinkType.Slope, PositionStart = positionStart, PositionEnd = positionEnd }); num23++; } } } stats.Pass3LinksAdded = num23; } ConsolidateLinearChains(regionIds, centroids, lookupGrid, boundaryCells, links, kindMap, triangles, pass3EdgePairs, ref stats); SnapBordersToAgentNavMesh(regionIds, links, triangles, ref stats); LastOutsideCells = new HashSet(outsideCells); Dictionary dictionary5 = new Dictionary(xzMaxYTerrain.Count + xzMaxYPiece.Count); foreach (KeyValuePair item21 in xzMaxYTerrain) { dictionary5[item21.Key] = item21.Value; } foreach (KeyValuePair item22 in xzMaxYPiece) { if (!dictionary5.TryGetValue(item22.Key, out var value15) || item22.Value > value15) { dictionary5[item22.Key] = item22.Value; } } LastXzMaxY = dictionary5; LastGxMin = num; LastGzMin = num2; LastGxMax = num3; LastGzMax = num4; LastCell = cell; LastPieceMask = pieceMask; HasSnapshot = true; if (anchorReachableCells.Count > 0) { int[] array3 = new int[4] { 1, -1, 0, 0 }; int[] array4 = new int[4] { 0, 0, 1, -1 }; List<(string, Vector3, Vector3)> list2 = new List<(string, Vector3, Vector3)>(); Vector3 item4 = default(Vector3); for (int num24 = num; num24 <= num3; num24++) { for (int num25 = num2; num25 <= num4; num25++) { long num26 = XzKey(num24, num25); if (!anchorReachableCells.Contains(num26)) { continue; } Vector3 val = Vector3.zero; for (int num27 = 0; num27 < 4; num27++) { for (int num28 = 1; num28 <= 4; num28++) { long item3 = XzKey(num24 + array3[num27] * num28, num25 + array4[num27] * num28); if (anchorReachableCells.Contains(item3)) { break; } if (outsideCells.Contains(item3)) { val += new Vector3((float)array3[num27], 0f, (float)array4[num27]); break; } } } if (!(((Vector3)(ref val)).sqrMagnitude < 1E-06f)) { bool populated; float num29 = SurfaceY(num26, num24, num25, out populated); ((Vector3)(ref item4))..ctor((float)num24 * cell + cell * 0.5f, num29, (float)num25 * cell + cell * 0.5f); int hb2 = RegionGraph.HeightBucket(num29); string value16; string item5 = (lookupGrid.TryGetValue(RegionGraph.PackLookup(num24, num25, hb2), out value16) ? value16 : "frontier"); list2.Add((item5, item4, ((Vector3)(ref val)).normalized)); } } } if (list2.Count >= 3) { boundaryCells.Clear(); boundaryCells.AddRange(list2); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[RubberBand] Boundary cells from flood frontier: {list2.Count} outer cells"); } } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)($"[RubberBand] Flood frontier degenerate ({list2.Count} cells); " + "keeping upstream region-edge boundary cells")); } } } anchorReachableCellsOut = new HashSet(anchorReachableCells); outsideCellsOut = new HashSet(outsideCells); return stats; static string CanonicalPair(string a, string b) { if (string.CompareOrdinal(a, b) >= 0) { return b + "|" + a; } return a + "|" + b; } static void ComputePieceStepLinkPositions(long fromXz, long toXz, float fromY, float toY, float cellSize, bool sameCell, out Vector3 reference, out Vector3 reference2) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00e0: 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) //IL_0056: 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_0067: Unknown result type (might be due to invalid IL or missing references) UnpackXz(fromXz, out var gx4, out var gz4); UnpackXz(toXz, out var gx5, out var gz5); float num30 = cellSize * 0.5f; float num31 = (float)gx4 * cellSize + num30; float num32 = (float)gz4 * cellSize + num30; float num33 = (float)gx5 * cellSize + num30; float num34 = (float)gz5 * cellSize + num30; if (sameCell) { reference = new Vector3(num31, fromY, num32); reference2 = new Vector3(num31, toY, num32); } else { float num35 = (num31 + num33) * 0.5f; float num36 = (num32 + num34) * 0.5f; float num37 = Mathf.Sign(num33 - num31); float num38 = Mathf.Sign(num34 - num32); reference = new Vector3(num35 - num37 * 0.1f, fromY, num36 - num38 * 0.1f); reference2 = new Vector3(num35 + num37 * 0.1f, toY, num36 + num38 * 0.1f); } } string PieceAtCellInReachable(long xz, float targetY) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (!xzToLookupKeysPiece.TryGetValue(xz, out var value17)) { return null; } string result = null; float num30 = float.MaxValue; foreach (long item23 in value17) { if (pieceReachableKeys.Contains(item23) && lookupGrid.TryGetValue(item23, out var value18) && centroids.TryGetValue(value18, out var value19)) { float num31 = Mathf.Abs(value19.y - targetY); if (!(num31 > 1f) && num31 < num30) { num30 = num31; result = value18; } } } return result; } void RecordPass3Edge(string fromRid, string toRid, Vector3 item7, Vector3 item8) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(fromRid) && !string.IsNullOrEmpty(toRid) && !(fromRid == toRid)) { string item6 = CanonicalPair(fromRid, toRid); if (pass3DiscoveredEdges.Add(item6)) { pass3EdgePairs.Add((fromRid, toRid, item7, item8)); } } } float SurfaceY(long xzKey, int num31, int num32, out bool reference) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) float num30 = float.MinValue; if (xzMaxYTerrain.TryGetValue(xzKey, out var value17)) { num30 = value17; } if (xzMaxYPiece.TryGetValue(xzKey, out var value18) && value18 > num30) { num30 = value18; } reference = num30 > float.MinValue; if (reference) { return num30; } if (!((Object)(object)ZoneSystem.instance != (Object)null)) { return 0f; } return ZoneSystem.instance.GetGroundHeight(new Vector3((float)num31 * cell + cell * 0.5f, 0f, (float)num32 * cell + cell * 0.5f)); } string TerrainRegionAtCell(long xz) { if (!xzToLookupKeysTerrain.TryGetValue(xz, out var value17)) { return null; } foreach (long item24 in value17) { if (lookupGrid.TryGetValue(item24, out var value18)) { return value18; } } return null; } } internal static long DiagnoseXzKey(int gx, int gz) { return XzKey(gx, gz); } internal static float DiagnoseCellY(int gx, int gz) { if (LastXzMaxY == null) { return 0f; } return GetCellY(gx, gz, LastXzMaxY, (LastCell > 0f) ? LastCell : 1f); } internal static HashSet PerimeterOutsideFlood(int gxMin, int gzMin, int gxMax, int gzMax, Func cellY, Func wallBlocks, out int perimeterSeedCount) { HashSet hashSet = new HashSet(); Queue queue = new Queue(); for (int i = gxMin; i <= gxMax; i++) { EnqueuePerimeterSeed(i, gzMin, hashSet, queue); EnqueuePerimeterSeed(i, gzMax, hashSet, queue); } for (int j = gzMin + 1; j <= gzMax - 1; j++) { EnqueuePerimeterSeed(gxMin, j, hashSet, queue); EnqueuePerimeterSeed(gxMax, j, hashSet, queue); } perimeterSeedCount = hashSet.Count; int[] array = new int[4] { 1, -1, 0, 0 }; int[] array2 = new int[4] { 0, 0, 1, -1 }; while (queue.Count > 0) { UnpackXz(queue.Dequeue(), out var gx, out var gz); float arg = cellY(gx, gz); for (int k = 0; k < 4; k++) { int num = gx + array[k]; int num2 = gz + array2[k]; if (num < gxMin || num > gxMax || num2 < gzMin || num2 > gzMax) { continue; } long item = XzKey(num, num2); if (!hashSet.Contains(item)) { float arg2 = cellY(num, num2); if (!wallBlocks(gx, gz, num, num2, arg, arg2)) { hashSet.Add(item); queue.Enqueue(item); } } } } return hashSet; } internal static void AnchorReachableFlood(int gxMin, int gzMin, int gxMax, int gzMax, IReadOnlyList anchors, HashSet outsideCells, float cell, int anchorSnapRingMax, Func isPopulated, Func surfaceY, Func wallBlocks, out HashSet anchorReachableCells, out Dictionary anchorReachableCellY, out int seedCount, Action warn = null) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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) anchorReachableCells = new HashSet(); anchorReachableCellY = new Dictionary(); seedCount = 0; if (anchors == null || anchors.Count == 0) { return; } Queue<(long, float)> queue = new Queue<(long, float)>(); foreach (Vector3 anchor in anchors) { int num = Mathf.FloorToInt(anchor.x / cell); int num2 = Mathf.FloorToInt(anchor.z / cell); int num3 = num; int num4 = num2; bool flag = false; for (int i = 0; i <= anchorSnapRingMax; i++) { if (flag) { break; } for (int j = -i; j <= i; j++) { if (flag) { break; } for (int k = -i; k <= i; k++) { if (flag) { break; } if (Mathf.Max(Mathf.Abs(j), Mathf.Abs(k)) != i) { continue; } int num5 = num + j; int num6 = num2 + k; if (num5 >= gxMin && num5 <= gxMax && num6 >= gzMin && num6 <= gzMax) { long num7 = XzKey(num5, num6); if (!outsideCells.Contains(num7) && isPopulated(num7)) { num3 = num5; num4 = num6; flag = true; } } } } } if (!flag) { warn?.Invoke($"[RubberBand] Pass 2 anchor skipped: anchor=({anchor.x:F1},{anchor.z:F1}) " + $"cell=({num},{num2}) — no populated, non-outside cell within " + $"{anchorSnapRingMax} cells (anchor walled off or outside the village?)."); continue; } long num8 = XzKey(num3, num4); if (anchorReachableCells.Add(num8)) { float num9 = surfaceY(num8, num3, num4); anchorReachableCellY[num8] = num9; queue.Enqueue((num8, num9)); seedCount++; } } int[] array = new int[4] { 1, -1, 0, 0 }; int[] array2 = new int[4] { 0, 0, 1, -1 }; while (queue.Count > 0) { var (key, arg) = queue.Dequeue(); UnpackXz(key, out var gx, out var gz); for (int l = 0; l < 4; l++) { int num10 = gx + array[l]; int num11 = gz + array2[l]; if (num10 < gxMin || num10 > gxMax || num11 < gzMin || num11 > gzMax) { continue; } long num12 = XzKey(num10, num11); if (!anchorReachableCells.Contains(num12) && !outsideCells.Contains(num12)) { float num13 = surfaceY(num12, num10, num11); if (!wallBlocks(gx, gz, num10, num11, arg, num13)) { anchorReachableCells.Add(num12); anchorReachableCellY[num12] = num13; queue.Enqueue((num12, num13)); } } } } } public static HashSet ComputeOutsideCellsForBake(Bounds bounds) { //IL_004d: 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_0082: 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) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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) int pieceMask = LayerMask.GetMask(new string[1] { "piece" }); if (pieceMask == 0) { return new HashSet(); } if ((Object)(object)ZoneSystem.instance == (Object)null) { return new HashSet(); } float cell = 1f; int gxMin = Mathf.FloorToInt(((Bounds)(ref bounds)).min.x / cell) - 1; int gzMin = Mathf.FloorToInt(((Bounds)(ref bounds)).min.z / cell) - 1; int gxMax = Mathf.FloorToInt(((Bounds)(ref bounds)).max.x / cell) + 1; int gzMax = Mathf.FloorToInt(((Bounds)(ref bounds)).max.z / cell) + 1; float half = cell * 0.5f; List gateSeals = GatherGateSeals(((Bounds)(ref bounds)).min.x, ((Bounds)(ref bounds)).min.z, ((Bounds)(ref bounds)).max.x, ((Bounds)(ref bounds)).max.z); int perimeterSeedCount; return PerimeterOutsideFlood(gxMin, gzMin, gxMax, gzMax, (int gx, int gz) => ZoneSystem.instance.GetGroundHeight(new Vector3((float)gx * cell + half, 0f, (float)gz * cell + half)), (int ax, int az, int bx, int bz, float ya, float yb) => WallBlocks(ax, az, bx, bz, ya, yb, cell, pieceMask) || GateBlocksStep(ax, az, bx, bz, cell, gateSeals), out perimeterSeedCount); } public static void UnpackOutsideCellKey(long key, out int gx, out int gz) { UnpackXz(key, out gx, out gz); } public static bool IsOutsideCell(Vector3 worldPos, HashSet outsideCells) { //IL_0013: 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) if (outsideCells == null || outsideCells.Count == 0) { return false; } float num = 1f; int gx = Mathf.FloorToInt(worldPos.x / num); int gz = Mathf.FloorToInt(worldPos.z / num); return outsideCells.Contains(XzKey(gx, gz)); } public static long PackXzKey(int gx, int gz) { return XzKey(gx, gz); } public static List DecomposeToRectangles(HashSet cells) { List list = new List(); if (cells == null || cells.Count == 0) { return list; } HashSet hashSet = new HashSet(cells); List list2 = new List(hashSet); list2.Sort(); foreach (long item in list2) { if (!hashSet.Contains(item)) { continue; } UnpackXz(item, out var gx, out var gz); int i; for (i = gx; hashSet.Contains(XzKey(i + 1, gz)); i++) { } int num = gz; while (true) { int num2 = num + 1; bool flag = true; for (int j = gx; j <= i; j++) { if (!hashSet.Contains(XzKey(j, num2))) { flag = false; break; } } if (!flag) { break; } num = num2; } for (int k = gz; k <= num; k++) { for (int l = gx; l <= i; l++) { hashSet.Remove(XzKey(l, k)); } } list.Add(new CellRect(gx, gz, i, num)); } return list; } private static void EnqueuePerimeterSeed(int gx, int gz, HashSet outsideCells, Queue queue) { long item = XzKey(gx, gz); if (outsideCells.Add(item)) { queue.Enqueue(item); } } private static float GetCellY(int gx, int gz, Dictionary xzMaxY, float cell) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) long key = XzKey(gx, gz); if (xzMaxY.TryGetValue(key, out var value)) { return value; } if ((Object)(object)ZoneSystem.instance == (Object)null) { return 0f; } float num = (float)gx * cell + cell * 0.5f; float num2 = (float)gz * cell + cell * 0.5f; return ZoneSystem.instance.GetGroundHeight(new Vector3(num, 0f, num2)); } private static bool WallBlocks(int gxA, int gzA, int gxB, int gzB, float yA, float yB, float cell, int mask) { if (!ProbeAtWaist(gxA, gzA, gxB, gzB, yA, cell, mask)) { if (yA != yB) { return ProbeAtWaist(gxA, gzA, gxB, gzB, yB, cell, mask); } return false; } return true; } private static bool ProbeAtWaist(int gxA, int gzA, int gxB, int gzB, float floorY, float cell, int mask) { //IL_0011: 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_0018: Unknown result type (might be due to invalid IL or missing references) ComputeWaistProbeBox(gxA, gzA, gxB, gzB, floorY, cell, out var center, out var halfExtents); int num = Physics.OverlapBoxNonAlloc(center, halfExtents, s_waistProbeBuf, Quaternion.identity, mask, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider val = s_waistProbeBuf[i]; if (!((Object)(object)val == (Object)null) && !IsBedCollider(val)) { return true; } } return false; } private static bool IsBedCollider(Collider col) { return (Object)(object)((Component)col).GetComponentInParent() != (Object)null; } internal static List GatherGateSeals(float minX, float minZ, float maxX, float maxZ) { //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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Door[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (Door val in array) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null) { continue; } Vector3 position = ((Component)val).transform.position; if (!(position.x < minX) && !(position.x > maxX) && !(position.z < minZ) && !(position.z > maxZ)) { Vector3 forward = ((Component)val).transform.forward; forward.y = 0f; if (!(((Vector3)(ref forward)).sqrMagnitude < 0.0001f)) { ((Vector3)(ref forward)).Normalize(); list.Add(new GateSeal(position, forward, GateHalfWidth(val))); } } } return list; } private static float GateHalfWidth(Door door) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0067: Unknown result type (might be due to invalid IL or missing references) float num = 0f; Collider[] componentsInChildren = ((Component)door).GetComponentsInChildren(true); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.isTrigger) { BoxCollider val2 = (BoxCollider)(object)((val is BoxCollider) ? val : null); if (val2 != null) { Vector3 lossyScale = ((Component)val2).transform.lossyScale; num = Mathf.Max(num, Mathf.Max(Mathf.Abs(val2.size.x * lossyScale.x), Mathf.Abs(val2.size.z * lossyScale.z))); } } } if (num <= 0f) { num = 1.2f; } return num * 0.5f + 0.5f; } private static bool GateBlocksStep(int gxA, int gzA, int gxB, int gzB, float cell, List seals) { if (seals == null || seals.Count == 0) { return false; } float num = cell * 0.5f; float ax = (float)gxA * cell + num; float az = (float)gzA * cell + num; float bx = (float)gxB * cell + num; float bz = (float)gzB * cell + num; foreach (GateSeal seal in seals) { if (SegmentCrossesGateXz(ax, az, bx, bz, seal)) { return true; } } return false; } private static bool SegmentCrossesGateXz(float ax, float az, float bx, float bz, GateSeal s) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) float num = (ax - s.Mid.x) * s.Forward.x + (az - s.Mid.z) * s.Forward.z; float num2 = (bx - s.Mid.x) * s.Forward.x + (bz - s.Mid.z) * s.Forward.z; if (num >= 0f == num2 >= 0f) { return false; } float num3 = num - num2; if (Mathf.Abs(num3) < 1E-05f) { return false; } float num4 = num / num3; float num5 = ax + (bx - ax) * num4; float num6 = az + (bz - az) * num4; float num7 = num5 - s.Mid.x; float num8 = num6 - s.Mid.z; return num7 * num7 + num8 * num8 <= s.HalfWidth * s.HalfWidth; } private static void ConsolidateLinearChains(HashSet regionIds, Dictionary centroids, Dictionary lookupGrid, List<(string id, Vector3 center, Vector3 outwardDir)> boundaryCells, List links, Dictionary kindMap, List triangles, List<(string fromRid, string toRid, Vector3 startPos, Vector3 endPos)> pass3EdgePairs, ref Stats stats) { //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_0722: Unknown result type (might be due to invalid IL or missing references) //IL_0729: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_06d4: Unknown result type (might be due to invalid IL or missing references) //IL_06db: Unknown result type (might be due to invalid IL or missing references) if (links == null || links.Count == 0 || regionIds == null || regionIds.Count == 0) { return; } Dictionary> dictionary = new Dictionary>(); foreach (RegionLink link in links) { if (kindMap == null) { break; } if (kindMap.TryGetValue(link.FromRegionId, out var value) && kindMap.TryGetValue(link.ToRegionId, out var value2) && value == SurfaceKind.Piece && value2 == SurfaceKind.Piece) { if (!dictionary.TryGetValue(link.FromRegionId, out var value3)) { value3 = new HashSet(); dictionary[link.FromRegionId] = value3; } value3.Add(link.ToRegionId); if (!dictionary.TryGetValue(link.ToRegionId, out var value4)) { value4 = new HashSet(); dictionary[link.ToRegionId] = value4; } value4.Add(link.FromRegionId); } } if (dictionary.Count == 0) { return; } HashSet hashSet = new HashSet(); Dictionary dictionary2 = new Dictionary(); int num = 0; int num2 = 0; foreach (string key in dictionary.Keys) { if (hashSet.Contains(key) || dictionary[key].Count != 1) { continue; } List list = new List { key }; hashSet.Add(key); string text = null; string text2 = key; while (true) { string text3 = null; foreach (string item3 in dictionary[text2]) { if (item3 != text) { text3 = item3; break; } } if (text3 == null || hashSet.Contains(text3) || !dictionary.TryGetValue(text3, out var value5) || value5.Count > 2) { break; } list.Add(text3); hashSet.Add(text3); if (value5.Count == 1) { break; } text = text2; text2 = text3; } if (list.Count < 2) { continue; } Vector3 val = Vector3.zero; int num3 = 0; while (true) { Vector3 val3; if (num3 < list.Count - 1) { if (!centroids.TryGetValue(list[num3], out var value6) || !centroids.TryGetValue(list[num3 + 1], out var value7)) { break; } Vector3 val2 = val; val3 = value7 - value6; val = val2 + ((Vector3)(ref val3)).normalized; num3++; continue; } val3 = val / (float)(list.Count - 1); val = ((Vector3)(ref val3)).normalized; if (Mathf.Abs(val.y) < 0.1f) { break; } bool flag = true; for (int i = 0; i < list.Count - 1; i++) { val3 = centroids[list[i + 1]] - centroids[list[i]]; if (Vector3.Dot(((Vector3)(ref val3)).normalized, val) < 0.94f) { flag = false; break; } } if (!flag) { break; } string text4 = list[0]; Vector3 val4 = Vector3.zero; foreach (string item4 in list) { val4 += centroids[item4]; } centroids[text4] = val4 / (float)list.Count; for (int j = 1; j < list.Count; j++) { dictionary2[list[j]] = text4; num2++; } num++; break; } } if (dictionary2.Count == 0) { stats.Pass5ChainsConsolidated = 0; stats.Pass5RegionsConsumed = 0; stats.Pass5LinksRemoved = 0; return; } foreach (string key2 in dictionary2.Keys) { regionIds.Remove(key2); centroids?.Remove(key2); kindMap?.Remove(key2); } if (triangles != null) { for (int k = 0; k < triangles.Count; k++) { RegionBuilder.CachedTriangle value8 = triangles[k]; if (dictionary2.TryGetValue(value8.RegionId, out var value9)) { value8.RegionId = value9; triangles[k] = value8; } } } if (lookupGrid != null) { List list2 = new List(); foreach (KeyValuePair item5 in lookupGrid) { if (dictionary2.ContainsKey(item5.Value)) { list2.Add(item5.Key); } } foreach (long item6 in list2) { lookupGrid[item6] = dictionary2[lookupGrid[item6]]; } } int num4 = 0; if (links != null) { HashSet hashSet2 = new HashSet(); for (int num5 = links.Count - 1; num5 >= 0; num5--) { RegionLink value10 = links[num5]; string value11; string text5 = (dictionary2.TryGetValue(value10.FromRegionId, out value11) ? value11 : value10.FromRegionId); string value12; string text6 = (dictionary2.TryGetValue(value10.ToRegionId, out value12) ? value12 : value10.ToRegionId); if (text5 == text6) { links.RemoveAt(num5); num4++; } else { string item = ((string.CompareOrdinal(text5, text6) < 0) ? (text5 + "|" + text6) : (text6 + "|" + text5)); if (!hashSet2.Add(item)) { links.RemoveAt(num5); num4++; } else { value10.FromRegionId = text5; value10.ToRegionId = text6; links[num5] = value10; } } } } if (pass3EdgePairs != null) { HashSet hashSet3 = new HashSet(); for (int num6 = pass3EdgePairs.Count - 1; num6 >= 0; num6--) { (string, string, Vector3, Vector3) tuple = pass3EdgePairs[num6]; string text7; if (!dictionary2.TryGetValue(tuple.Item1, out var value13)) { (text7, _, _, _) = tuple; } else { text7 = value13; } string text8 = text7; string value14; string text9 = (dictionary2.TryGetValue(tuple.Item2, out value14) ? value14 : tuple.Item2); if (text8 == text9) { pass3EdgePairs.RemoveAt(num6); } else { string item2 = ((string.CompareOrdinal(text8, text9) < 0) ? (text8 + "|" + text9) : (text9 + "|" + text8)); if (!hashSet3.Add(item2)) { pass3EdgePairs.RemoveAt(num6); } else { pass3EdgePairs[num6] = (text8, text9, tuple.Item3, tuple.Item4); } } } } if (boundaryCells != null) { for (int l = 0; l < boundaryCells.Count; l++) { (string, Vector3, Vector3) tuple3 = boundaryCells[l]; if (dictionary2.TryGetValue(tuple3.Item1, out var value15)) { boundaryCells[l] = (value15, tuple3.Item2, tuple3.Item3); } } } stats.Pass5ChainsConsolidated = num; stats.Pass5RegionsConsumed = num2; stats.Pass5LinksRemoved = num4; DebugLog.Event("RubberBandPrune", "pass5_chain_consolidation", ("chains_consolidated", num), ("regions_consumed", num2), ("links_removed", num4)); } private static void SnapBordersToAgentNavMesh(HashSet regionIds, List links, List triangles, ref Stats stats) { //IL_001c: 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) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) if (!VillagerAgentType.IsRegistered || triangles == null || triangles.Count == 0) { return; } int unityAgentTypeID = VillagerAgentType.UnityAgentTypeID; NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = unityAgentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; Dictionary> dictionary = new Dictionary>(); for (int i = 0; i < triangles.Count; i++) { string regionId = triangles[i].RegionId; if (!string.IsNullOrEmpty(regionId) && regionIds.Contains(regionId)) { if (!dictionary.TryGetValue(regionId, out var value)) { value = (dictionary[regionId] = new List()); } value.Add(i); } } Dictionary dictionary2 = new Dictionary(); int snapped = 0; int misses = 0; foreach (KeyValuePair> item in dictionary) { List value2 = item.Value; Dictionary dictionary3 = new Dictionary(); Dictionary dictionary4 = new Dictionary(); foreach (int item2 in value2) { RegionBuilder.CachedTriangle cachedTriangle = triangles[item2]; AddEdgeForSnap(dictionary3, dictionary4, cachedTriangle.V0, cachedTriangle.V1); AddEdgeForSnap(dictionary3, dictionary4, cachedTriangle.V1, cachedTriangle.V2); AddEdgeForSnap(dictionary3, dictionary4, cachedTriangle.V2, cachedTriangle.V0); } foreach (KeyValuePair item3 in dictionary3) { if (item3.Value == 1) { var (v, v2) = dictionary4[item3.Key]; TrySnapAndCache(v, val2, 0.5f, dictionary2, ref snapped, ref misses); TrySnapAndCache(v2, val2, 0.5f, dictionary2, ref snapped, ref misses); } } } for (int j = 0; j < triangles.Count; j++) { RegionBuilder.CachedTriangle value3 = triangles[j]; bool flag = false; if (dictionary2.TryGetValue(value3.V0, out var value4) && value4 != value3.V0) { value3.V0 = value4; flag = true; } if (dictionary2.TryGetValue(value3.V1, out var value5) && value5 != value3.V1) { value3.V1 = value5; flag = true; } if (dictionary2.TryGetValue(value3.V2, out var value6) && value6 != value3.V2) { value3.V2 = value6; flag = true; } if (flag) { triangles[j] = value3; } } int num = 0; if (links != null) { NavMeshHit val3 = default(NavMeshHit); NavMeshHit val4 = default(NavMeshHit); for (int k = 0; k < links.Count; k++) { RegionLink value7 = links[k]; bool flag2 = false; if (NavMesh.SamplePosition(value7.PositionStart, ref val3, 0.5f, val2) && value7.PositionStart != ((NavMeshHit)(ref val3)).position) { value7.PositionStart = ((NavMeshHit)(ref val3)).position; flag2 = true; } if (NavMesh.SamplePosition(value7.PositionEnd, ref val4, 0.5f, val2) && value7.PositionEnd != ((NavMeshHit)(ref val4)).position) { value7.PositionEnd = ((NavMeshHit)(ref val4)).position; flag2 = true; } if (flag2) { links[k] = value7; num++; } } } stats.Pass4BoundaryVertsSnapped = snapped; stats.Pass4SnapMisses = misses; stats.Pass4LinksSnapped = num; DebugLog.Event("RubberBandPrune", "pass4_border_snap", ("boundary_verts_snapped", snapped), ("snap_misses", misses), ("links_snapped", num)); } private unsafe static void AddEdgeForSnap(Dictionary edgeCount, Dictionary edgeVerts, Vector3 a, Vector3 b) { //IL_0053: 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) int hashCode = ((object)(*(Vector3*)(&a))/*cast due to .constrained prefix*/).GetHashCode(); int hashCode2 = ((object)(*(Vector3*)(&b))/*cast due to .constrained prefix*/).GetHashCode(); long key = ((hashCode <= hashCode2) ? (((long)hashCode << 32) | (uint)hashCode2) : (((long)hashCode2 << 32) | (uint)hashCode)); if (edgeCount.TryGetValue(key, out var value)) { edgeCount[key] = value + 1; return; } edgeCount[key] = 1; edgeVerts[key] = (a, b); } private static void TrySnapAndCache(Vector3 v, NavMeshQueryFilter filter, float radius, Dictionary cache, ref int snapped, ref int misses) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (cache.ContainsKey(v)) { return; } NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(v, ref val, radius, filter)) { cache[v] = ((NavMeshHit)(ref val)).position; if (((NavMeshHit)(ref val)).position != v) { snapped++; } } else { cache[v] = v; misses++; } } internal static bool Diagnose(int gxA, int gzA, int gxB, int gzB, float yA, float yB, float cell, int mask, out string hitNames) { //IL_0011: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) ComputeWaistProbeBox(gxA, gzA, gxB, gzB, yA, cell, out var center, out var halfExtents); Collider[] array = Physics.OverlapBox(center, halfExtents, Quaternion.identity, mask, (QueryTriggerInteraction)1); Collider[] array2 = null; if (yA != yB) { ComputeWaistProbeBox(gxA, gzA, gxB, gzB, yB, cell, out var center2, out var halfExtents2); array2 = Physics.OverlapBox(center2, halfExtents2, Quaternion.identity, mask, (QueryTriggerInteraction)1); } int num = ((array != null) ? array.Length : 0) + ((array2 != null) ? array2.Length : 0); if (num == 0) { hitNames = ""; return false; } List names = new List(Mathf.Min(num, 8)); bool blocked = false; AddNames(array, 4); AddNames(array2, 4); hitNames = string.Join(";", names); if (num > names.Count) { hitNames += $";+{num - names.Count}"; } return blocked; void AddNames(Collider[] arr, int max) { if (arr != null) { for (int i = 0; i < arr.Length; i++) { Collider val = arr[i]; bool flag = (Object)(object)val != (Object)null && IsBedCollider(val); if (!flag && (Object)(object)val != (Object)null) { blocked = true; } if (i < max) { if ((Object)(object)val == (Object)null) { names.Add(""); } else { names.Add(flag ? (((Object)val).name + "(bed,ignored)") : ((Object)val).name); } } } } } } private static void ComputeWaistProbeBox(int gxA, int gzA, int gxB, int gzB, float floorY, float cell, out Vector3 center, out Vector3 halfExtents) { //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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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) float num = cell * 0.5f; float num2 = floorY + 0.7f; float num3 = floorY + 1.3f; float num4 = (num2 + num3) * 0.5f; float num5 = (num3 - num2) * 0.5f; float num6 = (float)(gxA + gxB) * 0.5f * cell + num; float num7 = (float)(gzA + gzB) * 0.5f * cell + num; center = new Vector3(num6, num4, num7); int num8 = gxB - gxA; int num9 = gzB - gzA; if ((num8 != 0 && num9 == 0) || (num9 != 0 && num8 == 0)) { halfExtents = new Vector3(num, num5, num); return; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[RubberBand] ComputeWaistProbeBox called with non-cardinal step " + $"({gxA},{gzA})->({gxB},{gzB}); 4-neighbour BFS contract violated.")); } halfExtents = new Vector3(num, num5, num); } private static long XzKey(int gx, int gz) { return RegionGraph.PackXz(gx, gz); } private static void UnpackXz(long key, out int gx, out int gz) { RegionGraph.UnpackXz(key, out gx, out gz); } internal static void UnpackLookup(long key, out int gx, out int gz, out int hb) { long num = key % 1000003; if (num > 500001) { num -= 1000003; } else if (num < -500001) { num += 1000003; } long num2 = (key - num) / 1000003; long num3 = num2 % 1000003; if (num3 > 500001) { num3 -= 1000003; } else if (num3 < -500001) { num3 += 1000003; } long num4 = (num2 - num3) / 1000003; hb = (int)num; gz = (int)num3; gx = (int)num4; } } public static class SpatialDump { private const float CellSize = 4f; private const float ScanRadius = 50f; private const float RaycastHeight = 3f; private const float RaycastMaxDown = 8f; private const float HeightStep = 3f; private const float HeightMarginBelow = 5f; private const float HeightMarginAbove = 10f; private static readonly int GroundMask = LayerMask.GetMask(new string[4] { "Default", "static_solid", "terrain", "piece" }); [DevCommand("Dump spatial data (anchors, height grid, doors, pieces) to JSON for offline testing", Name = "vv_hna_dump")] public static void Dump() { //IL_0049: 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_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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: 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_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_04ff: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_0515: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_0529: Unknown result type (might be due to invalid IL or missing references) //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_066a: Unknown result type (might be due to invalid IL or missing references) //IL_066c: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_055d: Unknown result type (might be due to invalid IL or missing references) //IL_0694: Unknown result type (might be due to invalid IL or missing references) //IL_058f: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Unknown result type (might be due to invalid IL or missing references) //IL_05ad: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Unknown result type (might be due to invalid IL or missing references) //IL_05cb: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Unknown result type (might be due to invalid IL or missing references) //IL_06a8: Unknown result type (might be due to invalid IL or missing references) //IL_06e7: Unknown result type (might be due to invalid IL or missing references) //IL_06ec: Unknown result type (might be due to invalid IL or missing references) //IL_06f0: Unknown result type (might be due to invalid IL or missing references) //IL_06e0: Unknown result type (might be due to invalid IL or missing references) //IL_06f5: Unknown result type (might be due to invalid IL or missing references) //IL_06fe: Unknown result type (might be due to invalid IL or missing references) //IL_0703: Unknown result type (might be due to invalid IL or missing references) //IL_073e: Unknown result type (might be due to invalid IL or missing references) //IL_074d: Unknown result type (might be due to invalid IL or missing references) //IL_075c: Unknown result type (might be due to invalid IL or missing references) //IL_077b: Unknown result type (might be due to invalid IL or missing references) //IL_078a: Unknown result type (might be due to invalid IL or missing references) //IL_0799: Unknown result type (might be due to invalid IL or missing references) //IL_07ba: Unknown result type (might be due to invalid IL or missing references) //IL_07c6: Unknown result type (might be due to invalid IL or missing references) //IL_07d2: Unknown result type (might be due to invalid IL or missing references) List allAnchorPositions = VillagerAIManager.GetAllAnchorPositions(); if (allAnchorPositions == null || allAnchorPositions.Count == 0) { Console instance = Console.instance; if (instance != null) { instance.Print("No villager anchors found."); } return; } float minX; float minZ; float maxX; float maxZ; bool flag = VillageAreaManager.TryGetCombinedBounds(out minX, out minZ, out maxX, out maxZ); float num; float num2; float num3; float num4; if (flag) { num = minX; num2 = minZ; num3 = maxX; num4 = maxZ; } else { num = (num3 = allAnchorPositions[0].x); num2 = (num4 = allAnchorPositions[0].z); } foreach (Vector3 item2 in allAnchorPositions) { if (item2.x - 50f < num) { num = item2.x - 50f; } if (item2.z - 50f < num2) { num2 = item2.z - 50f; } if (item2.x + 50f > num3) { num3 = item2.x + 50f; } if (item2.z + 50f > num4) { num4 = item2.z + 50f; } } float num5 = num; float num6 = num2; int num7 = Mathf.Max(1, Mathf.CeilToInt((num3 - num) / 4f)); int num8 = Mathf.Max(1, Mathf.CeilToInt((num4 - num2) / 4f)); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{\n"); stringBuilder.Append(" \"anchors\": [\n"); for (int i = 0; i < allAnchorPositions.Count; i++) { Vector3 val = allAnchorPositions[i]; stringBuilder.Append($" [{val.x:F2}, {val.y:F2}, {val.z:F2}]"); stringBuilder.Append((i < allAnchorPositions.Count - 1) ? ",\n" : "\n"); } stringBuilder.Append(" ],\n"); if (flag) { stringBuilder.Append($" \"patrolBounds\": [{minX:F2}, {minZ:F2}, {maxX:F2}, {maxZ:F2}],\n"); } else { stringBuilder.Append(" \"patrolBounds\": null,\n"); } stringBuilder.Append($" \"cellSize\": {4f:F1},\n"); stringBuilder.Append($" \"origin\": [{num5:F2}, {num6:F2}],\n"); stringBuilder.Append($" \"gridSize\": [{num7}, {num8}],\n"); stringBuilder.Append(" \"heightGrid\": [\n"); int num9 = ((GroundMask != 0) ? GroundMask : (-1)); float[] array = GatherReferenceHeights(allAnchorPositions); RaycastHit val2 = default(RaycastHit); for (int j = 0; j < num8; j++) { for (int k = 0; k < num7; k++) { float num10 = num5 + ((float)k + 0.5f) * 4f; float num11 = num6 + ((float)j + 0.5f) * 4f; stringBuilder.Append(" { "); stringBuilder.Append($"\"ix\": {k}, \"iz\": {j}, "); stringBuilder.Append($"\"wx\": {num10:F2}, \"wz\": {num11:F2}, "); stringBuilder.Append("\"hits\": ["); HashSet hashSet = new HashSet(); bool flag2 = true; float[] array2 = array; foreach (float num12 in array2) { if (!Physics.Raycast(new Vector3(num10, num12 + 3f, num11), Vector3.down, ref val2, 8f, num9, (QueryTriggerInteraction)1)) { continue; } int item = Mathf.RoundToInt(((RaycastHit)(ref val2)).point.y * 4f); if (hashSet.Add(item)) { if (!flag2) { stringBuilder.Append(", "); } string text = LayerMask.LayerToName(((Component)((RaycastHit)(ref val2)).collider).gameObject.layer); stringBuilder.Append($"{{\"refY\": {num12:F2}, \"hitY\": {((RaycastHit)(ref val2)).point.y:F2}, \"layer\": \"{text}\", \"layerIdx\": {((Component)((RaycastHit)(ref val2)).collider).gameObject.layer}}}"); flag2 = false; } } stringBuilder.Append("] }"); bool flag3 = j == num8 - 1 && k == num7 - 1; stringBuilder.Append(flag3 ? "\n" : ",\n"); } } stringBuilder.Append(" ],\n"); stringBuilder.Append(" \"doors\": [\n"); Door[] array3 = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); int num13 = 0; Door[] array4 = array3; foreach (Door val3 in array4) { if ((Object)(object)val3 == (Object)null) { continue; } Vector3 position = ((Component)val3).transform.position; if (!(position.x < num - 10f) && !(position.x > num3 + 10f) && !(position.z < num2 - 10f) && !(position.z > num4 + 10f)) { Vector3 forward = ((Component)val3).transform.forward; bool flag4 = (Object)(object)((Component)val3).GetComponentInParent() != (Object)null; if (num13 > 0) { stringBuilder.Append(",\n"); } stringBuilder.Append(string.Format(" {{\"pos\": [{0:F2}, {1:F2}, {2:F2}], \"forward\": [{3:F3}, {4:F3}, {5:F3}], \"hasPiece\": {6}}}", position.x, position.y, position.z, forward.x, forward.y, forward.z, flag4 ? "true" : "false")); num13++; } } stringBuilder.Append("\n ],\n"); stringBuilder.Append(" \"buildingPieces\": [\n"); Piece[] array5 = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); int num14 = 0; Piece[] array6 = array5; foreach (Piece val4 in array6) { if ((Object)(object)val4 == (Object)null) { continue; } Vector3 position2 = ((Component)val4).transform.position; if (!(position2.x < num - 5f) && !(position2.x > num3 + 5f) && !(position2.z < num2 - 5f) && !(position2.z > num4 + 5f)) { string s = val4.m_name ?? ((Object)((Component)val4).gameObject).name; Collider component = ((Component)val4).GetComponent(); Vector3 val5; if (component == null) { val5 = Vector3.zero; } else { Bounds bounds = component.bounds; val5 = ((Bounds)(ref bounds)).extents; } Vector3 val6 = val5; Vector3 forward2 = ((Component)val4).transform.forward; int layer = ((Component)val4).gameObject.layer; if (num14 > 0) { stringBuilder.Append(",\n"); } stringBuilder.Append($" {{\"name\": \"{EscapeJson(s)}\", \"pos\": [{position2.x:F2}, {position2.y:F2}, {position2.z:F2}], " + $"\"fwd\": [{forward2.x:F3}, {forward2.y:F3}, {forward2.z:F3}], \"layer\": {layer}, " + $"\"extents\": [{val6.x:F2}, {val6.y:F2}, {val6.z:F2}]}}"); num14++; } } stringBuilder.Append("\n ]\n"); stringBuilder.Append("}\n"); string text2 = Path.Combine(Paths.ConfigPath, "vv_dumps", "hna_spatial_dump.json"); Directory.CreateDirectory(Path.GetDirectoryName(text2)); File.WriteAllText(text2, stringBuilder.ToString()); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print($"HNA spatial dump written to {text2} ({allAnchorPositions.Count} anchors, {num7}x{num8} grid, {num13} doors, {num14} pieces)"); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Region] Spatial dump: " + text2)); } } private static float[] GatherReferenceHeights(List anchors) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); foreach (Vector3 anchor in anchors) { int num = Mathf.FloorToInt((anchor.y - 5f) / 3f) * 3; int num2 = Mathf.CeilToInt((anchor.y + 10f) / 3f) * 3; for (int i = num; i <= num2; i += 3) { hashSet.Add(i); } } List list = new List(hashSet); list.Sort(); return list.ConvertAll((Converter)((int h) => h)).ToArray(); } private static string EscapeJson(string s) { if (s == null) { return ""; } return s.Replace("\\", "\\\\").Replace("\"", "\\\""); } } public class HnaPathRecorder : MonoBehaviour { private const float SampleInterval = 0.3f; private const float MinMoveDist = 0.5f; private static HnaPathRecorder s_instance; private static readonly List s_positions = new List(); private Vector3 _lastPos; private float _timer; private void Update() { //IL_004f: 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_007b: 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_0083: 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_0064: Unknown result type (might be due to invalid IL or missing references) _timer -= Time.deltaTime; if (_timer > 0f) { return; } _timer = 0.3f; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Component)localPlayer).transform == (Object)null)) { Vector3 position = ((Component)localPlayer).transform.position; if (s_positions.Count <= 0 || !(Vector3.Distance(position, _lastPos) < 0.5f)) { s_positions.Add(position); _lastPos = position; } } } [DevCommand("Start recording player path for walkable ground truth", Name = "vv_hna_record_start")] public static void StartRecording() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown if ((Object)(object)s_instance != (Object)null) { Console instance = Console.instance; if (instance != null) { instance.Print("Already recording. Use vv_hna_record_stop to stop."); } return; } s_positions.Clear(); GameObject val = new GameObject("HnaPathRecorder"); Object.DontDestroyOnLoad((Object)val); s_instance = val.AddComponent(); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print("Recording player path. Walk around all walkable areas, then run: vv_hna_record_stop"); } } [DevCommand("Stop recording and save path to vv_dumps/hna_walkable_path.json", Name = "vv_hna_record_stop")] public static void StopRecording() { if ((Object)(object)s_instance == (Object)null) { Console instance = Console.instance; if (instance != null) { instance.Print("Not recording. Use vv_hna_record_start first."); } } else { Object.Destroy((Object)(object)((Component)s_instance).gameObject); s_instance = null; SavePath(); } } private static void SavePath() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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) //IL_0080: 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) if (s_positions.Count == 0) { Console instance = Console.instance; if (instance != null) { instance.Print("No positions recorded."); } return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{\n"); stringBuilder.Append($" \"count\": {s_positions.Count},\n"); stringBuilder.Append(" \"positions\": [\n"); for (int i = 0; i < s_positions.Count; i++) { Vector3 val = s_positions[i]; stringBuilder.Append($" [{val.x:F2}, {val.y:F2}, {val.z:F2}]"); stringBuilder.Append((i < s_positions.Count - 1) ? ",\n" : "\n"); } stringBuilder.Append(" ]\n"); stringBuilder.Append("}\n"); string text = Path.Combine(Paths.ConfigPath, "vv_dumps", "hna_walkable_path.json"); Directory.CreateDirectory(Path.GetDirectoryName(text)); File.WriteAllText(text, stringBuilder.ToString()); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print($"Saved {s_positions.Count} positions to {text}"); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Region] Walkable path recording: {s_positions.Count} positions → {text}"); } } } public static class VillageNavLock { private static float s_holdUntil; public static bool IsHeld => Time.time < s_holdUntil; public static float SecondsRemaining => Mathf.Max(0f, s_holdUntil - Time.time); public static void RequestHold(float seconds) { float num = Time.time + seconds; if (num > s_holdUntil) { s_holdUntil = num; } } } public static class VillagerMovement { private const float ApproachProbeRadius = 1.5f; private static readonly Vector3[] s_probeOffsets = BuildProbeOffsets(); public static bool IsAtPosition(Vector3 villagerPos, Vector3 target, float threshold) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(villagerPos, target) < threshold; } public static bool TryFindCompletePath(Vector3 start, Vector3 end, List outPath) { //IL_0014: 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_002f: 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_0031: 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) outPath?.Clear(); if (!VillagerAgentType.IsRegistered) { return false; } NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = VillagerAgentType.UnityAgentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter filter = val; return TryFindUnconstrainedPath(start, end, filter, outPath); } private static bool TryFindUnconstrainedPath(Vector3 start, Vector3 end, NavMeshQueryFilter filter, List outPath) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_001a: 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_002a: Expected O, but got Unknown //IL_002c: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(start, ref val, 3f, filter)) { return false; } NavMeshHit val2 = default(NavMeshHit); if (!NavMesh.SamplePosition(end, ref val2, 3f, filter)) { return false; } NavMeshPath val3 = new NavMeshPath(); if (!NavMesh.CalculatePath(((NavMeshHit)(ref val)).position, ((NavMeshHit)(ref val2)).position, filter, val3)) { return false; } if ((int)val3.status != 0) { return false; } if (outPath != null) { Vector3[] corners = val3.corners; for (int i = 0; i < corners.Length; i++) { outPath.Add(corners[i]); } } return true; } public static bool TryFindReachableApproach(Vector3 target, float maxRadius, out Vector3 approachPoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) approachPoint = target; if (!VillagerAgentType.IsRegistered) { return false; } NavMeshQueryFilter val = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val)).agentTypeID = VillagerAgentType.UnityAgentTypeID; ((NavMeshQueryFilter)(ref val)).areaMask = -1; NavMeshQueryFilter val2 = val; NavMeshHit val3 = default(NavMeshHit); if (!NavMesh.SamplePosition(target, ref val3, maxRadius, val2)) { return false; } approachPoint = ((NavMeshHit)(ref val3)).position; return true; } public static bool TryResolveApproach(Vector3 target, Vector3 pathSource, Func hullPredicate, out Vector3 approach) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_004a: Unknown result type (might be due to invalid IL or missing references) approach = target; Vector3[] array = s_probeOffsets; List outPath = new List(); for (int i = 0; i < array.Length; i++) { if (TryFindReachableApproach(target + array[i], 1.5f, out var approachPoint) && (hullPredicate == null || hullPredicate(approachPoint)) && TryFindCompletePath(pathSource, approachPoint, outPath)) { approach = approachPoint; return true; } } return false; } private static Vector3[] BuildProbeOffsets() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) List list = new List { Vector3.zero }; float[] array = new float[2] { 2f, 4f }; foreach (float num in array) { list.Add(new Vector3(0f, 0f, num)); list.Add(new Vector3(num, 0f, 0f)); list.Add(new Vector3(0f, 0f, 0f - num)); list.Add(new Vector3(0f - num, 0f, 0f)); list.Add(new Vector3(num, 0f, num)); list.Add(new Vector3(num, 0f, 0f - num)); list.Add(new Vector3(0f - num, 0f, 0f - num)); list.Add(new Vector3(0f - num, 0f, num)); } return list.ToArray(); } } } namespace ValheimVillages.Villager.AI.Memory { public class VillagerMemory : IVillagerMemory { private const string ZdoKeyBestComfort = "vv_memory_best_comfort"; private const string ZdoKeyBestComfortPos = "vv_memory_best_comfort_pos"; public float BestComfortLevel { get; set; } public Vector3? BestComfortPosition { get; set; } public Vector3 HomeAnchor { get; set; } public VillagerMemory(Vector3 anchorPosition) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) HomeAnchor = anchorPosition; } public void UpdateBestComfort(float comfort, Vector3 position) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (comfort > BestComfortLevel) { BestComfortLevel = comfort; BestComfortPosition = position; } } public void SaveToZDO(ZDO zdo) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return; } try { zdo.Set("vv_memory_best_comfort", BestComfortLevel); if (BestComfortPosition.HasValue) { zdo.Set("vv_memory_best_comfort_pos", BestComfortPosition.Value); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("Failed to save villager memory: " + ex.Message)); } } } public void LoadFromZDO(ZDO zdo) { //IL_0021: 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) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return; } try { BestComfortLevel = zdo.GetFloat("vv_memory_best_comfort", 0f); Vector3 vec = zdo.GetVec3("vv_memory_best_comfort_pos", Vector3.zero); if (vec != Vector3.zero) { BestComfortPosition = vec; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("Failed to load villager memory: " + ex.Message)); } } } } } namespace ValheimVillages.Testing { public static class ModAssert { public class CollectScope : IDisposable { private readonly List _previous; public CollectScope() { _previous = s_collected; s_collected = new List(); } public void Dispose() { List s_collected = ModAssert.s_collected; ModAssert.s_collected = _previous; if (s_collected != null && s_collected.Count > 0) { throw new ModAssertException(s_collected); } } } [ThreadStatic] private static List s_collected; public static void True(bool condition, string message) { if (!condition) { AssertionEntry item = new AssertionEntry { Message = message, Expected = "true", Actual = "false" }; if (s_collected == null) { throw new ModAssertException(message, "true", "false"); } s_collected.Add(item); } } public static void Equal(T expected, T actual, string message) { if (EqualityComparer.Default.Equals(expected, actual)) { return; } ref T reference = ref expected; T val = default(T); object obj; if (val == null) { val = reference; reference = ref val; if (val == null) { obj = null; goto IL_0040; } } obj = reference.ToString(); goto IL_0040; IL_007b: object obj2; if (obj2 == null) { obj2 = "null"; } string actual2 = (string)obj2; string expected2; AssertionEntry item = new AssertionEntry { Message = message, Expected = expected2, Actual = actual2 }; if (s_collected != null) { s_collected.Add(item); return; } throw new ModAssertException(message, expected2, actual2); IL_0040: if (obj == null) { obj = "null"; } expected2 = (string)obj; ref T reference2 = ref actual; val = default(T); if (val == null) { val = reference2; reference2 = ref val; if (val == null) { obj2 = null; goto IL_007b; } } obj2 = reference2.ToString(); goto IL_007b; } public static void NotNull(object obj, string message) { if (obj == null) { AssertionEntry item = new AssertionEntry { Message = message, Expected = "not null", Actual = "null" }; if (s_collected == null) { throw new ModAssertException(message, "not null", "null"); } s_collected.Add(item); } } public static CollectScope Collect() { return new CollectScope(); } } public class AssertionEntry { public string Actual; public string Expected; public string Message; } public class ModAssertException : Exception { public List Assertions { get; } public ModAssertException(string message) : base(message) { Assertions = new List { new AssertionEntry { Message = message } }; } public ModAssertException(string message, string expected, string actual) : base(message) { Assertions = new List { new AssertionEntry { Message = message, Expected = expected, Actual = actual } }; } public ModAssertException(List assertions) : base((assertions.Count > 0) ? assertions[0].Message : "Assertion failed") { Assertions = assertions; } } public static class ModTestRunner { private class TestResultEntry { public readonly List Assertions = new List(); public string ClassName = ""; public string File; public int Line; public string Message = ""; public string StackTrace = ""; public string State = ""; public string Test = ""; } private class AssertionOutput { public string Actual = ""; public string Expected = ""; public string Message = ""; } public static bool AutoRunEnabled { get; set; } = true; private static string ResultsPath => Path.Combine(Paths.ConfigPath, "vv_test_results.json"); public static void RunAll() { List list = DiscoverTests(typeof(Plugin).Assembly); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[ModTestRunner] Running {list.Count} integration tests..."); } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; List list2 = new List(); List list3 = new List(); ModAssertException ex2 = default(ModAssertException); foreach (MethodInfo item3 in list) { string text = item3.GetCustomAttribute()?.Name ?? (item3.DeclaringType?.Name + "." + item3.Name); try { item3.Invoke(null, null); num++; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("[ModTestRunner] PASS: " + text)); } } catch (TargetInvocationException ex) when (((Func)delegate { // Could not convert BlockContainer to single expression ex2 = ex.InnerException as ModAssertException; return ex2 != null; }).Invoke()) { num2++; TestResultEntry item = BuildResult(item3, ex2, text, "FAIL"); list2.Add(item); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[ModTestRunner] FAIL: " + text + " — " + ex2.Message)); } } catch (Exception ex3) { Exception ex4 = ((ex3 is TargetInvocationException ex5) ? (ex5.InnerException ?? ex3) : ex3); num3++; TestResultEntry item2 = BuildResult(item3, ex4, text, "ERROR"); list3.Add(item2); ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)("[ModTestRunner] ERROR: " + text + " — " + ex4.Message)); } } } string text2 = ((num2 == 0 && num3 == 0) ? "PASS" : "FAIL"); ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)($"[ModTestRunner] Results: {num} passed, {num2} failed, " + $"{num3} errors, {num4} skipped — {text2}")); } WriteJsonResults(text2, num, num2, num3, num4, list2, list3, list.Count); } private static List DiscoverTests(Assembly assembly) { List<(MethodInfo, int, string)> list = new List<(MethodInfo, int, string)>(); Type[] types = assembly.GetTypes(); foreach (Type type in types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { ModTestAttribute customAttribute = methodInfo.GetCustomAttribute(); if (customAttribute == null) { continue; } if (methodInfo.GetParameters().Length != 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[ModTestRunner] Skipping " + type.Name + "." + methodInfo.Name + ": must be parameterless static")); } } else { string item = customAttribute.Name ?? (type.Name + "." + methodInfo.Name); list.Add((methodInfo, customAttribute.Order, item)); } } } return (from m in list orderby m.order, m.name select m.method).ToList(); } private static TestResultEntry BuildResult(MethodInfo method, Exception ex, string testName, string state) { TestResultEntry testResultEntry = new TestResultEntry { Test = testName, State = state, Message = ex.Message, StackTrace = (ex.StackTrace ?? "") }; if (ex.StackTrace != null) { Match match = Regex.Match(ex.StackTrace, "in (.+):line (\\d+)"); if (match.Success) { testResultEntry.File = match.Groups[1].Value; int.TryParse(match.Groups[2].Value, out testResultEntry.Line); } } testResultEntry.ClassName = method.DeclaringType?.FullName ?? ""; if (ex is ModAssertException ex2) { foreach (AssertionEntry assertion in ex2.Assertions) { testResultEntry.Assertions.Add(new AssertionOutput { Message = assertion.Message, Expected = (assertion.Expected ?? ""), Actual = (assertion.Actual ?? "") }); } } return testResultEntry; } private static void WriteJsonResults(string result, int passed, int failed, int errored, int skipped, List failures, List errors, int totalTests) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" \"v\": 1,"); stringBuilder.AppendLine($" \"ts\": \"{DateTime.UtcNow:O}\","); stringBuilder.AppendLine(" \"result\": \"" + result + "\","); stringBuilder.AppendLine(" \"summary\": {"); stringBuilder.AppendLine($" \"total\": {totalTests},"); stringBuilder.AppendLine($" \"passed\": {passed},"); stringBuilder.AppendLine($" \"failed\": {failed},"); stringBuilder.AppendLine($" \"errors\": {errored},"); stringBuilder.AppendLine($" \"skipped\": {skipped}"); stringBuilder.AppendLine(" },"); stringBuilder.AppendLine(" \"failures\": ["); WriteEntries(stringBuilder, failures); stringBuilder.AppendLine(" ],"); stringBuilder.AppendLine(" \"errors\": ["); WriteEntries(stringBuilder, errors); stringBuilder.AppendLine(" ],"); stringBuilder.AppendLine(" \"skipped\": []"); stringBuilder.AppendLine("}"); try { File.WriteAllText(ResultsPath, stringBuilder.ToString()); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[ModTestRunner] Results written to " + ResultsPath)); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("[ModTestRunner] Failed to write results: " + ex.Message)); } } } private static void WriteEntries(StringBuilder sb, List entries) { for (int i = 0; i < entries.Count; i++) { TestResultEntry testResultEntry = entries[i]; sb.AppendLine(" {"); sb.AppendLine(" \"test\": " + JsonEscape(testResultEntry.Test) + ","); sb.AppendLine(" \"state\": " + JsonEscape(testResultEntry.State) + ","); sb.AppendLine(" \"location\": {"); sb.AppendLine(" \"file\": " + JsonEscape(testResultEntry.File ?? "") + ","); sb.AppendLine($" \"line\": {testResultEntry.Line},"); sb.AppendLine(" \"class\": " + JsonEscape(testResultEntry.ClassName ?? "")); sb.AppendLine(" },"); sb.AppendLine(" \"message\": " + JsonEscape(testResultEntry.Message ?? "") + ","); sb.AppendLine(" \"assertions\": ["); for (int j = 0; j < testResultEntry.Assertions.Count; j++) { AssertionOutput assertionOutput = testResultEntry.Assertions[j]; sb.Append(" { "); sb.Append("\"message\": " + JsonEscape(assertionOutput.Message) + ", "); sb.Append("\"expected\": " + JsonEscape(assertionOutput.Expected) + ", "); sb.Append("\"actual\": " + JsonEscape(assertionOutput.Actual)); sb.Append(" }"); if (j < testResultEntry.Assertions.Count - 1) { sb.Append(","); } sb.AppendLine(); } sb.AppendLine(" ],"); sb.AppendLine(" \"stackTrace\": " + JsonEscape(testResultEntry.StackTrace ?? "")); sb.Append(" }"); if (i < entries.Count - 1) { sb.Append(","); } sb.AppendLine(); } } private static string JsonEscape(string s) { if (s == null) { return "\"\""; } return "\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r") .Replace("\t", "\\t") + "\""; } [DevCommand("Run all [ModTest] integration tests", Name = "vv_test_run")] public static void RunTestsCommand() { RunAll(); } } public class SceneSnapshot { public string Timestamp; public List VillageAreas = new List(); public List Villagers = new List(); public static SceneSnapshot Capture() { //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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) SceneSnapshot sceneSnapshot = new SceneSnapshot { Timestamp = DateTime.UtcNow.ToString("O") }; foreach (KeyValuePair activeVillager in VillagerAIManager.ActiveVillagers) { VillagerAI value = activeVillager.Value; Vector3 position = value.Position; sceneSnapshot.Villagers.Add(new VillagerSnapshot { UniqueId = (value.UniqueId ?? "unknown"), NpcType = (value.VillagerType ?? "unknown"), BehaviorState = value.CurrentState.ToString(), Position = new float[3] { position.x, position.y, position.z }, KnownLocationCount = 0 }); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)($"[SceneSnapshot] Captured {sceneSnapshot.Villagers.Count} villagers, " + $"{VillageAreaManager.AreaCount} village areas")); } return sceneSnapshot; } public void SaveToFile(string path) { string contents = ToJson(); File.WriteAllText(path, contents); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[SceneSnapshot] Saved to " + path)); } } public static SceneSnapshot LoadFromFile(string path) { if (!File.Exists(path)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[SceneSnapshot] File not found: " + path)); } return null; } return FromJson(File.ReadAllText(path)); } public static string CompareWithCurrent(SceneSnapshot saved) { SceneSnapshot sceneSnapshot = Capture(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Snapshot comparison (saved: " + saved.Timestamp + ", current: " + sceneSnapshot.Timestamp + ")"); stringBuilder.AppendLine($" Villagers: saved={saved.Villagers.Count}, current={sceneSnapshot.Villagers.Count}"); Dictionary dictionary = (from v in saved.Villagers group v by v.NpcType ?? "unknown").ToDictionary((IGrouping g) => g.Key, (IGrouping g) => g.Count()); Dictionary dictionary2 = (from v in sceneSnapshot.Villagers group v by v.NpcType ?? "unknown").ToDictionary((IGrouping g) => g.Key, (IGrouping g) => g.Count()); foreach (string item in from t in dictionary.Keys.Union(dictionary2.Keys) orderby t select t) { int value; int num = (dictionary.TryGetValue(item, out value) ? value : 0); int value2; int num2 = (dictionary2.TryGetValue(item, out value2) ? value2 : 0); if (num != num2) { stringBuilder.AppendLine($" DIFF {item}: saved={num}, current={num2}"); } } return stringBuilder.ToString(); } private string ToJson() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" \"timestamp\": \"" + Timestamp + "\","); stringBuilder.AppendLine(" \"villagers\": ["); for (int i = 0; i < Villagers.Count; i++) { VillagerSnapshot villagerSnapshot = Villagers[i]; stringBuilder.AppendLine(" {"); stringBuilder.AppendLine(" \"uniqueId\": \"" + Esc(villagerSnapshot.UniqueId) + "\","); stringBuilder.AppendLine(" \"npcType\": \"" + Esc(villagerSnapshot.NpcType) + "\","); stringBuilder.AppendLine(" \"behaviorState\": \"" + Esc(villagerSnapshot.BehaviorState) + "\","); stringBuilder.AppendLine($" \"position\": [{villagerSnapshot.Position[0]:F2}, {villagerSnapshot.Position[1]:F2}, {villagerSnapshot.Position[2]:F2}],"); stringBuilder.AppendLine($" \"knownLocationCount\": {villagerSnapshot.KnownLocationCount}"); stringBuilder.Append(" }"); if (i < Villagers.Count - 1) { stringBuilder.Append(","); } stringBuilder.AppendLine(); } stringBuilder.AppendLine(" ],"); stringBuilder.AppendLine(" \"villageAreas\": ["); for (int j = 0; j < VillageAreas.Count; j++) { VillageAreaSnapshot villageAreaSnapshot = VillageAreas[j]; stringBuilder.AppendLine(" {"); stringBuilder.AppendLine($" \"center\": [{villageAreaSnapshot.Center[0]:F2}, {villageAreaSnapshot.Center[1]:F2}, {villageAreaSnapshot.Center[2]:F2}],"); stringBuilder.AppendLine($" \"radius\": {villageAreaSnapshot.Radius:F2},"); stringBuilder.AppendLine($" \"villagerCount\": {villageAreaSnapshot.VillagerCount}"); stringBuilder.Append(" }"); if (j < VillageAreas.Count - 1) { stringBuilder.Append(","); } stringBuilder.AppendLine(); } stringBuilder.AppendLine(" ]"); stringBuilder.AppendLine("}"); return stringBuilder.ToString(); } private static SceneSnapshot FromJson(string json) { SceneSnapshot sceneSnapshot = new SceneSnapshot(); Match match = Regex.Match(json, "\"timestamp\":\\s*\"([^\"]+)\""); if (match.Success) { sceneSnapshot.Timestamp = match.Groups[1].Value; } return sceneSnapshot; } private static string Esc(string s) { return s?.Replace("\"", "\\\"") ?? ""; } [DevCommand("Capture scene snapshot to vv_snapshot.json", Name = "vv_snapshot_capture")] public static void CaptureCommand() { string path = Path.Combine(Paths.ConfigPath, "vv_snapshot.json"); Capture().SaveToFile(path); } [DevCommand("Verify current state against saved snapshot", Name = "vv_snapshot_verify")] public static void VerifyCommand() { SceneSnapshot sceneSnapshot = LoadFromFile(Path.Combine(Paths.ConfigPath, "vv_snapshot.json")); if (sceneSnapshot == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[SceneSnapshot] No saved snapshot found. Run vv_snapshot first."); } return; } string text = CompareWithCurrent(sceneSnapshot); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[SceneSnapshot] Comparison:\n" + text)); } } } public class VillagerSnapshot { public string BehaviorState; public int KnownLocationCount; public string NpcType; public float[] Position = new float[3]; public string UniqueId; } public class VillageAreaSnapshot { public float[] Center = new float[3]; public float Radius; public int VillagerCount; } } namespace ValheimVillages.TaskQueue { public static class GlobalTaskQueue { private static readonly Dictionary> s_queues = new Dictionary> { { TaskPriority.High, new Queue() }, { TaskPriority.Medium, new Queue() }, { TaskPriority.Low, new Queue() } }; private static readonly TaskPriority[] s_tiersDescending = new TaskPriority[3] { TaskPriority.High, TaskPriority.Medium, TaskPriority.Low }; private static readonly HashSet<(string, string)> s_pendingKeys = new HashSet<(string, string)>(); private const float ReadinessRecheckSeconds = 1.5f; private static readonly List s_deadLetters = new List(); public static IReadOnlyList DeadLetters => s_deadLetters; public static int PendingCount => s_queues.Values.Sum((Queue q) => q.Count); public static bool Enqueue(VillagerTask task) { if (task == null) { return false; } (string, string) item = (task.Name, task.SourceId); if (s_pendingKeys.Contains(item)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[TaskQueue] Dedup: skipping duplicate " + task.Name + " for " + task.SourceId)); } return false; } if (!s_queues.ContainsKey(task.Priority)) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)$"[TaskQueue] Unknown priority {task.Priority}, dropping task {task.Name}"); } return false; } task.CreatedAt = Time.time; s_queues[task.Priority].Enqueue(task); s_pendingKeys.Add(item); return true; } public static void ProcessBatch() { int num = 0; int num2 = (int)s_tiersDescending[0]; TaskPriority[] array = s_tiersDescending; for (int i = 0; i < array.Length; i++) { int maxCount; int num3 = DrainQueue((TaskPriority)(maxCount = (int)array[i]), maxCount); num += num3; } if (num >= num2) { return; } int num4 = num2 - num; array = s_tiersDescending; foreach (TaskPriority tier in array) { if (num4 > 0) { int num5 = DrainQueue(tier, num4); num += num5; num4 -= num5; continue; } break; } } private static int DrainQueue(TaskPriority tier, int maxCount) { Queue queue = s_queues[tier]; int num = 0; int num2 = 0; int count = queue.Count; while (num < maxCount && queue.Count > 0 && num2 < count) { num2++; VillagerTask villagerTask = queue.Dequeue(); if (villagerTask.NotBefore > 0f && Time.time < villagerTask.NotBefore) { queue.Enqueue(villagerTask); continue; } if (TaskHandlerRegistry.Get(villagerTask.Name) is ITaskPrecondition taskPrecondition && !taskPrecondition.IsReady(villagerTask)) { if (Time.time - villagerTask.CreatedAt > villagerTask.TimeoutSeconds) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[TaskQueue] Task '" + villagerTask.Name + "' for " + villagerTask.SourceId + " timed out waiting " + $"for preconditions after {Time.time - villagerTask.CreatedAt:F1}s; dropping.")); } RemovePendingKey(villagerTask); } else { villagerTask.NotBefore = Time.time + 1.5f; queue.Enqueue(villagerTask); } continue; } RemovePendingKey(villagerTask); if (Time.time - villagerTask.CreatedAt > villagerTask.TimeoutSeconds) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[TaskQueue] Task '" + villagerTask.Name + "' for " + villagerTask.SourceId + " timed out " + $"after {Time.time - villagerTask.CreatedAt:F1}s (limit {villagerTask.TimeoutSeconds}s)")); } continue; } ITaskHandler taskHandler = TaskHandlerRegistry.Get(villagerTask.Name); if (taskHandler == null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[TaskQueue] No handler registered for '" + villagerTask.Name + "', dead-lettering")); } AddToDeadLetters(villagerTask); continue; } try { TaskResult taskResult = ((ITaskHandlerWithLog)taskHandler).Handle(villagerTask, VillagerActivityLog.Instance); if (taskResult.Success) { villagerTask.Callback?.Invoke(taskResult); num++; } else { HandleFailure(villagerTask, taskResult.Error); num++; } } catch (Exception ex) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)("[TaskQueue] Handler '" + villagerTask.Name + "' threw exception: " + ex.Message)); } HandleFailure(villagerTask, ex.Message); num++; } } return num; } private static void HandleFailure(VillagerTask task, string error) { task.RetryCount++; if (task.RetryCount < 3) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[TaskQueue] Retrying '" + task.Name + "' for " + task.SourceId + " " + $"(attempt {task.RetryCount + 1}/{3}): {error}")); } s_queues[task.Priority].Enqueue(task); s_pendingKeys.Add((task.Name, task.SourceId)); } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[TaskQueue] Dead-lettering '" + task.Name + "' for " + task.SourceId + " " + $"after {task.RetryCount} retries: {error}")); } AddToDeadLetters(task); } } private static void AddToDeadLetters(VillagerTask task) { if (s_deadLetters.Count >= 50) { s_deadLetters.RemoveAt(0); } s_deadLetters.Add(task); } private static void RemovePendingKey(VillagerTask task) { s_pendingKeys.Remove((task.Name, task.SourceId)); } public static int PendingCount_ForTier(TaskPriority tier) { if (!s_queues.TryGetValue(tier, out var value)) { return 0; } return value.Count; } [RegisterCleanup] public static void Clear() { foreach (Queue value in s_queues.Values) { value.Clear(); } s_pendingKeys.Clear(); s_deadLetters.Clear(); } } public interface ITaskHandlerWithLog : ITaskHandler { TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog); } public interface ITaskPrecondition { bool IsReady(VillagerTask task); } internal static class RepartitionCommand { [DevCommand("Force enqueue an immediate hna_partition rebuild", Name = "vv_repartition")] public static void Repartition() { GlobalTaskQueue.Enqueue(new VillagerTask { Name = "hna_partition", SourceId = "user", Priority = TaskPriority.High, TimeoutSeconds = 60f, Attributes = new Dictionary() }); string text = "[vv_repartition] Enqueued hna_partition (high priority, no anchor)"; Console instance = Console.instance; if (instance != null) { instance.Print(text); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } } } public static class TaskAttributeParser { public static bool TryParsePosition(Dictionary attrs, string prefix, out Vector3 result) { //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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) result = Vector3.zero; if (attrs == null) { return false; } if (!attrs.TryGetValue(prefix + "_x", out var value) || !attrs.TryGetValue(prefix + "_y", out var value2) || !attrs.TryGetValue(prefix + "_z", out var value3)) { return false; } if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(value2, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(value3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result4)) { return false; } result = new Vector3(result2, result3, result4); return true; } } public static class TaskHandlerRegistry { private static readonly Dictionary s_handlers = new Dictionary(); public static void Register(ITaskHandler handler) { if (handler == null) { return; } if (s_handlers.ContainsKey(handler.TaskName)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[TaskRegistry] Replacing existing handler for '" + handler.TaskName + "'")); } } s_handlers[handler.TaskName] = handler; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("[TaskRegistry] Registered handler: " + handler.TaskName)); } } public static ITaskHandler Get(string taskName) { s_handlers.TryGetValue(taskName, out var value); return value; } [RegisterCleanup] public static void Clear() { s_handlers.Clear(); } } } namespace ValheimVillages.TaskQueue.Handlers { internal static class CellValidator { internal const float MaxLedgeDrop = 1.5f; internal const float MaxSlopeDeg = 30f; internal const float GroundCheckDist = 2f; internal const float MinEdgeDistance = 0.2f; internal const float WidthProbeOffset = 0.35f; internal const int MinProbeHits = 3; private static readonly int GroundMask = LayerMask.GetMask(new string[4] { "Default", "static_solid", "terrain", "piece" }); internal static bool IsLedgeDrop(float fromY, float toY) { return fromY - toY > 1.5f; } internal static bool IsTooSteep(float fromX, float fromY, float fromZ, float toX, float toY, float toZ) { if (TryIsTooSteep(fromX, fromY, fromZ, toX, toY, toZ, out var tooSteep)) { return tooSteep; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[CellValidator] IsTooSteep: villager agent climb unavailable (Pathfinding.instance not alive or agent slot 31 not registered); rejecting cell transition fail-closed. Caller should defer cell validation."); } return true; } internal static bool TryIsTooSteep(float fromX, float fromY, float fromZ, float toX, float toY, float toZ, out bool tooSteep) { tooSteep = false; float num = Mathf.Abs(toY - fromY); float num2 = toX - fromX; float num3 = toZ - fromZ; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); if (num4 < 0.01f) { if (!VillagerAgentType.TryGetClimb(out var climb)) { return false; } tooSteep = num > climb; return true; } tooSteep = Mathf.Atan2(num, num4) * 57.29578f > 30f; return true; } internal static bool HasGroundBelow(Vector3 pos) { //IL_0000: 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_0012: 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) return Physics.Raycast(new Vector3(pos.x, pos.y + 0.2f, pos.z), Vector3.down, 2.2f, GroundMask, (QueryTriggerInteraction)1); } internal static bool IsSurfaceWideEnough(Vector3 pos, NavMeshQueryFilter filter) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); if (!NavMesh.FindClosestEdge(pos, ref val, filter)) { return false; } return ((NavMeshHit)(ref val)).distance >= 0.2f; } internal static bool IsWideEnough(Vector3 pos, NavMeshQueryFilter filter) { //IL_0002: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_005c: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) int num = 0; NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(pos + new Vector3(0.35f, 0f, 0f), ref val, 0.5f, filter)) { num++; } if (NavMesh.SamplePosition(pos + new Vector3(-0.35f, 0f, 0f), ref val, 0.5f, filter)) { num++; } if (NavMesh.SamplePosition(pos + new Vector3(0f, 0f, 0.35f), ref val, 0.5f, filter)) { num++; } if (NavMesh.SamplePosition(pos + new Vector3(0f, 0f, -0.35f), ref val, 0.5f, filter)) { num++; } return num >= 3; } } [RegisterTaskHandler] public class ContainerScanHandler : ITaskHandlerWithLog, ITaskHandler { public string TaskName => "container_scan"; public TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog) { //IL_004d: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) if (!TaskAttributeParser.TryParsePosition(task.Attributes, "center", out var result)) { return TaskResult.Fail("Missing or invalid center position attributes"); } if (!task.Attributes.TryGetValue("radius", out var value) || !float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { result2 = 20f; } List list = ContainerScanner.FindNearbyContainers(result, result2); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)($"[ContainerScanHandler] Found {list.Count} containers " + $"near ({result.x:F0},{result.y:F0},{result.z:F0}), radius={result2:F0}m")); } activityLog.Record(task.SourceId, TaskName, "scan_containers", $"found {list.Count} containers near ({result.x:F0},{result.y:F0},{result.z:F0})"); return TaskResult.Ok(new Dictionary { { "container_count", list.Count.ToString() } }); } } public static class FarmWorkOrderHelper { public static FarmingContext BuildFarmingContext(IVillagerWorkContext ai, WorkOrderMatch match, Recipe recipe, List ingredients, int existingCount) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) string itemPrefabName = match.ItemPrefabName; Vector3 anchorPos = ai.HomeAnchor; Pickable val = HarvestHelper.FindNearestHarvestableCrop(anchorPos, itemPrefabName, 20f); if ((Object)(object)val != (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[FarmScan:" + ai.NpcName + "] Found harvestable " + itemPrefabName + " at " + $"{((Component)val).transform.position}")); } return new FarmingContext { WorkOrder = match, Recipe = recipe, SourceContainer = match.SourceContainer, IngredientSources = null, FarmPosition = ((Component)val).transform.position, HarvestedCount = existingCount, IsHarvestingPass = true, CurrentHarvestTarget = val }; } KnownLocation knownLocation = (from l in VillagePoiRegistry.GetPois(anchorPos, LocationType.Farm) orderby Vector3.Distance(anchorPos, l.Position) select l).FirstOrDefault(); Vector3 val2; if (knownLocation != null) { val2 = knownLocation.Position; } else { Vector3? val3 = FindCultivatedGroundNearAnchor(anchorPos); if (!val3.HasValue) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("[FarmScan:" + ai.NpcName + "] No ready crop, farm location, or cultivated ground found")); } return null; } val2 = val3.Value; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[FarmScan:{ai.NpcName}] Using cultivated ground at {val2}"); } } GameObject piecePrefab = PlantPieceRegistry.GetPiecePrefab(itemPrefabName); if ((Object)(object)piecePrefab == (Object)null) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogDebug((object)("[FarmScan:" + ai.NpcName + "] No plant piece for " + itemPrefabName)); } return null; } if (ingredients == null || ingredients.Count == 0) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogDebug((object)("[FarmScan:" + ai.NpcName + "] No seeds for " + itemPrefabName)); } return null; } Plant component = piecePrefab.GetComponent(); float num = (((Object)(object)component != (Object)null) ? component.m_growRadius : 0.5f); if (!PlantingHelper.FindPlantingPosition(val2, 20f, num).HasValue) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogDebug((object)("[FarmScan:" + ai.NpcName + "] No planting positions near farm")); } return null; } ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogInfo((object)("[FarmScan:" + ai.NpcName + "] Planting pass for " + itemPrefabName)); } return new FarmingContext { WorkOrder = match, Recipe = recipe, SourceContainer = match.SourceContainer, IngredientSources = ingredients, FarmPosition = val2, PlantPiecePrefab = piecePrefab, PlantGrowRadius = num, HarvestedCount = existingCount, IsHarvestingPass = false }; } private static Vector3? FindCultivatedGroundNearAnchor(Vector3 anchorPos) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) for (float num = 5f; num <= 30f; num += 3f) { int num2 = Mathf.Max(8, Mathf.RoundToInt((float)Math.PI * 2f * num / 3f)); for (int i = 0; i < num2; i++) { float num3 = (float)Math.PI * 2f * (float)i / (float)num2; Vector3 val = anchorPos + new Vector3(Mathf.Cos(num3) * num, 0f, Mathf.Sin(num3) * num); if ((Object)(object)ZoneSystem.instance == (Object)null) { continue; } float groundHeight = ZoneSystem.instance.GetGroundHeight(val); if (!(groundHeight <= -1000f)) { val.y = groundHeight; if (PlantingHelper.IsCultivated(val)) { return val; } } } } return null; } } [RegisterTaskHandler] public class IntegrationTestHandler : ITaskHandlerWithLog, ITaskHandler { public const string TaskNameConst = "integration_tests"; private const float DeferralSeconds = 2f; private const float DeadlineSeconds = 30f; private const string AttrScheduledAt = "scheduled_at"; public string TaskName => "integration_tests"; public TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog) { float scheduledAt = GetScheduledAt(task); float num = Time.time - scheduledAt; if (num < 2f) { GlobalTaskQueue.Enqueue(new VillagerTask { Name = "integration_tests", SourceId = "system", Priority = TaskPriority.Low, TimeoutSeconds = 35f, NotBefore = Time.time + 2f, Attributes = new Dictionary { { "scheduled_at", scheduledAt.ToString("R") } } }); return TaskResult.Ok(); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[IntegrationTests] Running tests ({num:F1}s after schedule)"); } ModTestRunner.RunAll(); return TaskResult.Ok(); } private static float GetScheduledAt(VillagerTask task) { if (task.Attributes != null && task.Attributes.TryGetValue("scheduled_at", out var value) && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } return task.CreatedAt; } } [RegisterTaskHandler] public class RecipeDiscoveryRefreshHandler : ITaskHandlerWithLog, ITaskHandler { public string TaskName => "recipe_discovery_refresh"; public TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog) { if ((Object)(object)ObjectDB.instance == (Object)null) { return TaskResult.Fail("ObjectDB not ready"); } int num = VirtualRecipeLoader.RecheckDiscoveredRecipes(ObjectDB.instance); activityLog.Record(task.SourceId, TaskName, "recheck", $"added {num} discovered recipes"); return TaskResult.Ok(new Dictionary { { "recipes_added", num.ToString() } }); } } [RegisterTaskHandler] public class RegionPartitionHandler : ITaskHandlerWithLog, ITaskHandler, ITaskPrecondition { public const string RegionPartitionTaskName = "hna_partition"; private static readonly int s_pieceLayerMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); private static readonly List s_readinessScratch = new List(); public const float AnchorVillageRadius = 15f; internal const float FloodFillRadius = 30f; private const float RegionBuildRadius = 30f; private const float VillageClusterRadius = 50f; private const float NavRebuildSettleSeconds = 3f; public string TaskName => "hna_partition"; public bool IsReady(VillagerTask task) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || ZDOMan.instance == null) { return false; } if (!VillagerAgentType.IsRegistered) { return false; } List list = FilterAnchorsByTask(VillagerAIManager.GetAllAnchorPositions(), task); if (list == null || list.Count == 0) { return true; } int activeArea = ZoneSystem.instance.m_activeArea; foreach (Vector3 item in list) { Vector2i zone = ZoneSystem.GetZone(item); if (!ZoneSystem.instance.IsZoneLoaded(zone)) { return false; } if (!SectorBakeGeometryInstantiated(zone, activeArea)) { return false; } } return true; } private static bool SectorBakeGeometryInstantiated(Vector2i zone, int area) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) s_readinessScratch.Clear(); ZDOMan.instance.FindSectorObjects(zone, area, 0, s_readinessScratch, (List)null); foreach (ZDO item in s_readinessScratch) { if (item != null) { GameObject prefab = ZNetScene.instance.GetPrefab(item.GetPrefab()); if (!((Object)(object)prefab == (Object)null) && ((1 << prefab.layer) & s_pieceLayerMask) != 0 && (Object)(object)ZNetScene.instance.FindInstance(item) == (Object)null) { return false; } } } return true; } public TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog) { //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0343: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) VillageNavLock.RequestHold(3f); List anchors = FilterAnchorsByTask(VillagerAIManager.GetAllAnchorPositions(), task); anchors = ResolveWalkableSeeds(anchors); float minX; float minZ; float maxX; float maxZ; bool flag = VillageAreaManager.TryGetCombinedBounds(out minX, out minZ, out maxX, out maxZ); Village village = ResolveVillage(task, anchors); if (village == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Region] Partition skipped: no existing village resolved for this task (villages are created at registry placement; nothing to partition)."); } return TaskResult.Ok(new Dictionary { { "regions", "0" }, { "links", "0" }, { "reason", "no_village" } }); } string villageId = village.VillageId; float num; float num2; float num3; float num4; if (flag && anchors != null && anchors.Count > 0) { num = minX; num2 = minZ; num3 = maxX; num4 = maxZ; foreach (Vector3 item4 in anchors) { if (item4.x - 30f < num) { num = item4.x - 30f; } if (item4.z - 30f < num2) { num2 = item4.z - 30f; } if (item4.x + 30f > num3) { num3 = item4.x + 30f; } if (item4.z + 30f > num4) { num4 = item4.z + 30f; } } } else if (flag) { num = minX; num2 = minZ; num3 = maxX; num4 = maxZ; } else { if (anchors == null || anchors.Count <= 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[Region] Partition skipped: no village areas and no villager anchors."); } return TaskResult.Ok(new Dictionary { { "regions", "0" }, { "links", "0" }, { "reason", "no_anchors_or_areas" } }); } num = (num3 = anchors[0].x); num2 = (num4 = anchors[0].z); foreach (Vector3 item5 in anchors) { if (item5.x - 30f < num) { num = item5.x - 30f; } if (item5.z - 30f < num2) { num2 = item5.z - 30f; } if (item5.x + 30f > num3) { num3 = item5.x + 30f; } if (item5.z + 30f > num4) { num4 = item5.z + 30f; } } } if (anchors == null || anchors.Count == 0) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)("[Region] Partition aborted: no villager anchors for village '" + villageId + "'. Cannot determine bake elevation without anchors — refusing to bake at sea-level fallback.")); } return TaskResult.Ok(new Dictionary { { "regions", "0" }, { "links", "0" }, { "reason", "no_anchors_for_bake_y" } }); } float num5 = float.MaxValue; float num6 = float.MinValue; foreach (Vector3 item6 in anchors) { if (item6.y < num5) { num5 = item6.y; } if (item6.y > num6) { num6 = item6.y; } } Bounds bounds = default(Bounds); ((Bounds)(ref bounds)).SetMinMax(new Vector3(num, num5 - 30f, num2), new Vector3(num3, num6 + 30f, num4)); NavMeshBakeManager.BakeResult bakeResult = NavMeshBakeManager.BakeVillage(bounds); DebugLog.Event("NavMeshBake", "village_bake", ("success", bakeResult.Success), ("sources", bakeResult.SourceCount), ("terrain_sources", bakeResult.TerrainSourceCount), ("piece_sources", bakeResult.PieceSourceCount), ("doors_blocked", bakeResult.DoorsBlocked), ("door_pieces_dropped", bakeResult.DoorPiecesDropped), ("beds_blocked", bakeResult.BedsBlocked), ("outside_cells_blocked", bakeResult.OutsideCellsBlocked), ("duration_ms", bakeResult.DurationMs), ("terrain_ms", bakeResult.TerrainDurationMs), ("piece_ms", bakeResult.PieceDurationMs), ("agent_slot", VillagerAgentType.UnityAgentTypeID), ("bounds_x", $"{num:F0}..{num3:F0}"), ("bounds_z", $"{num2:F0}..{num4:F0}"), ("bounds_y", $"{num5 - 30f:F0}..{num6 + 30f:F0}"), ("reason", bakeResult.FailureReason ?? "")); RegionBuilder.BuildResult terrainResult = RegionBuilder.BuildFromTriangulation(SurfaceKind.Terrain, num, num2, num3, num4, anchors); RegionBuilder.BuildResult pieceResult = RegionBuilder.BuildFromTriangulation(SurfaceKind.Piece, num, num2, num3, num4, anchors); (Dictionary>, HashSet, Dictionary)? tuple = BuildCrossKindAdjacency(terrainResult, pieceResult, anchors); RegionBuilder.CombineTerrainAndPiece(terrainResult, pieceResult, out var combinedRegionIds, out var combinedCentroids, out var combinedLinks, out var combinedLookup, out var combinedBoundary, out var combinedTriangles, out var kindMap); HashSet droppedRegionIds; List<(string, string, Vector3, Vector3)> pass3DiscoveredEdgeList; HashSet anchorReachableCellsOut; HashSet outsideCellsOut; HashSet prunedPieceKeysOut; List gateMarkersOut; RubberBandPrune.Stats stats = RubberBandPrune.Apply(combinedRegionIds, combinedCentroids, combinedLookup, combinedBoundary, combinedLinks, kindMap, combinedTriangles, anchors, num, num2, num3, num4, out droppedRegionIds, out pass3DiscoveredEdgeList, out anchorReachableCellsOut, out outsideCellsOut, out prunedPieceKeysOut, out gateMarkersOut); if (tuple.HasValue) { (Dictionary>, HashSet, Dictionary) value = tuple.Value; Dictionary> item = value.Item1; HashSet item2 = value.Item2; Dictionary item3 = value.Item3; int num7 = 0; foreach (var (text, text2, _, _) in pass3DiscoveredEdgeList) { if (!droppedRegionIds.Contains(text) && !droppedRegionIds.Contains(text2)) { if (!item.TryGetValue(text, out var value2)) { value2 = (item[text] = new HashSet()); } if (!item.TryGetValue(text2, out var value3)) { value3 = (item[text2] = new HashSet()); } value2.Add(text2); value3.Add(text); string key = BfsAdjacencyStore.EdgeKey(text, text2); if (item3.TryGetValue(key, out var value4)) { value4.Kinds |= BfsEdgeKind.Pass3Step; item3[key] = value4; } else { item3[key] = new BfsEdgeMeta { Kinds = BfsEdgeKind.Pass3Step }; num7++; } } } BfsAdjacencyStore.Set(item, item2, item3); if (num7 > 0) { DebugLog.Event("Region", "bfs_store_merged_pass3", ("new_edges", num7), ("total_pass3_pairs", pass3DiscoveredEdgeList.Count)); } } DebugLog.Event("RubberBandPrune", "applied", ("outside_terrain_cells", stats.OutsideTerrainCells), ("pass2_seeds", stats.Pass2Seeds), ("anchor_reachable_terrain_cells", stats.AnchorReachableTerrainCells), ("pass3_seeds", stats.Pass3Seeds), ("anchor_reachable_piece_keys", stats.AnchorReachablePieceKeys), ("pass3_piece_keys_dropped", stats.Pass3PieceKeysDropped), ("pass3_links_added", stats.Pass3LinksAdded), ("pass4_verts_snapped", stats.Pass4BoundaryVertsSnapped), ("pass4_snap_misses", stats.Pass4SnapMisses), ("pass4_links_snapped", stats.Pass4LinksSnapped), ("pass5_chains", stats.Pass5ChainsConsolidated), ("pass5_consumed", stats.Pass5RegionsConsumed), ("pass5_links_removed", stats.Pass5LinksRemoved), ("lookup_cells_dropped", stats.LookupCellsDropped), ("triangles_dropped", stats.TrianglesDropped), ("static_solid_dropped", stats.StaticSolidTrianglesDropped), ("regions_dropped", stats.RegionsDropped), ("seed_perimeter_cells", stats.PerimeterSeeds), ("regions_kept", combinedRegionIds.Count)); if (droppedRegionIds.Count > 0) { DebugLog.List("RubberBandPrune", "dropped_region_ids", ((IEnumerable)droppedRegionIds).Select((Func)((string r) => r))); } if (combinedRegionIds.Count == 0) { RegionGraph regionGraph = FindContainingNonEmptyGraph(anchors); if (regionGraph != null) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)("[Region] Partition for key=" + villageId + " produced 0 regions, but its seed is inside " + $"existing graph '{regionGraph.RegisteredVillageKey}' ({regionGraph.RegionCount} regions, " + $"{regionGraph.LinkCount} links) — treating as a failed mutation of the same village; " + "keeping the existing graph rather than clobbering it.")); } return TaskResult.Ok(new Dictionary { { "regions", regionGraph.RegionCount.ToString() }, { "links", regionGraph.LinkCount.ToString() }, { "village_key", regionGraph.RegisteredVillageKey ?? villageId }, { "reason", "degenerate_kept_existing" } }); } } RegionGraph orCreateGraph = village.GetOrCreateGraph(); orCreateGraph.SetGraph(combinedRegionIds, combinedLinks, combinedCentroids, combinedLookup, combinedBoundary, kindMap); orCreateGraph.SetGates(gateMarkersOut); orCreateGraph.SetClassification(outsideCellsOut, anchorReachableCellsOut, prunedPieceKeysOut); if (gateMarkersOut.Count > 0) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)$"[Region] Sealed {gateMarkersOut.Count} gate(s) into the village boundary"); } } int num8 = VillagerAIManager.InvalidatePathsAfterRebake(); if (num8 > 0) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogInfo((object)$"[Region] Invalidated cached paths for {num8} villager(s) after rebake"); } } string regionCenters = BuildRegionCentersString(orCreateGraph); string linksSummary = BuildLinksSummaryString(combinedLinks); PathTelemetry.LogRegionGraph(combinedRegionIds.Count, combinedLinks.Count, num, num2, num3, num4, regionCenters, linksSummary); ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogInfo((object)($"[Region] Partition complete: {combinedRegionIds.Count} regions " + $"(terrain={terrainResult.RegionIds.Count}, piece={pieceResult.RegionIds.Count}), " + $"{combinedLinks.Count} links " + $"(bounds {num:F0},{num2:F0} to {num3:F0},{num4:F0}, key={villageId})")); } village.SaveGraph(); VillageAreaManager.RefreshFromVillage(village); int num9 = VillagerAIManager.ResetPatrolRoutesAfterRepartition(); if (num9 > 0) { ManualLogSource log8 = Plugin.Log; if (log8 != null) { log8.LogInfo((object)$"[Region] Rebuilt patrol routes for {num9} patroller(s) after repartition"); } } return TaskResult.Ok(new Dictionary { { "regions", combinedRegionIds.Count.ToString() }, { "regions_terrain", terrainResult.RegionIds.Count.ToString() }, { "regions_piece", pieceResult.RegionIds.Count.ToString() }, { "links", combinedLinks.Count.ToString() }, { "village_key", villageId } }); } private static string BuildRegionCentersString(RegionGraph graph) { StringBuilder stringBuilder = new StringBuilder(); foreach (string regionId in graph.GetRegionIds()) { if (!string.IsNullOrEmpty(regionId) && graph.GetCellWorldXZ(regionId, out var wx, out var wz)) { float num = 0f; float height2; if (graph.TryGetCellHeight(regionId, out var height)) { num = height; } else if (RegionGraph.GetSolidHeightAt(wx, wz, out height2)) { num = height2; } if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } stringBuilder.Append(regionId).Append(',').Append(wx.ToString("F1", CultureInfo.InvariantCulture)) .Append(',') .Append(num.ToString("F1", CultureInfo.InvariantCulture)) .Append(',') .Append(wz.ToString("F1", CultureInfo.InvariantCulture)); } } return stringBuilder.ToString(); } private static string BuildLinksSummaryString(List links) { StringBuilder stringBuilder = new StringBuilder(); foreach (RegionLink link in links) { if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } string value = ((link.LinkType == RegionLinkType.Door) ? "door" : ((link.LinkType == RegionLinkType.Slope) ? "slope" : "stair")); stringBuilder.Append(link.FromRegionId).Append(',').Append(link.ToRegionId) .Append(',') .Append(value); } return stringBuilder.ToString(); } private static Village ResolveVillage(VillagerTask task, List anchors) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (task?.Attributes != null && task.Attributes.TryGetValue("village_id", out var value) && !string.IsNullOrEmpty(value)) { Village village = VillageRegistry.FindById(value); if (village != null) { return village; } } if (task?.Attributes != null && task.Attributes.TryGetValue("anchor_x", out var value2) && task.Attributes.TryGetValue("anchor_z", out var value3) && float.TryParse(value2, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(value3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { float num = ((anchors != null && anchors.Count > 0) ? anchors[0].y : 0f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(result, num, result2); return VillageRegistry.GetVillageCovering(val) ?? VillageRegistry.FindNearAnchor(val); } if (anchors != null && anchors.Count > 0) { return VillageRegistry.GetVillageCovering(anchors[0]) ?? VillageRegistry.FindNearAnchor(anchors[0]); } return null; } private static RegionGraph FindContainingNonEmptyGraph(List seeds) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (seeds == null) { return null; } foreach (Vector3 seed in seeds) { RegionGraph regionGraph = VillageRegistry.GetVillageAt(seed)?.Graph; if (regionGraph != null && regionGraph.RegionCount != 0) { if (!string.IsNullOrEmpty(regionGraph.PointToRegionId(seed))) { return regionGraph; } if (regionGraph.TryFindNearestLookupCell(seed, null, out var _, out var _, 6f)) { return regionGraph; } } } return null; } private static List ResolveWalkableSeeds(List anchors) { //IL_0029: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_003b: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_008c: 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 (anchors == null || anchors.Count == 0) { return anchors; } List list = new List(anchors.Count); int num = 0; foreach (Vector3 anchor in anchors) { if (RegistrySeedResolver.TryResolveWalkableSeed(anchor, out var seed)) { Vector3 val = seed - anchor; if (((Vector3)(ref val)).sqrMagnitude > 0.25f) { num++; } list.Add(seed); } else { list.Add(anchor); ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)($"[Region] No walkable seed near home ({anchor.x:F1},{anchor.y:F1},{anchor.z:F1}); " + "using it as-is (flood may degenerate).")); } } } if (num > 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[Region] Snapped {num}/{anchors.Count} village seed(s) onto walkable cells near their anchor."); } } return list; } private static List FilterAnchorsByTask(List allAnchors, VillagerTask task) { //IL_0089: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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) if (allAnchors == null || allAnchors.Count == 0) { return allAnchors; } if (task?.Attributes == null || !task.Attributes.TryGetValue("anchor_x", out var value) || !task.Attributes.TryGetValue("anchor_z", out var value2)) { return allAnchors; } if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(value2, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return allAnchors; } float num = 2500f; List list = new List(); foreach (Vector3 allAnchor in allAnchors) { float num2 = allAnchor.x - result; float num3 = allAnchor.z - result2; if (num2 * num2 + num3 * num3 <= num) { list.Add(allAnchor); } } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Region] Filtered anchors by anchor ({result:F0},{result2:F0}): " + $"{list.Count}/{allAnchors.Count} within {50f}m")); } if (list.Count == 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)$"[Region] No anchors within {50f}m of anchor ({result:F0},{result2:F0})"); } } return list; } private static (Dictionary> adjacency, HashSet seeds, Dictionary edgeMeta)? BuildCrossKindAdjacency(RegionBuilder.BuildResult terrainResult, RegionBuilder.BuildResult pieceResult, List anchors) { //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_0744: Unknown result type (might be due to invalid IL or missing references) //IL_0749: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_077e: Unknown result type (might be due to invalid IL or missing references) //IL_0785: Unknown result type (might be due to invalid IL or missing references) //IL_0799: Unknown result type (might be due to invalid IL or missing references) //IL_07a0: Unknown result type (might be due to invalid IL or missing references) //IL_07a8: Unknown result type (might be due to invalid IL or missing references) //IL_07af: Unknown result type (might be due to invalid IL or missing references) //IL_0515: Unknown result type (might be due to invalid IL or missing references) //IL_0521: Unknown result type (might be due to invalid IL or missing references) //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_0556: Unknown result type (might be due to invalid IL or missing references) //IL_0562: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_057b: Unknown result type (might be due to invalid IL or missing references) //IL_0599: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_05b2: Unknown result type (might be due to invalid IL or missing references) //IL_05be: Unknown result type (might be due to invalid IL or missing references) //IL_05fb: Unknown result type (might be due to invalid IL or missing references) //IL_06d7: Unknown result type (might be due to invalid IL or missing references) //IL_0614: Unknown result type (might be due to invalid IL or missing references) //IL_0619: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0624: Unknown result type (might be due to invalid IL or missing references) //IL_0629: Unknown result type (might be due to invalid IL or missing references) //IL_062b: Unknown result type (might be due to invalid IL or missing references) //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_063c: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_064d: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_067d: Unknown result type (might be due to invalid IL or missing references) //IL_067f: Unknown result type (might be due to invalid IL or missing references) //IL_0681: Unknown result type (might be due to invalid IL or missing references) //IL_068b: Unknown result type (might be due to invalid IL or missing references) //IL_0690: Unknown result type (might be due to invalid IL or missing references) if (terrainResult.RegionIds == null || terrainResult.RegionIds.Count == 0) { return null; } Dictionary> combinedAdj = new Dictionary>(); Dictionary edgeMeta = new Dictionary(); if (terrainResult.Adjacency != null) { foreach (KeyValuePair> item in terrainResult.Adjacency) { EnsureNode(item.Key); foreach (string item2 in item.Value) { RecordEdge(item.Key, item2, BfsEdgeKind.InPassEdge, null, 0f); } } } if (pieceResult.Adjacency != null) { foreach (KeyValuePair> item3 in pieceResult.Adjacency) { EnsureNode(item3.Key); foreach (string item4 in item3.Value) { RecordEdge(item3.Key, item4, BfsEdgeKind.InPassEdge, null, 0f); } } } Dictionary dictionary = new Dictionary(); if (terrainResult.RegionVertexList != null) { foreach (KeyValuePair> regionVertex in terrainResult.RegionVertexList) { foreach (Vector3 item5 in regionVertex.Value) { long key = RegionBuilder.PackQuantizedPos(item5); if (!dictionary.ContainsKey(key)) { dictionary[key] = item5; } } } } if (pieceResult.RegionVertexList != null) { foreach (KeyValuePair> regionVertex2 in pieceResult.RegionVertexList) { foreach (Vector3 item6 in regionVertex2.Value) { long key2 = RegionBuilder.PackQuantizedPos(item6); if (!dictionary.ContainsKey(key2)) { dictionary[key2] = item6; } } } } int num = 0; int num2 = 0; if (terrainResult.RegionVertexPositions != null && pieceResult.RegionVertexPositions != null) { Dictionary> dictionary2 = new Dictionary>(); foreach (KeyValuePair> regionVertexPosition in pieceResult.RegionVertexPositions) { foreach (long item7 in regionVertexPosition.Value) { if (!dictionary2.TryGetValue(item7, out var value)) { value = (dictionary2[item7] = new List()); } value.Add(regionVertexPosition.Key); } } foreach (KeyValuePair> regionVertexPosition2 in terrainResult.RegionVertexPositions) { Dictionary dictionary3 = new Dictionary(); foreach (long item8 in regionVertexPosition2.Value) { if (!dictionary2.TryGetValue(item8, out var value2)) { continue; } foreach (string item9 in value2) { if (!dictionary3.ContainsKey(item9)) { dictionary3[item9] = item8; } } } foreach (KeyValuePair item10 in dictionary3) { Vector3 value3; Vector3? repPos = (dictionary.TryGetValue(item10.Value, out value3) ? new Vector3?(value3) : ((Vector3?)null)); RecordEdge(regionVertexPosition2.Key, item10.Key, BfsEdgeKind.CrossVert, repPos, 0f); num++; } } } if (terrainResult.RegionVertexList != null && pieceResult.RegionVertexList != null && terrainResult.RegionBounds != null && pieceResult.RegionBounds != null) { foreach (KeyValuePair> regionVertex3 in terrainResult.RegionVertexList) { if (!terrainResult.RegionBounds.TryGetValue(regionVertex3.Key, out var value4)) { continue; } List value5 = regionVertex3.Value; foreach (KeyValuePair> regionVertex4 in pieceResult.RegionVertexList) { if (!pieceResult.RegionBounds.TryGetValue(regionVertex4.Key, out var value6)) { continue; } float num3 = Mathf.Max(0f, Mathf.Max(((Bounds)(ref value4)).min.x - ((Bounds)(ref value6)).max.x, ((Bounds)(ref value6)).min.x - ((Bounds)(ref value4)).max.x)); float num4 = Mathf.Max(0f, Mathf.Max(((Bounds)(ref value4)).min.y - ((Bounds)(ref value6)).max.y, ((Bounds)(ref value6)).min.y - ((Bounds)(ref value4)).max.y)); float num5 = Mathf.Max(0f, Mathf.Max(((Bounds)(ref value4)).min.z - ((Bounds)(ref value6)).max.z, ((Bounds)(ref value6)).min.z - ((Bounds)(ref value4)).max.z)); if (num3 * num3 + num4 * num4 + num5 * num5 > 0.25f) { continue; } List value7 = regionVertex4.Value; bool flag = false; Vector3 value8 = default(Vector3); float num6 = 0f; for (int i = 0; i < value5.Count; i++) { if (flag) { break; } Vector3 val = value5[i]; for (int j = 0; j < value7.Count; j++) { Vector3 val2 = value7[j]; float num7 = val.x - val2.x; float num8 = val.y - val2.y; float num9 = val.z - val2.z; float num10 = num7 * num7 + num8 * num8 + num9 * num9; if (num10 <= 0.25f) { flag = true; value8 = (val + val2) * 0.5f; num6 = num10; break; } } } if (flag) { RecordEdge(regionVertex3.Key, regionVertex4.Key, BfsEdgeKind.CrossProx, value8, Mathf.Sqrt(num6)); num2++; } } } } HashSet hashSet = new HashSet(); if (anchors != null) { foreach (Vector3 anchor in anchors) { string text = null; float num11 = float.MaxValue; foreach (string regionId in terrainResult.RegionIds) { if (terrainResult.Centroids.TryGetValue(regionId, out var value9) && !(Mathf.Abs(value9.y - anchor.y) > 3f)) { float num12 = value9.x - anchor.x; float num13 = value9.z - anchor.z; float num14 = num12 * num12 + num13 * num13; if (!(num14 > 900f) && num14 < num11) { num11 = num14; text = regionId; } } } if (text != null) { hashSet.Add(text); } } } if (hashSet.Count == 0) { int num15 = anchors?.Count ?? 0; int num16 = terrainResult.RegionIds?.Count ?? 0; ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Region] CrossKind adjacency aborted: no anchor mapped to any terrain region " + $"(anchors={num15}, terrain_regions={num16}). " + "Refusing to seed BFS from a synthetic largest-region fallback; vv_bfs_trace will report no data.")); } return null; } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)($"[Region] CrossKind adjacency built: {combinedAdj.Count} nodes, " + $"seeds={hashSet.Count}, edges={edgeMeta.Count}, " + $"cross_vert={num}, cross_prox={num2} " + "(piece-step edges added downstream by RubberBandPrune)")); } return (combinedAdj, hashSet, edgeMeta); void AddEdgeBoth(string a, string b) { EnsureNode(a); EnsureNode(b); combinedAdj[a].Add(b); combinedAdj[b].Add(a); } void EnsureNode(string id) { if (!combinedAdj.ContainsKey(id)) { combinedAdj[id] = new HashSet(); } } void RecordEdge(string a, string b, BfsEdgeKind kind, Vector3? representativePos, float proxDist) { AddEdgeBoth(a, b); string key3 = BfsAdjacencyStore.EdgeKey(a, b); if (edgeMeta.TryGetValue(key3, out var value10)) { value10.Kinds |= kind; if (!value10.RepresentativePos.HasValue && representativePos.HasValue) { value10.RepresentativePos = representativePos; } if (kind == BfsEdgeKind.CrossProx && (value10.ProxMinDist == 0f || proxDist < value10.ProxMinDist)) { value10.ProxMinDist = proxDist; } edgeMeta[key3] = value10; } else { edgeMeta[key3] = new BfsEdgeMeta { Kinds = kind, RepresentativePos = representativePos, ProxMinDist = ((kind == BfsEdgeKind.CrossProx) ? proxDist : 0f) }; } } } } [RegisterTaskHandler] public class VillageIndexHandler : ITaskHandlerWithLog, ITaskHandler { public string TaskName => "village_index"; public TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog) { (int villages, int withGraph) tuple = VillageRegistry.HydrateAll(); int item = tuple.villages; int item2 = tuple.withGraph; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[village_index] villages={item} with_graph={item2}"); } activityLog.Record(task.SourceId, TaskName, "index", $"villages={item} with_graph={item2}"); return TaskResult.Ok(new Dictionary { { "villages", item.ToString() }, { "with_graph", item2.ToString() } }); } } [RegisterTaskHandler] public class VillagerRecordIndexHandler : ITaskHandlerWithLog, ITaskHandler { public string TaskName => "villager_record_index"; public TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog) { //IL_00f0: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) ZDOMan instance = ZDOMan.instance; if (instance == null) { return TaskResult.Fail("ZDOMan not ready"); } Dictionary value = Traverse.Create((object)instance).Field>("m_objectsByID").Value; if (value == null) { return TaskResult.Fail("m_objectsByID unavailable"); } List list = new List(); foreach (ZDO value2 in value.Values) { if (value2 != null && string.IsNullOrEmpty(value2.GetString("vv_record_id", "")) && !string.IsNullOrEmpty(value2.GetString("vv_villager_type", ""))) { list.Add(value2); } } int num = 0; foreach (ZDO item in list) { string text = item.GetString("vv_villager_type", ""); string text2 = item.GetString("vv_villager_name", ""); Vector3 vec = item.GetVec3("vv_home_position", Vector3.zero); string text3 = item.GetString("vv_village_id", ""); string text4 = ((!string.IsNullOrEmpty(text3)) ? text3 : (VillageRegistry.GetVillageCovering(vec) ?? VillageRegistry.FindNearAnchor(vec))?.VillageId); if (string.IsNullOrEmpty(text4)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)($"[villager_record_index] legacy villager '{text2}' ({text}) at {vec} resolves to " + "no village; not migrating.")); } continue; } VillagerRecord villagerRecord = VillagerRecordTable.Create(text, string.IsNullOrEmpty(text2) ? text : text2, text4, vec, RecordStatus.Alive, item.m_uid); if (villagerRecord != null) { item.Set("vv_record_id", villagerRecord.RecordId); item.Set("vv_village_id", text4); num++; } } int num2 = VillagerRecordTable.AuditOrphans(); int num3 = VillagerRecordTable.EnumerateAll().Count(); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[villager_record_index] records={num3} migrated={num} orphans={num2}"); } activityLog.Record(task.SourceId, TaskName, "index", $"records={num3} migrated={num} orphans={num2}"); return TaskResult.Ok(new Dictionary { { "records_total", num3.ToString() }, { "migrated", num.ToString() }, { "orphans", num2.ToString() } }); } } [RegisterTaskHandler] public class WorkOrderScanHandler : ITaskHandlerWithLog, ITaskHandler { private struct RejectionRecord { public string ItemPrefab; public string Station; public string PhysicalStation; public string Reason; public bool IsUnimplemented; public Vector3 WorkOrderPosition; } public string TaskName => "work_order_scan"; public TaskResult Handle(VillagerTask task, VillagerActivityLog activityLog) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_03ee: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_0779: Unknown result type (might be due to invalid IL or missing references) //IL_0794: Unknown result type (might be due to invalid IL or missing references) //IL_064f: Unknown result type (might be due to invalid IL or missing references) //IL_059d: Unknown result type (might be due to invalid IL or missing references) //IL_0590: Unknown result type (might be due to invalid IL or missing references) //IL_0676: Unknown result type (might be due to invalid IL or missing references) //IL_05c9: Unknown result type (might be due to invalid IL or missing references) //IL_0914: Unknown result type (might be due to invalid IL or missing references) //IL_0919: Unknown result type (might be due to invalid IL or missing references) //IL_06a5: Unknown result type (might be due to invalid IL or missing references) //IL_06b2: Unknown result type (might be due to invalid IL or missing references) //IL_06b4: Unknown result type (might be due to invalid IL or missing references) //IL_0877: Unknown result type (might be due to invalid IL or missing references) //IL_087c: Unknown result type (might be due to invalid IL or missing references) if (!task.Attributes.TryGetValue("villager_id", out var value)) { return TaskResult.Fail("Missing villager_id"); } if (!task.Attributes.TryGetValue("villager_type", out var value2) || string.IsNullOrEmpty(value2)) { return TaskResult.Fail("Missing villager_type"); } if (!TaskAttributeParser.TryParsePosition(task.Attributes, "home", out var result)) { return TaskResult.Fail("Missing or invalid anchor position"); } if (!VillagerAIManager.ActiveVillagers.TryGetValue(value, out var value3)) { return TaskResult.Fail("Villager " + value + " not found in active villagers"); } List list = ContainerScanner.FindNearbyContainers(result, 20f); if (list.Count == 0) { return TaskResult.Fail("No containers found near anchor"); } List list2 = ContainerScanner.FindAllWorkOrders(list, value2); if (list2 == null || list2.Count == 0) { return TaskResult.Ok(); } if (!VillageStationRegistry.HasVillageFor(result)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[WorkOrderScan] {value3.NpcName} deferring scan — no village registered yet at anchor {result}"); } return TaskResult.Ok(); } List list3 = new List(); foreach (WorkOrderMatch match in list2) { int num = ContainerScanner.CountAcrossContainers(list, match.ItemPrefabName); if (num >= match.MaxQuantity) { list3.Add(new RejectionRecord { ItemPrefab = match.ItemPrefabName, Station = match.StationName, PhysicalStation = null, Reason = $"Already have {num}/{match.MaxQuantity}", IsUnimplemented = false, WorkOrderPosition = ((Component)match.SourceContainer).transform.position }); continue; } Recipe val = StationMatcher.FindRecipeForNpc(match.ItemPrefabName, value2); if ((Object)(object)val == (Object)null) { list3.Add(new RejectionRecord { ItemPrefab = match.ItemPrefabName, Station = match.StationName, PhysicalStation = null, Reason = "No recipe for '" + match.ItemPrefabName + "'", IsUnimplemented = false, WorkOrderPosition = ((Component)match.SourceContainer).transform.position }); continue; } int amount = ((val.m_amount <= 0) ? 1 : val.m_amount); if (!ContainerScanner.CanAcceptItem(match.SourceContainer, match.ItemPrefabName, amount)) { list3.Add(new RejectionRecord { ItemPrefab = match.ItemPrefabName, Station = match.StationName, PhysicalStation = null, Reason = "Output chest full", IsUnimplemented = false, WorkOrderPosition = ((Component)match.SourceContainer).transform.position }); continue; } string physicalStation = VirtualRecipeLoader.GetPhysicalStation(((Object)val).name); List list4 = ContainerScanner.FindIngredients(list, val); if (list4 == null && physicalStation != "farm") { list3.Add(new RejectionRecord { ItemPrefab = match.ItemPrefabName, Station = match.StationName, PhysicalStation = null, Reason = "Missing ingredients for " + match.ItemPrefabName, IsUnimplemented = false, WorkOrderPosition = ((Component)match.SourceContainer).transform.position }); continue; } if (physicalStation == "farm") { FarmingContext farmingContext = FarmWorkOrderHelper.BuildFarmingContext(value3, match, val, list4, num); if (farmingContext == null) { list3.Add(new RejectionRecord { ItemPrefab = match.ItemPrefabName, Station = match.StationName, PhysicalStation = physicalStation, Reason = "No farm location in memory", IsUnimplemented = false, WorkOrderPosition = ((Component)match.SourceContainer).transform.position }); continue; } activityLog.Record(value, TaskName, "farm_work_matched", "matched farming work order for " + match.ItemPrefabName); return TaskResult.Ok(new Dictionary { { "item_prefab", match.ItemPrefabName }, { "station_name", match.StationName }, { "existing_count", num.ToString() }, { "is_farming", "true" } }, farmingContext); } CookingStation val2 = null; Smelter val3 = null; string smelterInputItemName = null; FuelNeed? fuelRequirement = null; Container fuelContainer = null; Vector3? val4; string text; if (physicalStation == "cookingstation") { if (VillageStationRegistry.TryFindStation(result, (Func)((CookingStation s) => StationFinder.IsCookingStationReady(s)), out Vector3 stationPos, out CookingStation component)) { val4 = stationPos; val2 = component; } else if (VillageStationRegistry.TryFindStation(result, (Func)null, out stationPos, out component)) { if (StationFuelHelper.DiagnoseFuelNeed(component, out var need) && StationFuelHelper.FindFuelInContainers(list, need.FuelItemPrefab, out var fuelContainer2)) { val4 = stationPos; val2 = component; fuelRequirement = need; fuelContainer = fuelContainer2; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[WorkOrderScan] Station needs fuel (" + need.FuelItemPrefab + "), found in container. Will fuel before cooking.")); } } else { val4 = null; } } else { val4 = null; } text = "CookingStation"; } else if (!string.IsNullOrEmpty(physicalStation) && (Object)(object)StationFinder.GetSmelterPrefab(physicalStation) != (Object)null) { if (VillageStationRegistry.TryFindStation(result, (Func)((Smelter s) => (Object)(object)s != (Object)null && PrefabNameMatches(((Object)((Component)s).gameObject).name, physicalStation)), out Vector3 stationPos2, out Smelter component2)) { FuelNeed need2; Container fuelContainer3; if (StationFinder.IsSmelterReady(component2)) { val4 = stationPos2; val3 = component2; } else if (StationFuelHelper.DiagnoseFuelNeed(component2, out need2) && StationFuelHelper.FindFuelInContainers(list, need2.FuelItemPrefab, out fuelContainer3)) { val4 = stationPos2; val3 = component2; need2.FuelTargetPosition = stationPos2; fuelRequirement = need2; fuelContainer = fuelContainer3; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[WorkOrderScan] Smelter (" + physicalStation + ") needs fuel (" + need2.FuelItemPrefab + "), found in container. Will fuel before smelting.")); } } else { val4 = null; } if ((Object)(object)val3 != (Object)null && val.m_resources != null && val.m_resources.Length != 0 && (Object)(object)val.m_resources[0].m_resItem != (Object)null) { smelterInputItemName = ((Object)((Component)val.m_resources[0].m_resItem).gameObject).name; } } else { val4 = null; } text = physicalStation; } else { val4 = ((!VillageStationRegistry.TryFindStation(result, (Func)((CraftingStation cs) => cs.m_name == match.StationName), out Vector3 stationPos3, out CraftingStation _)) ? ((Vector3?)null) : new Vector3?(stationPos3)); text = match.StationName; } if (!val4.HasValue) { bool isUnimplemented = physicalStation != null && physicalStation != "farm" && physicalStation != "cookingstation" && (Object)(object)StationFinder.GetSmelterPrefab(physicalStation) == (Object)null; list3.Add(new RejectionRecord { ItemPrefab = match.ItemPrefabName, Station = match.StationName, PhysicalStation = physicalStation, Reason = "No station '" + text + "' in village", IsUnimplemented = isUnimplemented, WorkOrderPosition = ((Component)match.SourceContainer).transform.position }); continue; } string cookingInputItemName = null; if ((Object)(object)val2 != (Object)null && val.m_resources != null && val.m_resources.Length != 0 && (Object)(object)val.m_resources[0].m_resItem != (Object)null) { cookingInputItemName = ((Object)((Component)val.m_resources[0].m_resItem).gameObject).name; } WorkOrderContext payload = new WorkOrderContext { SourceContainer = match.SourceContainer, WorkOrder = match, Recipe = val, IngredientSources = list4, CraftStationPosition = val4.Value, CookingStationRef = val2, CookingInputItemName = cookingInputItemName, CraftedCount = num, CurrentIngredientIndex = 0, FuelRequirement = fuelRequirement, FuelContainer = fuelContainer, SmelterRef = val3, SmelterInputItemName = smelterInputItemName, SmelterProcessedAtStart = 0, SmelterRemovalRequested = false, SmelterItemAlreadyInChest = false }; string text2 = string.Join(", ", list4.Select((IngredientSource i) => $"{i.Amount}x {i.PrefabName}")); activityLog.Record(value, TaskName, "work_order_matched", "matched work order for " + match.ItemPrefabName + " (need: " + text2 + ", station: " + match.StationName + ")"); return TaskResult.Ok(new Dictionary { { "item_prefab", match.ItemPrefabName }, { "station_name", match.StationName }, { "existing_count", num.ToString() } }, payload); } EmitRejections(list3, value3, activityLog, value); return TaskResult.Ok(); } private void EmitRejections(List rejections, VillagerAI ai, VillagerActivityLog activityLog, string villagerId) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if (rejections.Count == 0) { return; } bool num = rejections.Any((RejectionRecord r) => r.IsUnimplemented); string text = string.Concat(str1: string.Join("\n", rejections.Select(delegate(RejectionRecord r) { string text2 = r.PhysicalStation ?? r.Station; return " " + r.ItemPrefab + " [" + text2 + "] — " + r.Reason; })), str0: $"[WorkOrderScan] {ai.NpcName} blocked on {rejections.Count} orders:\n"); if (num) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)text); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)text); } } foreach (RejectionRecord rejection in rejections) { string stationName = rejection.PhysicalStation ?? rejection.Station; activityLog.RecordBlocked(villagerId, TaskName, rejection.ItemPrefab, stationName, rejection.Reason, rejection.WorkOrderPosition); } } private static bool PrefabNameMatches(string instanceName, string prefabName) { if (string.IsNullOrEmpty(instanceName) || string.IsNullOrEmpty(prefabName)) { return false; } if (instanceName == prefabName) { return true; } int num = instanceName.IndexOf("(Clone)", StringComparison.Ordinal); if (num > 0) { instanceName = instanceName.Substring(0, num); } return instanceName == prefabName; } } } namespace ValheimVillages.TaskQueue.ActivityLog { public class ActivityLogEntry { public string Action; public bool Committed; public string Description; public string TaskName; public float Timestamp; public string VillagerId; public string ItemPrefab; public string StationName; public string Reason; public float? WorkOrderPosX; public float? WorkOrderPosY; public float? WorkOrderPosZ; } public class VillagerActivityLog { private const string ZdoKey = "vv_wal"; private const char FieldSeparator = '\u001f'; private const char EntrySeparator = '\u001e'; private static VillagerActivityLog s_instance; private readonly Dictionary> m_logs = new Dictionary>(); public static VillagerActivityLog Instance => s_instance ?? (s_instance = new VillagerActivityLog()); public void Record(string villagerId, string taskName, string action, string description) { if (!string.IsNullOrEmpty(villagerId)) { if (!m_logs.TryGetValue(villagerId, out var value)) { value = new List(); m_logs[villagerId] = value; } if (value.Count >= 100) { TrimOldest(value); } value.Add(new ActivityLogEntry { Timestamp = Time.time, VillagerId = villagerId, TaskName = taskName, Action = action, Description = description, Committed = false }); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[ActivityLog:" + villagerId + "] " + taskName + "/" + action + ": " + description)); } } } public void RecordBlocked(string villagerId, string taskName, string itemPrefab, string stationName, string reason, Vector3? workOrderPosition) { //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(villagerId)) { if (!m_logs.TryGetValue(villagerId, out var value)) { value = new List(); m_logs[villagerId] = value; } value.RemoveAll((ActivityLogEntry e) => e.VillagerId == villagerId && e.TaskName == taskName && e.Action == "blocked" && e.ItemPrefab == itemPrefab && e.StationName == stationName && e.Reason == reason); if (value.Count >= 100) { TrimOldest(value); } string text = string.Empty; if (!string.IsNullOrEmpty(itemPrefab)) { text = itemPrefab; } if (!string.IsNullOrEmpty(stationName)) { text = text + " [" + stationName + "]"; } text = text.Trim(); string text2 = (string.IsNullOrEmpty(text) ? reason : (text + " — " + reason)); value.Add(new ActivityLogEntry { Timestamp = Time.time, VillagerId = villagerId, TaskName = taskName, Action = "blocked", Description = text2, ItemPrefab = itemPrefab, StationName = stationName, Reason = reason, WorkOrderPosX = workOrderPosition?.x, WorkOrderPosY = workOrderPosition?.y, WorkOrderPosZ = workOrderPosition?.z, Committed = false }); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[ActivityLog:" + villagerId + "] " + taskName + "/blocked: " + text2)); } } } public IReadOnlyList GetEntries(string villagerId) { if (!m_logs.TryGetValue(villagerId, out var value)) { return new List(); } return value; } public List GetUncommitted(string villagerId) { if (!m_logs.TryGetValue(villagerId, out var value)) { return new List(); } return value.Where((ActivityLogEntry e) => !e.Committed).ToList(); } public void MarkCommitted(string villagerId) { if (!m_logs.TryGetValue(villagerId, out var value)) { return; } foreach (ActivityLogEntry item in value) { item.Committed = true; } } public void TrimCommitted(string villagerId) { if (!m_logs.TryGetValue(villagerId, out var value)) { return; } List list = value.Where((ActivityLogEntry e) => e.Committed).ToList(); if (list.Count > 10) { int count = list.Count - 10; HashSet toRemove = new HashSet(list.Take(count)); value.RemoveAll((ActivityLogEntry e) => toRemove.Contains(e)); } } public void SaveToZDO(string villagerId, ZDO zdo) { if (zdo == null) { return; } List uncommitted = GetUncommitted(villagerId); if (uncommitted.Count == 0) { zdo.Set("vv_wal", ""); return; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < uncommitted.Count; i++) { ActivityLogEntry activityLogEntry = uncommitted[i]; if (i > 0) { stringBuilder.Append('\u001e'); } stringBuilder.Append(activityLogEntry.Timestamp.ToString("F2")); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.TaskName ?? ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.Action ?? ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.Description ?? ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.ItemPrefab ?? ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.StationName ?? ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.Reason ?? ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.WorkOrderPosX.HasValue ? activityLogEntry.WorkOrderPosX.Value.ToString(CultureInfo.InvariantCulture) : ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.WorkOrderPosY.HasValue ? activityLogEntry.WorkOrderPosY.Value.ToString(CultureInfo.InvariantCulture) : ""); stringBuilder.Append('\u001f'); stringBuilder.Append(activityLogEntry.WorkOrderPosZ.HasValue ? activityLogEntry.WorkOrderPosZ.Value.ToString(CultureInfo.InvariantCulture) : ""); } zdo.Set("vv_wal", stringBuilder.ToString()); } public void LoadFromZDO(string villagerId, ZDO zdo) { if (zdo == null) { return; } string text = zdo.GetString("vv_wal", ""); if (string.IsNullOrEmpty(text)) { return; } if (!m_logs.TryGetValue(villagerId, out var value)) { value = new List(); m_logs[villagerId] = value; } string[] array = text.Split(new char[1] { '\u001e' }); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string[] array3 = array2[i].Split(new char[1] { '\u001f' }); if (array3.Length < 4 || !float.TryParse(array3[0], out var result)) { continue; } float? workOrderPosX = null; float? workOrderPosY = null; float? workOrderPosZ = null; if (array3.Length >= 10) { if (float.TryParse(array3[7], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { workOrderPosX = result2; } if (float.TryParse(array3[8], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { workOrderPosY = result3; } if (float.TryParse(array3[9], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4)) { workOrderPosZ = result4; } } value.Add(new ActivityLogEntry { Timestamp = result, VillagerId = villagerId, TaskName = array3[1], Action = array3[2], Description = array3[3], ItemPrefab = ((array3.Length >= 7) ? array3[4] : null), StationName = ((array3.Length >= 7) ? array3[5] : null), Reason = ((array3.Length >= 7) ? array3[6] : null), WorkOrderPosX = workOrderPosX, WorkOrderPosY = workOrderPosY, WorkOrderPosZ = workOrderPosZ, Committed = false }); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)$"[ActivityLog:{villagerId}] Loaded {array.Length} entries from ZDO"); } } public void ClearVillager(string villagerId) { m_logs.Remove(villagerId); } public void Clear() { m_logs.Clear(); } [RegisterCleanup] public static void ResetInstance() { s_instance?.Clear(); s_instance = null; } private static void TrimOldest(List entries) { int num = entries.Count - 100 + 1; if (num > 0) { entries.RemoveRange(0, num); } } } } namespace ValheimVillages.Tags { public static class TagParser { public static bool TryParse(string tag, out string ns, out string value) { ns = null; value = null; if (string.IsNullOrEmpty(tag)) { return false; } int num = tag.IndexOf(':'); if (num <= 0 || num >= tag.Length - 1) { return false; } ns = tag.Substring(0, num).Trim(); value = tag.Substring(num + 1).Trim(); if (ns.Length > 0) { return value.Length > 0; } return false; } public static string GetNamespace(string tag) { if (!TryParse(tag, out var ns, out var _)) { return null; } return ns; } public static string GetValue(string tag) { if (!TryParse(tag, out var _, out var value)) { return null; } return value; } public static List FilterByNamespace(IEnumerable tags, string ns) { List list = new List(); foreach (string tag in tags) { if (TryParse(tag, out var ns2, out var _) && string.Equals(ns2, ns, StringComparison.OrdinalIgnoreCase)) { list.Add(tag); } } return list; } public static List GetValues(IEnumerable tags, string ns) { List list = new List(); foreach (string tag in tags) { if (TryParse(tag, out var ns2, out var value) && string.Equals(ns2, ns, StringComparison.OrdinalIgnoreCase)) { list.Add(value); } } return list; } public static bool HasTag(IEnumerable tags, string ns, string value) { foreach (string tag in tags) { if (TryParse(tag, out var ns2, out var value2) && string.Equals(ns2, ns, StringComparison.OrdinalIgnoreCase) && string.Equals(value2, value, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public static bool HasNamespace(IEnumerable tags, string ns) { foreach (string tag in tags) { if (TryParse(tag, out var ns2, out var _) && string.Equals(ns2, ns, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } } namespace ValheimVillages.Settings { public static class VillagerSettings { public const float MaxWanderRange = 200f; public const float DiscoveryRadius = 20f; public const float UpdateInterval = 15f; public const float PatrolWaypointLookahead = 2f; public const float BehaviorReselectIntervalSec = 2f; public const float PostWorkLingerSec = 15f; public const float BehaviorTickJitter = 11f; public const float ArrivalThreshold = 1f; public const float PathNodePopThreshold = 0.5f; public const float NavMeshBakeRadiusBuffer = 0.025f; public const float PatrolHardStuckTimeoutSeconds = 60f; public const float PathStallEscapeSeconds = 10f; public const int MaxRecoveryAttempts = 3; public const float RecoveryBackoffBaseSeconds = 5f; public const float RecoveryBackoffMaxSeconds = 30f; public const float StepJumpForceFraction = 0.6f; public const bool StepJumpEnabled = false; public const bool AutoPathRecoveryEnabled = false; public const bool AutoDiagnosticCaptureEnabled = false; public const float NightStart = 0.875f; public const float MorningStart = 0.25f; public const float DayStart = 0.417f; public const float EveningStart = 0.708f; } public static class DoorSettings { public const float DoorCloseDelay = 1.5f; public const float DoorDetectionRadius = 3f; public const float MovementStallThreshold = 1f; public const float MovementProgressThreshold = 0.5f; } public static class ExplorationSettings { public const int MinDesiredVariety = 4; public const float ExplorationChance = 0.4f; public const float MinDistanceFromKnown = 25f; public const float MaxExplorationRange = 250f; public const float ExplorationDuration = 5f; public const float ExplorationWanderRadius = 25f; } public static class WorkSettings { public const float ChestScanRadius = 20f; public const float HaulScanRadius = 32f; public const float CraftDuration = 5f; public const float WorkScanInterval = 6f; public const float WorkArrivalThreshold = 2.5f; public const float WaitingPollInterval = 3f; public const float CookingDoneGraceSeconds = 1.5f; public const float WorkStuckTimeoutSeconds = 30f; public const float RepairScanRadius = 40f; } public static class CombatSettings { public const float DetectionRadius = 25f; public const float LeashRadius = 40f; public const float MeleeAttackRange = 2.2f; public const float RangedEngageRange = 22f; public const float RangedMinStandoff = 8f; public const float TargetRescanInterval = 1f; public const float ChaseRepathInterval = 0.35f; public const int AmmoTopUpStack = 20; public const float VillageThreatRadius = 18f; public const float FleeDangerRadius = 16f; public const float FleeClearRadius = 24f; public const float FleeDistance = 14f; public const float LosEyeHeight = 1.5f; public const float LosSearchInterval = 0.4f; public const int LosMaxSearchFails = 3; public const float LosIgnoreSeconds = 8f; public const int LosSampleCount = 12; } public static class DevSettings { public const bool ShowDebugTools = false; } internal static class HelpCommand { [DevCommand("List all Valheim Villages dev commands (try also: vv help, vv --help)", Name = "vv")] public static void PrintHelp(ConsoleEventArgs args) { List<(string, string)> list = (from c in AttributeScanner.GetRegisteredDevCommands() orderby c.Name select c).ToList(); if (list.Count == 0) { Console instance = Console.instance; if (instance != null) { instance.Print("[vv] No dev commands registered."); } return; } int totalWidth = list.Max<(string, string)>(((string Name, string Description) c) => c.Name.Length); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("[vv] ").Append(list.Count).Append(" dev command(s):"); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(stringBuilder.ToString()); } foreach (var (text, text2) in list) { stringBuilder.Clear(); stringBuilder.Append(" ").Append(text.PadRight(totalWidth)).Append(" ") .Append(text2 ?? ""); Console instance3 = Console.instance; if (instance3 != null) { instance3.Print(stringBuilder.ToString()); } } } } internal static class LogCommands { [DevCommand("Toggle high-volume NavMesh probe-area logging on/off", Name = "vv_log_navmesh")] public static void ToggleVerboseNavMesh(ConsoleEventArgs args) { LogSettings.VerboseNavMesh = !LogSettings.VerboseNavMesh; string text = (LogSettings.VerboseNavMesh ? "ON" : "OFF"); string text2 = "[LogSettings] VerboseNavMesh = " + text; Console instance = Console.instance; if (instance != null) { instance.Print(text2); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text2); } } } public static class LogSettings { public static bool VerboseNavMesh; } } namespace ValheimVillages.Schemas { public struct BehaviorContext { public bool IsRaining; public TimeOfDay TimeOfDay; public bool InShelter; public float CurrentComfort; public Vector3 CurrentPosition; } public class KnownLocation { public const float SameLocationThreshold = 2f; public Vector3 Position { get; set; } public LocationType Type { get; set; } public bool HasShelter { get; set; } public float ComfortValue { get; set; } public float LastVisitedAt { get; set; } public bool IsSameLocation(Vector3 other) { //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) return Vector3.Distance(Position, other) < 2f; } public bool IsTooCloseForSameType(Vector3 other) { //IL_000d: 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) float minDistanceForType = GetMinDistanceForType(Type); return Vector3.Distance(Position, other) < minDistanceForType; } public static float GetMinDistanceForType(LocationType type) { return type switch { LocationType.Home => 3f, LocationType.Shelter => 20f, LocationType.Fire => 15f, LocationType.Table => 10f, LocationType.Farm => 25f, LocationType.Animals => 20f, LocationType.CraftStation => 5f, LocationType.CookingStation => 5f, _ => 10f, }; } public static int GetMaxLocationsForType(LocationType type) { return type switch { LocationType.Home => 1, LocationType.Shelter => 3, LocationType.Fire => 2, LocationType.Table => 2, LocationType.Farm => 2, LocationType.Animals => 2, LocationType.CraftStation => 3, LocationType.CookingStation => 5, _ => 3, }; } public float GetQualityScore() { float num = ComfortValue * 10f; if (HasShelter) { num += 5f; } return num; } } public class TabDetailData { public string Title { get; set; } public string Description { get; set; } public string ActionText { get; set; } public Action OnAction { get; set; } } public class TabListItem { public string TabName { get; set; } } public class TaskResult { public Dictionary Data; public string Error; public object Payload; public bool Success; public static TaskResult Ok(Dictionary data = null, object payload = null) { return new TaskResult { Success = true, Data = data, Payload = payload }; } public static TaskResult Fail(string error) { return new TaskResult { Success = false, Error = error }; } } public class VillagerTask { public Dictionary Attributes; public Action Callback; public float CreatedAt; public string Name; public float NotBefore; public TaskPriority Priority; public int RetryCount; public string SourceId; public float TimeoutSeconds; } public static class TaskSettings { public const int MaxRetries = 3; public const float DefaultTimeoutSeconds = 30f; public const int MaxDeadLetterSize = 50; public const int MaxActivityLogEntriesPerVillager = 100; } [Serializable] public class VillagerDef { public string type = ""; public string category = ""; public string displayName = ""; public string description = ""; public bool disabled; public List workbenches = new List(); public List requiredBiomes = new List(); public List preferredBiomes = new List(); public bool requiresCoastal; public int minComfortLevel = 2; public string materialRequirements = ""; public string scalingType = "Comfort"; public string dependentOnNpcType = ""; public List tieredBenefits = new List(); public List productions = new List(); public List providesLevelTo = new List(); public List receivesLevelFrom = new List(); public string interdependenceDescription = ""; public string preferredPrefab = ""; public List equipment = new List(); public string skinColor = ""; public string stationName = ""; public string stationIcon = ""; public List workStations = new List(); public List stationRecipes = new List(); public List cultivatorExclusions = new List(); public List behaviors = new List(); public List tags = new List(); public List randomTalk = new List(); public List randomGreets = new List(); public List randomGoodbye = new List(); } [Serializable] public class WorkbenchRequirement { public string name = ""; public int minLevel = 1; } [Serializable] public class TieredBenefit { public int minLevel = 1; public int maxLevel = 99; public string description = ""; public float effectMultiplier = 1f; } [Serializable] public class ProductionOutput { public int requiredLevel = 1; public string outputItem = ""; public string description = ""; } [Serializable] public class StationRecipe { public string output = ""; public int outputAmount = 1; public string input = ""; public int inputAmount = 1; public int minStationLevel = 1; } public enum WorkSubState { Idle, GatheringFuel, FuelingStation, GatheringIngredients, TravelingToStation, Crafting, ReturningToChest, Depositing } public class WorkOrderContext { public string CookingInputItemName; public bool CookingItemAlreadyInChest; public bool CookingRemovalRequested; public CookingStation CookingStationRef; public float CraftCookTimeSeconds; public float CraftStartTime; public Vector3 CraftStationPosition; public int CraftedCount; public int CurrentIngredientIndex; public Container FuelContainer; public FuelNeed? FuelRequirement; public List IngredientSources; public bool IsRescue; public Recipe Recipe; public string SmelterInputItemName; public bool SmelterItemAlreadyInChest; public int SmelterProcessedAtStart; public Smelter SmelterRef; public bool SmelterRemovalRequested; public Container SourceContainer; public WorkOrderMatch WorkOrder; public List HeldItems = new List(); } public class HeldItem { public Container SourceContainer; public string PrefabName; public int Amount; } public class WorkOrderMatch { public ItemData ItemData; public string ItemPrefabName; public int MaxQuantity; public int MinQuantity; public Container SourceContainer; public string StationName; } public class IngredientSource { public int Amount; public Container Container; public string PrefabName; } } namespace ValheimVillages.Patches { [HarmonyPatch(typeof(ItemDrop), "Awake")] public static class ItemDropAwakePatch { [HarmonyPostfix] public static void Postfix(ItemDrop __instance) { GameObject gameObject = ((Component)__instance).gameObject; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[ItemDrop.Awake] " + ((gameObject != null) ? ((Object)gameObject).name : null))); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPriority(700)] public static class ObjectDBAwakePatch { [HarmonyPostfix] public static void Postfix(ObjectDB __instance) { ItemFactory.RegisterAll(__instance); VirtualRecipeLoader.RegisterAll(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] [HarmonyPriority(700)] public static class ObjectDBCopyPatch { [HarmonyPostfix] public static void Postfix(ObjectDB __instance) { ItemFactory.RegisterAll(__instance); VirtualRecipeLoader.RegisterAll(__instance); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] [HarmonyPriority(700)] public static class ZNetSceneAwakePatch { [HarmonyPostfix] public static void Postfix(ZNetScene __instance) { ItemFactory.RegisterAllInZNetScene(__instance); PieceFactory.RegisterAllInZNetScene(__instance); RecordPrefabFactory.RegisterInZNetScene(__instance); VillagePrefabFactory.RegisterInZNetScene(__instance); VirtualRecipeLoader.RegisterCookingRecipesIfNeeded(ObjectDB.instance); VillagerSpawner.LogAvailableDvergrPrefabs(); } } [HarmonyPatch(typeof(Localization), "SetupLanguage")] public static class LocalizationPatch { private static Dictionary s_tokens; private static MethodInfo s_addWord; private static Dictionary Tokens { get { if (s_tokens != null) { return s_tokens; } s_tokens = new Dictionary { { "vv_villager", "Villager" } }; foreach (KeyValuePair definition in VillagerRegistry.Definitions) { if (!string.IsNullOrEmpty(definition.Value.stationName)) { string key = definition.Value.stationName.TrimStart(new char[1] { '$' }); s_tokens[key] = definition.Value.displayName; } } return s_tokens; } } public static void RegisterTokens() { Localization instance = Localization.instance; if (instance != null) { AddTokens(instance); } } [HarmonyPostfix] public static void Postfix(Localization __instance) { AddTokens(__instance); } private static void AddTokens(Localization instance) { if ((object)s_addWord == null) { s_addWord = AccessTools.Method(typeof(Localization), "AddWord", new Type[2] { typeof(string), typeof(string) }, (Type[])null); } if (s_addWord == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"LocalizationPatch: AddWord method not found"); } return; } foreach (KeyValuePair token in Tokens) { s_addWord.Invoke(instance, new object[2] { token.Key, token.Value }); } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"LocalizationPatch: Registered {Tokens.Count} custom tokens"); } } } [HarmonyPatch] public static class PieceChangePatch { internal static float LastStructureChangeTime { get; private set; } internal static bool IsDirty { get; set; } [RegisterCleanup] public static void Reset() { IsDirty = false; LastStructureChangeTime = 0f; } private static void MarkDirty() { IsDirty = true; LastStructureChangeTime = Time.realtimeSinceStartup; } [HarmonyPostfix] [HarmonyPatch(typeof(Piece), "SetCreator")] private static void OnPiecePlaced() { MarkDirty(); } [HarmonyPrefix] [HarmonyPatch(typeof(WearNTear), "Remove")] private static void OnPieceRemoved() { MarkDirty(); } } [HarmonyPatch(typeof(ItemDrop), "Awake")] public static class ItemDropAwakeProtectionPatch { [HarmonyPrefix] public static bool Prefix(ItemDrop __instance) { string name = ((Object)((Component)__instance).gameObject).name; if (name.StartsWith("vv_") && !name.Contains("(Clone)")) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[ItemDrop.Awake] Skipping for template: " + name)); } return false; } return true; } } [HarmonyPatch(typeof(ItemDrop), "OnDestroy")] public static class ItemDropOnDestroyProtectionPatch { [HarmonyPrefix] public static bool Prefix(ItemDrop __instance) { string name = ((Object)((Component)__instance).gameObject).name; if (name.StartsWith("vv_") && !name.Contains("(Clone)")) { return false; } return true; } } [HarmonyPatch(typeof(ZNetView), "Awake")] public static class ZNetViewAwakeProtectionPatch { [HarmonyPrefix] public static bool Prefix(ZNetView __instance) { string name = ((Object)((Component)__instance).gameObject).name; if (name.StartsWith("vv_") && !name.Contains("(Clone)")) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[ZNetView.Awake] Skipping for template: " + name)); } return false; } return true; } } [HarmonyPatch(typeof(ZDOMan), "ReleaseNearbyZDOS")] public static class VillagerZDOOwnershipPatch { [HarmonyPostfix] private static void Postfix(Vector3 refPosition) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } Vector2i zone = ZoneSystem.GetZone(refPosition); List list = new List(); ZDOMan.instance.FindSectorObjects(zone, ZoneSystem.instance.m_activeArea, 0, list, (List)null); long uID = ZNet.GetUID(); foreach (ZDO item in list) { if (!string.IsNullOrEmpty(item.GetString("vv_record_id", "")) && item.GetOwner() != uID) { item.SetOwner(uID); } } } } public static class VillageZoneLoadingPatch { [HarmonyPatch(typeof(ZoneSystem), "CreateLocalZones")] [HarmonyPatch(new Type[] { typeof(Vector3) })] private static class ZoneSystemCreateZonesPatch { } [HarmonyPatch(typeof(ZoneSystem), "Update")] private static class ZoneSystemUpdatePatch { [HarmonyPostfix] private static void Postfix(ZoneSystem __instance) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List phantomPositions = GetPhantomPositions(); if (phantomPositions.Count == 0) { return; } Traverse val = Traverse.Create((object)__instance); foreach (Vector3 item in phantomPositions) { val.Method("CreateLocalZones", new object[1] { item }).GetValue(); } } } [HarmonyPatch(typeof(ZNetScene), "CreateDestroyObjects")] private static class ZNetSceneCreateDestroyPatch { [HarmonyPrefix] private static bool Prefix(ZNetScene __instance) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return true; } List phantomPositions = GetPhantomPositions(); if (phantomPositions.Count == 0) { return true; } Traverse val = Traverse.Create((object)__instance); List value = val.Field>("m_tempCurrentObjects").Value; List value2 = val.Field>("m_tempCurrentDistantObjects").Value; value.Clear(); value2.Clear(); Vector2i zone = ZoneSystem.GetZone(ZNet.instance.GetReferencePosition()); int activeArea = ZoneSystem.instance.m_activeArea; int activeDistantArea = ZoneSystem.instance.m_activeDistantArea; ZDOMan.instance.FindSectorObjects(zone, activeArea, activeDistantArea, value, value2); foreach (Vector3 item in phantomPositions) { Vector2i zone2 = ZoneSystem.GetZone(item); if (zone2.x != zone.x || zone2.y != zone.y) { ZDOMan.instance.FindSectorObjects(zone2, activeArea, 0, value, (List)null); } } val.Method("CreateObjects", new object[2] { value, value2 }).GetValue(); val.Method("RemoveObjects", new object[2] { value, value2 }).GetValue(); return false; } } private const int MaxPhantomZones = 10; private const float ZoneSize = 64f; private static List GetPhantomPositions() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0042: 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_0064: Unknown result type (might be due to invalid IL or missing references) List allAnchorPositions = VillagerAIManager.GetAllAnchorPositions(); if (allAnchorPositions.Count == 0) { return allAnchorPositions; } HashSet hashSet = new HashSet(); List list = new List(); Vector2Int item = default(Vector2Int); foreach (Vector3 item2 in allAnchorPositions) { ((Vector2Int)(ref item))..ctor(Mathf.FloorToInt(item2.x / 64f), Mathf.FloorToInt(item2.z / 64f)); if (hashSet.Add(item)) { list.Add(item2); if (list.Count >= 10) { break; } } } return list; } } [HarmonyPatch(typeof(ZNetView), "Awake")] public static class ZoneLoadRestorationPatch { [HarmonyPostfix] private static void Postfix(ZNetView __instance) { ZDO zDO = __instance.GetZDO(); if (zDO != null && zDO.GetPrefab() != RecordPrefabFactory.RecordPrefabHash && !NativeNpcStripper.IsPlayerOwned(((Component)__instance).gameObject) && (!string.IsNullOrEmpty(zDO.GetString("vv_record_id", "")) || !string.IsNullOrEmpty(zDO.GetString("vv_villager_id", ""))) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { VillagerRestoration.Restore(((Component)__instance).gameObject, zDO); } } } } namespace ValheimVillages.Items { [Serializable] public class ItemDefinition { public string name = ""; public string source = ""; public string basePrefab = ""; public string displayName = ""; public string description = ""; public int maxStackSize = 1; public float weight = 1f; public int variants; public string itemType = ""; public string biome = ""; public string stationType = ""; } public static class ItemFactory { private static readonly List _prefabs = new List(); private static List _definitions; private static readonly (string station, string key, string displayName, string stationType)[] PhysicalStations = new(string, string, string, string)[5] { ("$piece_workbench", "workbench", "Workbench", "Workbench"), ("$piece_forge", "forge", "Forge", "Forge"), ("$piece_cauldron", "cauldron", "Cauldron", "Cauldron"), ("$piece_artisanstation", "artisan", "Artisan Table", "ArtisanTable"), ("$piece_stonecutter", "stonecutter", "Stonecutter", "Stonecutter") }; public static readonly (int biomeEnum, string key, string biomeId, string displayName, string inkColor)[] FragmentBiomes = new(int, string, string, string, string)[7] { (1, "meadows", "Meadows", "Meadows", "green"), (8, "blackforest", "BlackForest", "Black Forest", "dark blue"), (2, "swamp", "Swamp", "Swamp", "sickly brown"), (4, "mountains", "Mountain", "Mountains", "blue"), (16, "plains", "Plains", "Plains", "golden"), (512, "mistlands", "Mistlands", "Mistlands", "purple"), (32, "ashlands", "Ashlands", "Ashlands", "crimson") }; public static void RegisterAll(ObjectDB objectDB) { if (objectDB?.m_items == null || objectDB.m_items.Count == 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"ObjectDB not ready"); } return; } foreach (ItemDefinition definition in GetDefinitions()) { CreatePrefabIfNeeded(objectDB, definition); } int num = _prefabs.RemoveAll((GameObject p) => (Object)(object)p == (Object)null) + objectDB.m_items.RemoveAll((GameObject go) => (Object)(object)go == (Object)null); Dictionary privateDictionary = GetPrivateDictionary(objectDB, "m_itemByHash"); if (privateDictionary != null) { List list = new List(); foreach (KeyValuePair item in privateDictionary) { if ((Object)(object)item.Value == (Object)null) { list.Add(item.Key); } } foreach (int item2 in list) { privateDictionary.Remove(item2); } num += list.Count; } foreach (GameObject prefab in _prefabs) { AddToCollection(objectDB.m_items, prefab); AddToHashMap(privateDictionary, prefab); } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"Registered {_prefabs.Count} custom items in ObjectDB (purged {num} dead entries)"); } } public static void RegisterAllInZNetScene(ZNetScene instance) { _prefabs.RemoveAll((GameObject p) => (Object)(object)p == (Object)null); instance.m_prefabs.RemoveAll((GameObject go) => (Object)(object)go == (Object)null); Dictionary privateDictionary = GetPrivateDictionary(instance, "m_namedPrefabs"); if (privateDictionary != null) { List list = new List(); foreach (KeyValuePair item in privateDictionary) { if ((Object)(object)item.Value == (Object)null) { list.Add(item.Key); } } foreach (int item2 in list) { privateDictionary.Remove(item2); } } foreach (GameObject prefab in _prefabs) { AddToCollection(instance.m_prefabs, prefab); AddToHashMap(privateDictionary, prefab); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"Registered {_prefabs.Count} prefabs in ZNetScene"); } } public static List GetDefinitions() { if (_definitions != null) { return _definitions; } _definitions = new List(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); typeof(ItemDefinition).Namespace?.Replace('.', '_'); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (!text.EndsWith(".json") || !text.Contains(".Items.")) { continue; } try { using Stream stream = executingAssembly.GetManifestResourceStream(text); using StreamReader streamReader = new StreamReader(stream); ItemDefinition itemDefinition = JsonUtility.FromJson(streamReader.ReadToEnd()); if (!string.IsNullOrEmpty(itemDefinition?.name) && itemDefinition.source == "clone") { _definitions.Add(itemDefinition); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("Failed to load " + text + ": " + ex.Message)); } } } GenerateRegistryItems(_definitions); return _definitions; } public static Dictionary BuildStationWorkOrderMap() { Dictionary dictionary = new Dictionary(); (string, string, string, string)[] physicalStations = PhysicalStations; for (int i = 0; i < physicalStations.Length; i++) { (string, string, string, string) tuple = physicalStations[i]; string item = tuple.Item1; string item2 = tuple.Item2; dictionary[item] = "vv_workorder_" + item2; } foreach (KeyValuePair definition in VillagerRegistry.Definitions) { if (!string.IsNullOrEmpty(definition.Value.stationName)) { dictionary[definition.Value.stationName] = "vv_workorder_" + definition.Key.ToLower(); } } return dictionary; } private static void GenerateRegistryItems(List definitions) { AddIfMissing(definitions, new ItemDefinition { name = "vv_pawn", source = "clone", basePrefab = "DragonEgg", displayName = "Villager", description = "A villager packaged for transport.", maxStackSize = 1, weight = 10f, itemType = "pawn" }); foreach (KeyValuePair definition in VillagerRegistry.Definitions) { VillagerDef value = definition.Value; string text = value.type.ToLower(); AddIfMissing(definitions, new ItemDefinition { name = "vv_" + text + "_pawn", source = "clone", basePrefab = "DragonEgg", displayName = value.displayName, description = "A " + value.displayName.ToLower() + " villager packaged for transport. " + value.description, maxStackSize = 1, weight = 10f, itemType = "pawn" }); if (!string.IsNullOrEmpty(value.stationName)) { AddIfMissing(definitions, new ItemDefinition { name = "vv_workorder_" + text, source = "clone", basePrefab = "Wood", displayName = value.displayName + " Work Order", description = "A work order scroll for " + value.displayName.ToLower() + " tasks. Right-click to set production quotas.", maxStackSize = 1, weight = 0.3f, itemType = "workorder", stationType = value.type }); } } (string, string, string, string)[] physicalStations = PhysicalStations; for (int i = 0; i < physicalStations.Length; i++) { (string, string, string, string) tuple = physicalStations[i]; string item = tuple.Item2; string item2 = tuple.Item3; string item3 = tuple.Item4; AddIfMissing(definitions, new ItemDefinition { name = "vv_workorder_" + item, source = "clone", basePrefab = "Wood", displayName = item2 + " Work Order", description = "A work order scroll for " + item2.ToLower() + " tasks. Right-click to set production quotas.", maxStackSize = 1, weight = 0.3f, itemType = "workorder", stationType = item3 }); } (int, string, string, string, string)[] fragmentBiomes = FragmentBiomes; for (int i = 0; i < fragmentBiomes.Length; i++) { (int, string, string, string, string) tuple2 = fragmentBiomes[i]; string item4 = tuple2.Item2; string item5 = tuple2.Item3; string item6 = tuple2.Item4; string item7 = tuple2.Item5; AddIfMissing(definitions, new ItemDefinition { name = "vv_fragment_" + item4, source = "clone", basePrefab = "DragonEgg", displayName = item6 + " Ransom Fragment", description = "A torn piece of parchment stained with " + item7 + " ink. The scrawled text hints at a captive held somewhere in the " + item6.ToLower() + ". Combine three to reveal their location.", maxStackSize = 3, weight = 0.1f, itemType = "fragment", biome = item5 }); } } private static void AddIfMissing(List defs, ItemDefinition def) { if (!defs.Exists((ItemDefinition d) => d.name == def.name)) { defs.Add(def); } } public static List GetDefinitionsByType(string itemType) { List list = new List(); foreach (ItemDefinition definition in GetDefinitions()) { if (definition.itemType == itemType) { list.Add(definition); } } return list; } public static ItemDefinition GetDefinition(string name) { foreach (ItemDefinition definition in GetDefinitions()) { if (definition.name == name) { return definition; } } return null; } private static void CreatePrefabIfNeeded(ObjectDB objectDB, ItemDefinition def) { if (_prefabs.Exists((GameObject p) => (Object)(object)p != (Object)null && ((Object)p).name == def.name)) { return; } GameObject itemPrefab = objectDB.GetItemPrefab(def.name); if ((Object)(object)itemPrefab != (Object)null) { ApplyItemDefinition(itemPrefab, def); if (!_prefabs.Contains(itemPrefab)) { _prefabs.Add(itemPrefab); } return; } GameObject itemPrefab2 = objectDB.GetItemPrefab(def.basePrefab); if ((Object)(object)itemPrefab2 == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("Base prefab '" + def.basePrefab + "' not found for item '" + def.name + "'")); } } else { GameObject val = ClonePrefab(itemPrefab2, def.name); ApplyItemDefinition(val, def); _prefabs.Add(val); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("Created custom item: " + def.name)); } } } private static GameObject ClonePrefab(GameObject basePrefab, string newName) { bool activeSelf = basePrefab.activeSelf; basePrefab.SetActive(false); GameObject obj = Object.Instantiate(basePrefab); basePrefab.SetActive(activeSelf); ((Object)obj).name = newName; obj.transform.SetParent(PrefabTemplates.Root, false); obj.SetActive(true); return obj; } private static void ApplyItemDefinition(GameObject prefab, ItemDefinition def) { ItemDrop component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { return; } SharedData val = JsonUtility.FromJson(JsonUtility.ToJson((object)component.m_itemData.m_shared)); val.m_name = def.displayName; val.m_description = def.description; val.m_maxStackSize = def.maxStackSize; val.m_weight = def.weight; val.m_variants = def.variants; if (def.itemType == "workorder" && !string.IsNullOrEmpty(def.stationType)) { Sprite val2 = WorkOrderIconLoader.Load(def.stationType); if ((Object)(object)val2 != (Object)null) { val.m_icons = (Sprite[])(object)new Sprite[1] { val2 }; } Texture2D val3 = WorkOrderIconLoader.LoadTexture(def.stationType); if ((Object)(object)val3 != (Object)null) { ParchmentModel.Apply(prefab, val3); } } component.m_itemData.m_shared = val; component.m_itemData.m_dropPrefab = prefab; } private static Dictionary GetPrivateDictionary(T instance, string fieldName) { return typeof(T).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance) as Dictionary; } private static void AddToCollection(List list, GameObject prefab) { if (!((Object)(object)prefab == (Object)null) && !list.Contains(prefab)) { list.Add(prefab); } } private static void AddToHashMap(Dictionary hashMap, GameObject prefab) { if (hashMap != null && !((Object)(object)prefab == (Object)null)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); hashMap[stableHashCode] = prefab; } } } internal static class ParchmentModel { public static void Apply(GameObject prefab, Texture2D tex) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null || (Object)(object)tex == (Object)null) { return; } MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("ParchmentModel: no MeshRenderer on '" + ((Object)prefab).name + "'")); } return; } Mesh sharedMesh = BuildSheet(); MeshRenderer[] array = componentsInChildren; foreach (MeshRenderer obj in array) { MeshFilter component = ((Component)obj).GetComponent(); if ((Object)(object)component != (Object)null) { component.sharedMesh = sharedMesh; } Material val = new Material(((Renderer)obj).sharedMaterial) { name = "vv_parchment_mat" }; val.mainTexture = (Texture)(object)tex; if (val.HasProperty("_Color")) { val.color = Color.white; } if (val.HasProperty("_BumpMap")) { val.SetTexture("_BumpMap", (Texture)null); } val.DisableKeyword("_NORMALMAP"); val.EnableKeyword("_ALPHATEST_ON"); if (val.HasProperty("_Cutoff")) { val.SetFloat("_Cutoff", 0.5f); } val.SetOverrideTag("RenderType", "TransparentCutout"); val.renderQueue = 2450; ((Renderer)obj).sharedMaterials = (Material[])(object)new Material[1] { val }; } Light[] componentsInChildren2 = prefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Behaviour)componentsInChildren2[i]).enabled = false; } } private static Mesh BuildSheet(float width = 0.3f, float height = 0.4f) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0023: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //IL_005b: 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_006e: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) float num = width / 2f; float num2 = height / 2f; Vector3 up = Vector3.up; Vector3 down = Vector3.down; Mesh val = new Mesh(); ((Object)val).name = "vv_parchment"; val.vertices = (Vector3[])(object)new Vector3[8] { new Vector3(0f - num, 0f, 0f - num2), new Vector3(num, 0f, 0f - num2), new Vector3(num, 0f, num2), new Vector3(0f - num, 0f, num2), new Vector3(0f - num, 0f, 0f - num2), new Vector3(num, 0f, 0f - num2), new Vector3(num, 0f, num2), new Vector3(0f - num, 0f, num2) }; val.uv = (Vector2[])(object)new Vector2[8] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f) }; val.normals = (Vector3[])(object)new Vector3[8] { up, up, up, up, down, down, down, down }; val.triangles = new int[12] { 0, 1, 2, 0, 2, 3, 4, 6, 5, 4, 7, 6 }; val.RecalculateBounds(); return val; } } public static class PieceFactory { public const string RegistryPrefabName = "vv_village_registry"; private const string BaseTable = "piece_table"; private const string CandleSource = "Candle_resin"; private const string FeatherSource = "CelestialFeather"; private const string CurtainSource = "piece_cloth_hanging_door_blue2"; private const string ShelfSource = "dvergrprops_shelf"; private const string StoolSource = "dvergrprops_stool"; private const float TopY = 0.83f; private static GameObject _registryPrefab; public static void RegisterAllInZNetScene(ZNetScene zNetScene) { if ((Object)(object)zNetScene == (Object)null) { return; } EnsureRegistryPrefab(zNetScene); if (!((Object)(object)_registryPrefab == (Object)null)) { if (!zNetScene.m_prefabs.Contains(_registryPrefab)) { zNetScene.m_prefabs.Add(_registryPrefab); } Dictionary privateDictionary = GetPrivateDictionary(zNetScene, "m_namedPrefabs"); if (privateDictionary != null) { privateDictionary[StringExtensionMethods.GetStableHashCode("vv_village_registry")] = _registryPrefab; } AddToHammerTable(_registryPrefab); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[PieceFactory] Registered 'vv_village_registry' in ZNetScene + Hammer table"); } } } private static void EnsureRegistryPrefab(ZNetScene zNetScene) { if ((Object)(object)_registryPrefab != (Object)null) { return; } GameObject prefab = zNetScene.GetPrefab("vv_village_registry"); if ((Object)(object)prefab != (Object)null) { StripGraftedChildren(prefab); ConfigurePiece(prefab); ConfigureInteraction(prefab); GraftProps(prefab, zNetScene); _registryPrefab = prefab; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[PieceFactory] Re-grafted registry prefab after hot reload"); } return; } GameObject prefab2 = zNetScene.GetPrefab("piece_table"); if ((Object)(object)prefab2 == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)"[PieceFactory] Base prefab 'piece_table' not found; cannot build registry"); } return; } GameObject obj = ClonePrefab(prefab2, "vv_village_registry"); ConfigurePiece(obj); ConfigureInteraction(obj); GraftProps(obj, zNetScene); _registryPrefab = obj; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)"[PieceFactory] Built registry prefab from 'piece_table'"); } } private static void ConfigurePiece(GameObject prefab) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown Piece component = prefab.GetComponent(); if (!((Object)(object)component == (Object)null)) { component.m_name = "Village Registry"; component.m_description = "A scribe's desk where villagers are enrolled, revived, and recorded."; component.m_category = (PieceCategory)1; ObjectDB instance = ObjectDB.instance; object obj; if (instance == null) { obj = null; } else { GameObject itemPrefab = instance.GetItemPrefab("Wood"); obj = ((itemPrefab != null) ? itemPrefab.GetComponent() : null); } ItemDrop val = (ItemDrop)obj; ObjectDB instance2 = ObjectDB.instance; object obj2; if (instance2 == null) { obj2 = null; } else { GameObject itemPrefab2 = instance2.GetItemPrefab("Resin"); obj2 = ((itemPrefab2 != null) ? itemPrefab2.GetComponent() : null); } ItemDrop val2 = (ItemDrop)obj2; List list = new List(); if ((Object)(object)val != (Object)null) { list.Add(new Requirement { m_resItem = val, m_amount = 10, m_recover = true }); } if ((Object)(object)val2 != (Object)null) { list.Add(new Requirement { m_resItem = val2, m_amount = 4, m_recover = true }); } if (list.Count > 0) { component.m_resources = list.ToArray(); } } } private static void ConfigureInteraction(GameObject prefab) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown RegistryInteract target = prefab.GetComponent() ?? prefab.AddComponent(); CraftingStation val = prefab.GetComponent(); if ((Object)(object)val != (Object)null && ComponentIndex(prefab, (Component)(object)val) < ComponentIndex(prefab, (Component)(object)target)) { Object.DestroyImmediate((Object)(object)val); val = null; } if ((Object)(object)val == (Object)null) { val = prefab.AddComponent(); val.m_name = "$vv_village_registry"; val.m_discoverRange = 0f; val.m_rangeBuild = 0f; val.m_craftRequireRoof = false; val.m_craftRequireFire = false; val.m_showBasicRecipies = false; val.m_useDistance = 10f; val.m_useAnimation = 0; val.m_areaMarker = null; val.m_inUseObject = null; val.m_haveFireObject = null; val.m_craftItemEffects = new EffectList(); val.m_craftItemDoneEffects = new EffectList(); val.m_repairItemDoneEffects = new EffectList(); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[PieceFactory] Registry interaction ready: RegistryInteract@{ComponentIndex(prefab, (Component)(object)target)}, " + $"CraftingStation@{ComponentIndex(prefab, (Component)(object)val)} (interact must precede station)")); } } public static void ReapplyInteractionToInstance(GameObject instance) { if (!((Object)(object)instance == (Object)null)) { RegistryInteract[] components = instance.GetComponents(); for (int i = 0; i < components.Length; i++) { Object.DestroyImmediate((Object)(object)components[i]); } CraftingStation[] components2 = instance.GetComponents(); for (int i = 0; i < components2.Length; i++) { Object.DestroyImmediate((Object)(object)components2[i]); } ConfigureInteraction(instance); } } private static int ComponentIndex(GameObject prefab, Component target) { Component[] components = prefab.GetComponents(); for (int i = 0; i < components.Length; i++) { if (components[i] == target) { return i; } } return -1; } private static void GraftProps(GameObject prefab, ZNetScene zNetScene) { //IL_0048: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) GameObject prefab2 = zNetScene.GetPrefab("piece_cloth_hanging_door_blue2"); Material mat = BuildPaperMaterial(GetItemChildMaterial("vv_workorder_workbench", "log (1)")); Mesh sheet = BuildSheetMesh(0.28f, 0.38f); (Vector3, float, float)[] array = new(Vector3, float, float)[5] { (new Vector3(-0.3f, 0.835f, 0f), 18f, 1f), (new Vector3(-0.14f, 0.84f, -0.18f), -28f, 0.92f), (new Vector3(-0.4f, 0.844f, 0.16f), 42f, 0.85f), (new Vector3(0.06f, 0.838f, 0.16f), -8f, 1f), (new Vector3(0.2f, 0.84599996f, -0.04f), 62f, 0.8f) }; for (int i = 0; i < array.Length; i++) { AddPaper(prefab, sheet, mat, $"vv_paper_{i}", array[i].Item1, array[i].Item2, array[i].Item3); } GameObject prefab3 = zNetScene.GetPrefab("Candle_resin"); GraftMesh(prefab, prefab3, "full/stack", "vv_candle", new Vector3(0.84f, 0.83f, 0.34f), Vector3.zero, Vector3.one); AddCandleLight(prefab, new Vector3(0.84f, 1.11f, 0.34f)); GraftMesh(prefab, prefab3, "full/stack", "vv_candle2", new Vector3(0.99f, 0.83f, 0.2f), new Vector3(0f, 0f, 14f), new Vector3(1f, 1.6f, 1f)); AddCandleLight(prefab, new Vector3(0.99f, 1.48f, 0.2f)); GameObject prefab4 = zNetScene.GetPrefab("CelestialFeather"); GraftMesh(prefab, prefab4, "attach/default", "vv_feather", new Vector3(0.4f, 0.85999995f, -0.02f), new Vector3(0f, -40f, 0f), Vector3.one * 0.62f); object obj; if (!((Object)(object)prefab2 != (Object)null)) { obj = null; } else { Transform obj2 = prefab2.transform.Find("new"); obj = ((obj2 != null) ? ((Component)obj2).gameObject : null); } GameObject source = (GameObject)obj; GraftMeshGroup(prefab, source, "vv_curtain", new Vector3(-1.18f, 2.05f, 0.61f), new Vector3(0f, -90f, 0f), 0.28f); GameObject prefab5 = zNetScene.GetPrefab("dvergrprops_shelf"); GraftMesh(prefab, prefab5, "new/shelf_high", "vv_shelf", new Vector3(-0.9f, 0.83f, 0.34f), Vector3.zero, new Vector3(0.34f, 0.32f, 0.8f)); GameObject prefab6 = zNetScene.GetPrefab("dvergrprops_stool"); GraftMesh(prefab, prefab6, "new/high", "vv_stool", new Vector3(0f, 0f, -0.73f), Vector3.zero, Vector3.one); } private static Material GetChildMaterial(GameObject source, string childPath) { Transform val = (((Object)(object)source != (Object)null) ? source.transform.Find(childPath) : null); MeshRenderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : null); if (!((Object)(object)val2 != (Object)null)) { return null; } return ((Renderer)val2).sharedMaterial; } private static Material GetItemChildMaterial(string itemName, string childPath) { ObjectDB instance = ObjectDB.instance; return GetChildMaterial((instance != null) ? instance.GetItemPrefab(itemName) : null, childPath); } private static Material BuildPaperMaterial(Material baseMat) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0094: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); ((Color)(ref val))..ctor(0.88f, 0.82f, 0.67f); Shader val2 = Shader.Find("Unlit/Texture") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default"); Material val3 = (((Object)(object)val2 != (Object)null) ? new Material(val2) : (((Object)(object)baseMat != (Object)null) ? new Material(baseMat) : new Material(Shader.Find("Standard")))); ((Object)val3).name = "vv_paper_mat"; val3.mainTexture = (Texture)(object)BuildSolidTexture(val); if (val3.HasProperty("_Color")) { val3.color = val; } return val3; } private static void AddPaper(GameObject parent, Mesh sheet, Material mat, string name, Vector3 localPos, float yaw, float scale) { //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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0037: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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) GameObject val = new GameObject(name); val.transform.SetParent(parent.transform, false); val.transform.localPosition = localPos; val.transform.localRotation = Quaternion.Euler(0f, yaw, 0f); val.transform.localScale = Vector3.one * scale; val.AddComponent().sharedMesh = sheet; ((Renderer)val.AddComponent()).sharedMaterial = mat; } private static Texture2D BuildSolidTexture(Color c) { //IL_0002: 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_0013: Expected O, but got Unknown //IL_001c: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0035: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(2, 2) { name = "vv_solid_tex" }; val.SetPixels((Color[])(object)new Color[4] { c, c, c, c }); val.Apply(); return val; } private static Mesh BuildSheetMesh(float width, float height) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //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_0047: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) float num = width / 2f; float num2 = height / 2f; Mesh val = new Mesh(); ((Object)val).name = "vv_paper_sheet"; val.vertices = (Vector3[])(object)new Vector3[8] { new Vector3(0f - num, 0f, 0f - num2), new Vector3(num, 0f, 0f - num2), new Vector3(num, 0f, num2), new Vector3(0f - num, 0f, num2), new Vector3(0f - num, 0f, 0f - num2), new Vector3(num, 0f, 0f - num2), new Vector3(num, 0f, num2), new Vector3(0f - num, 0f, num2) }; val.uv = (Vector2[])(object)new Vector2[8] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f) }; val.normals = (Vector3[])(object)new Vector3[8] { Vector3.up, Vector3.up, Vector3.up, Vector3.up, Vector3.down, Vector3.down, Vector3.down, Vector3.down }; val.triangles = new int[12] { 0, 1, 2, 0, 2, 3, 4, 6, 5, 4, 7, 6 }; return val; } private static void GraftMesh(GameObject parent, GameObject source, string childPath, string name, Vector3 localPos, Vector3 localEuler, Vector3 scale) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[PieceFactory] Graft '" + name + "' skipped: source prefab missing")); } return; } Transform val = source.transform.Find(childPath); if ((Object)(object)val == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[PieceFactory] Graft '" + name + "' skipped: child '" + childPath + "' not found on '" + ((Object)source).name + "'")); } return; } MeshFilter component = ((Component)val).GetComponent(); MeshRenderer component2 = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[PieceFactory] Graft '" + name + "' skipped: no MeshFilter/MeshRenderer at '" + childPath + "'")); } } else { GameObject val2 = new GameObject(name); val2.transform.SetParent(parent.transform, false); val2.transform.localPosition = localPos; val2.transform.localRotation = Quaternion.Euler(localEuler); val2.transform.localScale = scale; val2.AddComponent().sharedMesh = component.sharedMesh; ((Renderer)val2.AddComponent()).sharedMaterials = ((Renderer)component2).sharedMaterials; } } private static void GraftMeshGroup(GameObject parent, GameObject source, string name, Vector3 localPos, Vector3 localEuler, float scale) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0048: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[PieceFactory] Graft group '" + name + "' skipped: source prefab missing")); } return; } GameObject val = new GameObject(name); val.transform.SetParent(parent.transform, false); val.transform.localPosition = localPos; val.transform.localRotation = Quaternion.Euler(localEuler); val.transform.localScale = Vector3.one * scale; int num = 0; MeshFilter[] componentsInChildren = source.GetComponentsInChildren(true); foreach (MeshFilter val2 in componentsInChildren) { MeshRenderer component = ((Component)val2).GetComponent(); if (!((Object)(object)component == (Object)null)) { GameObject val3 = new GameObject(((Object)val2).name); val3.transform.SetParent(val.transform, false); val3.transform.localPosition = ((Component)val2).transform.localPosition; val3.transform.localRotation = ((Component)val2).transform.localRotation; val3.transform.localScale = ((Component)val2).transform.localScale; val3.AddComponent().sharedMesh = val2.sharedMesh; ((Renderer)val3.AddComponent()).sharedMaterials = ((Renderer)component).sharedMaterials; num++; } } if (num == 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[PieceFactory] Graft group '" + name + "': no meshes copied from '" + ((Object)source).name + "'")); } } } private static void AddCandleLight(GameObject parent, Vector3 localPos) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("vv_candle_light"); val.transform.SetParent(parent.transform, false); val.transform.localPosition = localPos; Light obj = val.AddComponent(); obj.type = (LightType)2; obj.color = new Color(1f, 0.72f, 0.36f); obj.range = 3.5f; obj.intensity = 1.3f; obj.shadows = (LightShadows)0; } private static void AddToHammerTable(GameObject piece) { ObjectDB instance = ObjectDB.instance; object obj; if (instance == null) { obj = null; } else { GameObject itemPrefab = instance.GetItemPrefab("Hammer"); obj = ((itemPrefab != null) ? itemPrefab.GetComponent() : null); } PieceTable val = ((ItemDrop)(obj?)).m_itemData?.m_shared?.m_buildPieces; if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[PieceFactory] Hammer build PieceTable not available; piece not added to build menu"); } } else if (!val.m_pieces.Contains(piece)) { val.m_pieces.Add(piece); } } private static void StripGraftedChildren(GameObject prefab) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown List list = new List(); foreach (Transform item in prefab.transform) { Transform val = item; if (((Object)val).name.StartsWith("vv_")) { list.Add(val); } } foreach (Transform item2 in list) { Object.DestroyImmediate((Object)(object)((Component)item2).gameObject); } } private static GameObject ClonePrefab(GameObject basePrefab, string newName) { bool activeSelf = basePrefab.activeSelf; basePrefab.SetActive(false); GameObject obj = Object.Instantiate(basePrefab); basePrefab.SetActive(activeSelf); ((Object)obj).name = newName; obj.transform.SetParent(PrefabTemplates.Root, false); obj.SetActive(true); return obj; } private static Dictionary GetPrivateDictionary(T instance, string fieldName) { return typeof(T).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance) as Dictionary; } } internal static class PrefabTemplates { private static GameObject s_root; public static Transform Root { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)s_root == (Object)null) { s_root = new GameObject("vv_prefab_templates"); s_root.SetActive(false); Object.DontDestroyOnLoad((Object)(object)s_root); } return s_root.transform; } } } } namespace ValheimVillages.Items.WorkOrders { [HarmonyPatch] public static class CraftingStationPatch { private enum CraftFocus { List, Craft, Order } private const string WorkOrderTooltipText = "Orders placed in a chest will be fulfilled by nearby villagers."; private static GameObject _workOrderButton; private static bool _buttonCreated; private static CraftFocus s_focus = CraftFocus.List; private static GameObject s_craftFrame; private static GameObject s_orderFrame; private static GameObject s_listFrame; private static bool s_framesCreated; private static Vector2 _cleanCraftSizeDelta; private static bool _cleanSizeDeltaSaved; private static Dictionary s_stationWorkOrderMap; private static readonly Color FocusFrameColor = new Color(1f, 0.78f, 0.28f, 0.95f); private const float FocusFrameThickness = 3f; private static bool _orderReplacesCraft; private static Dictionary StationWorkOrderMap => s_stationWorkOrderMap ?? (s_stationWorkOrderMap = ItemFactory.BuildStationWorkOrderMap()); [RegisterCleanup] public static void Clear() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) _workOrderButton = null; _buttonCreated = false; _cleanSizeDeltaSaved = false; _cleanCraftSizeDelta = Vector2.zero; s_focus = CraftFocus.List; s_craftFrame = null; s_orderFrame = null; s_listFrame = null; s_framesCreated = false; } public static void HideWorkOrderButton() { if ((Object)(object)_workOrderButton != (Object)null) { _workOrderButton.SetActive(false); } } private static bool IsVirtualStation(string stationName) { return stationName?.StartsWith("$vv_") ?? false; } [HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")] [HarmonyPostfix] public static void UpdateCraftingPanelPostfix(InventoryGui __instance) { RepairCraftButtonIfCorrupted(__instance); EnsureButtonCreated(__instance); EnsureFocusFrames(__instance); UpdateButtonVisibility(__instance); ForceRecipeListFullColorAtVillagerStation(__instance); } private static void EnsureFocusFrames(InventoryGui gui) { if (!s_framesCreated && !((Object)(object)gui.m_craftButton == (Object)null) && !((Object)(object)_workOrderButton == (Object)null)) { s_framesCreated = true; s_craftFrame = CreateFocusFrame(((Component)gui.m_craftButton).transform); s_orderFrame = CreateFocusFrame(_workOrderButton.transform); BringGlyphToFront(((Component)gui.m_craftButton).gameObject); BringGlyphToFront(_workOrderButton); Transform val = (((Object)(object)gui.m_recipeListRoot != (Object)null) ? ((Transform)gui.m_recipeListRoot).parent : null); if ((Object)(object)val != (Object)null) { s_listFrame = CreateFocusFrame(val); } } } private static void BringGlyphToFront(GameObject buttonGO) { GameObject val = buttonGO.GetComponent()?.m_hint; if ((Object)(object)val != (Object)null) { val.transform.SetAsLastSibling(); } } private static GameObject CreateFocusFrame(Transform parent) { //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_002c: 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_0042: 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_006e: 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_0088: 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) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown GameObject val = new GameObject("VV_FocusFrame", new Type[1] { typeof(RectTransform) }); RectTransform component = val.GetComponent(); ((Transform)component).SetParent(parent, false); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; ((Transform)component).SetAsLastSibling(); float num = 3f; AddFrameEdge((Transform)(object)component, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, num)); AddFrameEdge((Transform)(object)component, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0f, num)); AddFrameEdge((Transform)(object)component, new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(num, 0f)); AddFrameEdge((Transform)(object)component, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(num, 0f)); val.SetActive(false); return val; } private static void AddFrameEdge(Transform parent, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta) { //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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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) //IL_005c: 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_0072: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Edge", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform component = val.GetComponent(); ((Transform)component).SetParent(parent, false); component.anchorMin = anchorMin; component.anchorMax = anchorMax; component.pivot = new Vector2(0.5f, 0.5f); component.sizeDelta = sizeDelta; component.anchoredPosition = Vector2.zero; Image component2 = val.GetComponent(); ((Graphic)component2).color = FocusFrameColor; ((Graphic)component2).raycastTarget = false; } [HarmonyPatch(typeof(InventoryGui), "Update")] [HarmonyPostfix] public static void UpdateFocusNavPostfix(InventoryGui __instance) { if (!FocusNavActive(__instance)) { if (!((Object)(object)_workOrderButton != (Object)null) || !_workOrderButton.activeSelf) { s_focus = CraftFocus.List; } RestoreButtons(__instance); SetFrameActive(s_craftFrame, active: false); SetFrameActive(s_orderFrame, active: false); SetFrameActive(s_listFrame, active: false); } else { HandleFocusInput(((Selectable)__instance.m_craftButton).interactable); ApplyFocusGating(__instance); SetFrameActive(s_craftFrame, s_focus == CraftFocus.Craft); SetFrameActive(s_orderFrame, s_focus == CraftFocus.Order); SetFrameActive(s_listFrame, s_focus == CraftFocus.List); } } private static void RestoreButtons(InventoryGui gui) { Button val = (((Object)(object)_workOrderButton != (Object)null) ? _workOrderButton.GetComponent