Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PortalAtlas v1.2.5
PortalAtlas.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PortalAtlas")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.5.0")] [assembly: AssemblyInformationalVersion("1.2.5+79c8b42c97fb56ab3bdaec5a60f8e6d41d595556")] [assembly: AssemblyProduct("PortalAtlas")] [assembly: AssemblyTitle("PortalAtlas")] [assembly: AssemblyVersion("1.2.5.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PortalAtlas { internal static class KnownPortalCache { [HarmonyPatch(typeof(TeleportWorld), "Interact")] private static class TeleportWorld_Interact_Patch { private static void Postfix(TeleportWorld __instance) { RecordTeleportWorld(__instance); } } [HarmonyPatch(typeof(TeleportWorld), "GetHoverText")] private static class TeleportWorld_GetHoverText_Patch { private static void Postfix(TeleportWorld __instance) { RecordTeleportWorld(__instance); } } private const float ApproachPollNearSeconds = 1.5f; private const float ApproachPollFarSeconds = 3.5f; private const float SaveDebounceSeconds = 4f; private const float MoveThresholdMeters = 1.25f; private static readonly Dictionary<string, KnownPortalEntry> Entries = new Dictionary<string, KnownPortalEntry>(StringComparer.OrdinalIgnoreCase); private static string _worldId = string.Empty; private static string _characterId = string.Empty; private static float _nextPoll; private static float _earliestSaveTime; private static bool _dirty; private static Vector3 _lastScanPlayerPos; private static bool _hasLastScanPos; private static int _lastNearbyCount; private static float ApproachRange { get { if (PortalAtlasPlugin.ApproachRangeMeters == null) { return 8f; } return Mathf.Clamp(PortalAtlasPlugin.ApproachRangeMeters.Value, 1f, 50f); } } internal static IReadOnlyCollection<KnownPortalEntry> All => Entries.Values; internal static void Tick() { //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_00c5: 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_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) if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return; } float unscaledTime = Time.unscaledTime; if (_dirty && unscaledTime >= _earliestSaveTime) { Save(); } if (unscaledTime < _nextPoll) { return; } float num = ((_lastNearbyCount > 0) ? 1.5f : 3.5f); _nextPoll = unscaledTime + num; Vector3 position = ((Component)Player.m_localPlayer).transform.position; if (_hasLastScanPos && _lastNearbyCount == 0) { float num2 = position.x - _lastScanPlayerPos.x; float num3 = position.z - _lastScanPlayerPos.z; if (num2 * num2 + num3 * num3 < 1.5625f) { _nextPoll = unscaledTime + 3.5f; return; } } EnsureLoaded(); ScanNearby(); _lastScanPlayerPos = position; _hasLastScanPos = true; if (_dirty && _earliestSaveTime <= 0f) { _earliestSaveTime = unscaledTime + 4f; } } internal static void FlushIfDirty() { if (_dirty) { Save(); } } internal static void EnsureLoaded() { string worldId = GetWorldId(); string characterId = GetCharacterId(); if (string.Equals(worldId, _worldId, StringComparison.Ordinal) && string.Equals(characterId, _characterId, StringComparison.Ordinal) && !string.IsNullOrEmpty(_worldId)) { return; } _worldId = worldId; _characterId = characterId; Entries.Clear(); _dirty = false; string text = PortalPaths.JournalPath(_worldId, _characterId); if (!File.Exists(text)) { return; } try { KnownPortalFile knownPortalFile = SimpleJson.Deserialize(File.ReadAllText(text, Encoding.UTF8)); if (knownPortalFile?.Portals == null) { return; } foreach (KnownPortalEntry portal in knownPortalFile.Portals) { if (portal != null && !string.IsNullOrEmpty(portal.Uid)) { Entries[portal.Uid] = portal; } } int num = CompactDuplicates(); PortalAtlasPlugin.ModLogger.LogInfo((object)$"Loaded {Entries.Count} known portal(s) from {text}"); PortalAtlasPlugin.Debug($"Journal load world='{_worldId}' character='{_characterId}' count={Entries.Count} " + $"compacted={num} path={text}"); if (num > 0) { Save(); } } catch (Exception ex) { PortalAtlasPlugin.ModLogger.LogWarning((object)("Failed to load portal journal: " + ex.Message)); } } internal static void Save() { if (string.IsNullOrEmpty(_worldId)) { EnsureLoaded(); } string text = PortalPaths.JournalPath(_worldId, _characterId); try { KnownPortalFile file = new KnownPortalFile { WorldId = _worldId, CharacterId = _characterId, Portals = new List<KnownPortalEntry>(Entries.Values) }; File.WriteAllText(text, SimpleJson.Serialize(file), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); _dirty = false; _earliestSaveTime = 0f; PortalAtlasPlugin.Debug($"Journal save count={Entries.Count} path={text}"); } catch (Exception ex) { PortalAtlasPlugin.ModLogger.LogWarning((object)("Failed to save portal journal: " + ex.Message)); } } internal unsafe static void RecordZdo(ZDO zdo, string prefabHint = null) { //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_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_0136: 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_017a: 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_0060: 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_007c: 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_008b: 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_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || !zdo.IsValid()) { return; } EnsureLoaded(); Vector3 position = zdo.GetPosition(); string text = PortalScan.SafeGetString(zdo, "tag"); ZDOID portalConnectionId = PortalScan.GetPortalConnectionId(zdo); float? targetX = null; float? targetY = null; float? targetZ = null; string text2 = ((object)(*(ZDOID*)(&portalConnectionId))/*cast due to .constrained prefix*/).ToString(); try { if (!((ZDOID)(ref portalConnectionId)).IsNone()) { ZDO zDO = ZDOMan.instance.GetZDO(portalConnectionId); if (zDO != null && zDO.IsValid()) { Vector3 position2 = zDO.GetPosition(); targetX = position2.x; targetY = position2.y; targetZ = position2.z; } } } catch { } string text3 = ((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString(); string text4 = prefabHint ?? string.Empty; if (string.IsNullOrEmpty(text4)) { try { ZNetView val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(zdo) : null); if ((Object)(object)val != (Object)null) { text4 = ((Object)((Component)val).gameObject).name.Replace("(Clone)", string.Empty).Trim(); } } catch { } } if (string.IsNullOrEmpty(text4)) { text4 = ResolvePrefabName(zdo); } int num = MergeAwayNearbyDuplicates(text3, text, position); KnownPortalEntry value; bool flag = !Entries.TryGetValue(text3, out value); KnownPortalEntry knownPortalEntry = new KnownPortalEntry { Uid = text3, Prefab = text4, Tag = text, X = position.x, Y = position.y, Z = position.z, TargetUid = text2, TargetX = targetX, TargetY = targetY, TargetZ = targetZ, LastSeenUnix = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }; if (flag || num > 0 || !EntriesMatch(value, knownPortalEntry)) { Entries[text3] = knownPortalEntry; _dirty = true; if (_earliestSaveTime <= 0f) { _earliestSaveTime = Time.unscaledTime + 4f; } bool flag2 = PortalAtlasPlugin.AutoPin != null && PortalAtlasPlugin.AutoPin.Value; PortalAtlasPlugin.Debug("Record " + (flag ? "new" : "update") + " prefab=" + text4 + " tag='" + text + "' uid=" + text3 + " " + string.Format("pos=({0:0.#},{1:0.#}) link={2} autoPin={3}", position.x, position.z, (!((ZDOID)(ref portalConnectionId)).IsNone()) ? text2 : "none", flag2)); if (flag2) { PortalMapPins.UpsertSavedPin(knownPortalEntry); } } } private static bool EntriesMatch(KnownPortalEntry a, KnownPortalEntry b) { if (a == null || b == null) { return false; } if (!string.Equals(a.Tag ?? string.Empty, b.Tag ?? string.Empty, StringComparison.Ordinal)) { return false; } if (!string.Equals(a.Prefab ?? string.Empty, b.Prefab ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { return false; } if (!string.Equals(a.TargetUid ?? string.Empty, b.TargetUid ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { return false; } if (Mathf.Abs(a.X - b.X) > 0.25f || Mathf.Abs(a.Y - b.Y) > 0.25f || Mathf.Abs(a.Z - b.Z) > 0.25f) { return false; } if (!NullableFloatClose(a.TargetX, b.TargetX, 0.25f) || !NullableFloatClose(a.TargetY, b.TargetY, 0.25f) || !NullableFloatClose(a.TargetZ, b.TargetZ, 0.25f)) { return false; } return true; } private static bool NullableFloatClose(float? a, float? b, float eps) { if (!a.HasValue && !b.HasValue) { return true; } if (!a.HasValue || !b.HasValue) { return false; } return Mathf.Abs(a.Value - b.Value) <= eps; } internal static bool AddFromRow(PortalRow row, bool alsoAutoPin = false) { if (row == null || string.IsNullOrEmpty(row.Uid)) { return false; } EnsureLoaded(); KnownPortalEntry knownPortalEntry = new KnownPortalEntry { Uid = row.Uid, Prefab = (row.Prefab ?? string.Empty), Tag = (row.Tag ?? string.Empty), X = row.X, Y = row.Y, Z = row.Z, TargetUid = (row.TargetUid ?? string.Empty), TargetX = row.TargetX, TargetY = row.TargetY, TargetZ = row.TargetZ, LastSeenUnix = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }; Entries[row.Uid] = knownPortalEntry; _dirty = true; Save(); if (alsoAutoPin || (PortalAtlasPlugin.AutoPin != null && PortalAtlasPlugin.AutoPin.Value)) { PortalMapPins.UpsertSavedPin(knownPortalEntry); } return true; } internal static void RecordTeleportWorld(TeleportWorld portal) { if (!((Object)(object)portal == (Object)null)) { ZNetView val = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)val == (Object)null) { val = ((Component)portal).GetComponentInParent<ZNetView>(); } if ((Object)(object)val == (Object)null || val.GetZDO() == null) { PortalAtlasPlugin.Debug("RecordTeleportWorld skipped — no ZNetView on '" + ((Object)((Component)portal).gameObject).name + "'"); return; } string prefabHint = ((Object)((Component)val).gameObject).name.Replace("(Clone)", string.Empty).Trim(); RecordZdo(val.GetZDO(), prefabHint); } } private static void ScanNearby() { //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_01b9: 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_01cb: 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_01d2: 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_01e0: 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_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_00d1: 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_00df: 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_016c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ZDOMan.instance == null) { return; } Vector3 position = ((Component)localPlayer).transform.position; float approachRange = ApproachRange; float num = approachRange * approachRange; List<ZDO> list = null; try { list = ZDOMan.instance.GetPortalList(); } catch (Exception ex) { PortalAtlasPlugin.Debug("GetPortalList failed: " + ex.Message); } if (list != null && list.Count > 0) { int num2 = 0; bool dirty = _dirty; HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (ZDO item2 in list) { if (item2 == null || !item2.IsValid()) { continue; } string item = ((object)Unsafe.As<ZDOID, ZDOID>(ref item2.m_uid)/*cast due to .constrained prefix*/).ToString(); if (hashSet.Add(item)) { Vector3 position2 = item2.GetPosition(); float num3 = position.x - position2.x; float num4 = position.z - position2.z; if (!(num3 * num3 + num4 * num4 > num)) { num2++; RecordZdo(item2); } } } _lastNearbyCount = num2; if (PortalAtlasPlugin.DebugEnabled && num2 > 0 && _dirty && !dirty) { PortalAtlasPlugin.Debug($"Approach scan via GetPortalList: total={list.Count} nearby={num2} " + $"range={approachRange:0.#}m player=({position.x:0.#},{position.z:0.#})"); } return; } TeleportWorld[] array = Resources.FindObjectsOfTypeAll<TeleportWorld>(); int num5 = 0; bool dirty2 = _dirty; TeleportWorld[] array2 = array; foreach (TeleportWorld val in array2) { if ((Object)(object)val == (Object)null) { continue; } Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { Vector3 portalApproachPoint = GetPortalApproachPoint(val); float num6 = position.x - portalApproachPoint.x; float num7 = position.z - portalApproachPoint.z; if (!(num6 * num6 + num7 * num7 > num)) { num5++; RecordTeleportWorld(val); } } } _lastNearbyCount = num5; if (PortalAtlasPlugin.DebugEnabled && num5 > 0 && _dirty && !dirty2) { PortalAtlasPlugin.Debug($"Approach scan fallback TeleportWorld[]: instances={array.Length} nearby={num5} range={approachRange:0.#}m"); } } private static Vector3 GetPortalApproachPoint(TeleportWorld portal) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) try { FieldInfo field = typeof(TeleportWorld).GetField("m_proximityRoot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value = field.GetValue(portal); Transform val = (Transform)((value is Transform) ? value : null); if ((Object)(object)val != (Object)null) { return val.position; } } } catch { } return ((Component)portal).transform.position; } private static string ResolvePrefabName(ZDO zdo) { if (zdo == null || (Object)(object)ZNetScene.instance == (Object)null) { return string.Empty; } try { int num = 0; FieldInfo field = typeof(ZDO).GetField("m_prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { num = Convert.ToInt32(field.GetValue(zdo), CultureInfo.InvariantCulture); } if (num == 0) { return string.Empty; } string[] array = new string[2] { "portal_wood", "portal_stone" }; foreach (string text in array) { if (!((Object)(object)ZNetScene.instance.GetPrefab(text) == (Object)null) && PortalScan.StableHash(text) == num) { return text; } } } catch { } return string.Empty; } private static int MergeAwayNearbyDuplicates(string keepUid, string tag, Vector3 pos) { //IL_0063: 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) float num = 16f; List<string> list = null; foreach (KeyValuePair<string, KnownPortalEntry> entry in Entries) { if (string.Equals(entry.Key, keepUid, StringComparison.OrdinalIgnoreCase) || !string.Equals(entry.Value.Tag ?? string.Empty, tag ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { continue; } float num2 = entry.Value.X - pos.x; float num3 = entry.Value.Z - pos.z; if (!(num2 * num2 + num3 * num3 > num)) { if (list == null) { list = new List<string>(); } list.Add(entry.Key); } } if (list == null) { return 0; } foreach (string item in list) { Entries.Remove(item); PortalAtlasPlugin.Debug("Journal merge: removed duplicate '" + tag + "' uid=" + item + " (keeping " + keepUid + ")"); } return list.Count; } internal static int CompactDuplicates() { float num = 16f; List<KnownPortalEntry> list = new List<KnownPortalEntry>(Entries.Values); list.Sort((KnownPortalEntry a, KnownPortalEntry b) => b.LastSeenUnix.CompareTo(a.LastSeenUnix)); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); List<string> list2 = new List<string>(); foreach (KnownPortalEntry item in list) { if (item == null || string.IsNullOrEmpty(item.Uid)) { continue; } bool flag = false; foreach (string item2 in hashSet) { if (Entries.TryGetValue(item2, out var value) && value != null && string.Equals(value.Tag ?? string.Empty, item.Tag ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { float num2 = value.X - item.X; float num3 = value.Z - item.Z; if (num2 * num2 + num3 * num3 <= num) { flag = true; break; } } } if (flag) { list2.Add(item.Uid); } else { hashSet.Add(item.Uid); } } foreach (string item3 in list2) { if (Entries.TryGetValue(item3, out var value2)) { PortalAtlasPlugin.Debug($"Journal compact: removed '{value2.Tag}' uid={item3} at ({value2.X:0.#},{value2.Z:0.#})"); } Entries.Remove(item3); } if (list2.Count > 0) { _dirty = true; } return list2.Count; } private static string GetWorldId() { try { if ((Object)(object)ZNet.instance != (Object)null) { string worldName = ZNet.instance.GetWorldName(); if (!string.IsNullOrEmpty(worldName)) { return worldName; } } } catch { } return "unknown_world"; } private static string GetCharacterId() { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { string playerName = localPlayer.GetPlayerName(); return localPlayer.GetPlayerID().ToString(CultureInfo.InvariantCulture) + "_" + (playerName ?? "player"); } } catch { } return "unknown_character"; } } internal static class SimpleJson { internal static string Serialize(KnownPortalFile file) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{\"WorldId\":").Append(Q(file.WorldId)); stringBuilder.Append(",\"CharacterId\":").Append(Q(file.CharacterId)); stringBuilder.Append(",\"Portals\":["); bool flag = true; foreach (KnownPortalEntry portal in file.Portals) { if (!flag) { stringBuilder.Append(','); } flag = false; stringBuilder.Append('{'); stringBuilder.Append("\"Prefab\":").Append(Q(portal.Prefab)).Append(','); stringBuilder.Append("\"Tag\":").Append(Q(portal.Tag)).Append(','); stringBuilder.Append("\"Uid\":").Append(Q(portal.Uid)).Append(','); stringBuilder.Append("\"X\":").Append(F(portal.X)).Append(','); stringBuilder.Append("\"Y\":").Append(F(portal.Y)).Append(','); stringBuilder.Append("\"Z\":").Append(F(portal.Z)).Append(','); stringBuilder.Append("\"TargetUid\":").Append(Q(portal.TargetUid)).Append(','); stringBuilder.Append("\"TargetX\":").Append(portal.TargetX.HasValue ? F(portal.TargetX.Value) : "null").Append(','); stringBuilder.Append("\"TargetY\":").Append(portal.TargetY.HasValue ? F(portal.TargetY.Value) : "null").Append(','); stringBuilder.Append("\"TargetZ\":").Append(portal.TargetZ.HasValue ? F(portal.TargetZ.Value) : "null").Append(','); stringBuilder.Append("\"LastSeenUnix\":").Append(portal.LastSeenUnix.ToString(CultureInfo.InvariantCulture)); stringBuilder.Append('}'); } stringBuilder.Append("]}"); return stringBuilder.ToString(); } internal static KnownPortalFile Deserialize(string json) { KnownPortalFile knownPortalFile = new KnownPortalFile { Portals = new List<KnownPortalEntry>() }; if (string.IsNullOrEmpty(json)) { return knownPortalFile; } knownPortalFile.WorldId = ExtractString(json, "WorldId"); knownPortalFile.CharacterId = ExtractString(json, "CharacterId"); int num = json.IndexOf("\"Portals\"", StringComparison.Ordinal); if (num < 0) { return knownPortalFile; } int num2 = json.IndexOf('[', num); int num3 = json.LastIndexOf(']'); if (num2 < 0 || num3 <= num2) { return knownPortalFile; } foreach (string item in SplitObjects(json.Substring(num2 + 1, num3 - num2 - 1))) { KnownPortalEntry knownPortalEntry = new KnownPortalEntry { Prefab = ExtractString(item, "Prefab"), Tag = ExtractString(item, "Tag"), Uid = ExtractString(item, "Uid"), X = ExtractFloat(item, "X"), Y = ExtractFloat(item, "Y"), Z = ExtractFloat(item, "Z"), TargetUid = ExtractString(item, "TargetUid"), TargetX = ExtractNullableFloat(item, "TargetX"), TargetY = ExtractNullableFloat(item, "TargetY"), TargetZ = ExtractNullableFloat(item, "TargetZ"), LastSeenUnix = (long)ExtractFloat(item, "LastSeenUnix") }; if (!string.IsNullOrEmpty(knownPortalEntry.Uid)) { knownPortalFile.Portals.Add(knownPortalEntry); } } return knownPortalFile; } private static IEnumerable<string> SplitObjects(string arrayBody) { List<string> list = new List<string>(); int num = 0; int num2 = -1; for (int i = 0; i < arrayBody.Length; i++) { switch (arrayBody[i]) { case '{': if (num == 0) { num2 = i; } num++; break; case '}': num--; if (num == 0 && num2 >= 0) { list.Add(arrayBody.Substring(num2, i - num2 + 1)); num2 = -1; } break; } } return list; } private static string ExtractString(string json, string key) { string text = "\"" + key + "\""; int num = json.IndexOf(text, StringComparison.Ordinal); if (num < 0) { return string.Empty; } int num2 = json.IndexOf(':', num + text.Length); if (num2 < 0) { return string.Empty; } int num3 = json.IndexOf('"', num2 + 1); if (num3 < 0) { return string.Empty; } int i; for (i = num3 + 1; i < json.Length && (json[i] != '"' || json[i - 1] == '\\'); i++) { } if (i >= json.Length) { return string.Empty; } return json.Substring(num3 + 1, i - num3 - 1).Replace("\\\"", "\""); } private static float ExtractFloat(string json, string key) { return ExtractNullableFloat(json, key).GetValueOrDefault(); } private static float? ExtractNullableFloat(string json, string key) { string text = "\"" + key + "\""; int num = json.IndexOf(text, StringComparison.Ordinal); if (num < 0) { return null; } int num2 = json.IndexOf(':', num + text.Length); if (num2 < 0) { return null; } int i; for (i = num2 + 1; i < json.Length && char.IsWhiteSpace(json[i]); i++) { } if (i + 4 <= json.Length && string.Compare(json, i, "null", 0, 4, StringComparison.OrdinalIgnoreCase) == 0) { return null; } int j; for (j = i; j < json.Length && (char.IsDigit(json[j]) || json[j] == '-' || json[j] == '+' || json[j] == '.' || json[j] == 'e' || json[j] == 'E'); j++) { } if (j <= i) { return null; } if (float.TryParse(json.Substring(i, j - i), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } return null; } private static string Q(string value) { value = value ?? string.Empty; return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; } private static string F(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } } internal static class PortalAccess { internal static bool CanRefreshWorld() { if ((Object)(object)ZNet.instance == (Object)null) { return false; } if (ZNet.instance.IsServer()) { return true; } return ServerDevcommandsAccess.IsAdmin(); } internal static string DescribeRefreshAccess() { if ((Object)(object)ZNet.instance == (Object)null) { return "ZNet missing"; } if (ZNet.instance.IsServer()) { return "host/server (local scan allowed)"; } return $"dedicated client ServerDevcommands.IsAdmin={ServerDevcommandsAccess.IsAdmin()} available={ServerDevcommandsAccess.IsAvailable}"; } internal static bool IsPeerAdmin(long sender) { if ((Object)(object)ZNet.instance == (Object)null) { return false; } if (sender == 0L) { return ZNet.instance.IsServer(); } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null) { return false; } string peerHostName = GetPeerHostName(peer); if (string.IsNullOrEmpty(peerHostName)) { return false; } try { return ZNet.instance.IsAdmin(peerHostName); } catch (Exception ex) { PortalAtlasPlugin.Debug("ZNet.IsAdmin(" + peerHostName + ") failed: " + ex.Message); return false; } } private static string GetPeerHostName(ZNetPeer peer) { try { if (peer.m_socket != null) { return peer.m_socket.GetHostName(); } } catch { } return null; } } [BepInPlugin("sonicdm.valheimportallist", "Portal Atlas", "1.2.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class PortalAtlasPlugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__21_0; public static ConsoleEvent <>9__21_1; internal void <TryRegisterCommands>b__21_0(ConsoleEventArgs args) { Debug($"Command: portallist canRefresh={PortalAccess.CanRefreshWorld()} isServer={(Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()}"); if (!PortalAccess.CanRefreshWorld() && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer())) { args.Context.AddString("Portal Atlas: need Server Devcommands admin (dedicated) or be the world host."); } else if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { PortalDumpResult portalDumpResult = PortalScan.DumpPortals(); args.Context.AddString($"Portal Atlas: wrote {portalDumpResult.Rows.Count} portal(s) to {portalDumpResult.CsvPath}"); } else { args.Context.AddString("Portal Atlas: run portallist on the host, or use Refresh world in the panel."); } } internal void <TryRegisterCommands>b__21_1(ConsoleEventArgs args) { Debug("Command: portals"); PortalMapPins.OpenLargeMap(); PortalPanelUi.Toggle(); } } public const string PluginGuid = "sonicdm.valheimportallist"; public const string PluginName = "Portal Atlas"; public const string PluginVersion = "1.2.5"; internal static ManualLogSource ModLogger; internal static PortalAtlasPlugin Instance; internal static ConfigEntry<bool> AutoPin; internal static ConfigEntry<float> ApproachRangeMeters; internal static ConfigEntry<bool> DebugLogging; private Harmony _harmony; private bool _commandRegistered; private bool _uiEnabled; private bool _subscribedGui; private bool _subscribedSdc; internal static bool DebugEnabled { get { if (DebugLogging != null) { return DebugLogging.Value; } return false; } } private void Awake() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown Instance = this; ModLogger = ((BaseUnityPlugin)this).Logger; PortalScan.BindConfig(((BaseUnityPlugin)this).Config); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "When true, write detailed [DEBUG] lines for all mod systems to BepInEx/LogOutput.log (journal, approach, pins, UI, refresh RPC, access, scans)."); AutoPin = ((BaseUnityPlugin)this).Config.Bind<bool>("Pins", "AutoPinOnApproach", false, "When enabled, approaching or using a portal also creates a saved map pin (DudeWheresMyPortal-style)."); ApproachRangeMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Pins", "ApproachRangeMeters", 8f, new ConfigDescription("How close you must be (meters) for a loaded portal to be recorded in the journal (and auto-pinned if AutoPinOnApproach is on).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>())); _harmony = new Harmony("sonicdm.valheimportallist"); try { _harmony.PatchAll(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"Harmony patch failed."); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } if (GUIManager.IsHeadless()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Portal Atlas 1.2.5 headless: CSV dump + admin Refresh RPC."); Debug("DebugLogging enabled."); return; } _uiEnabled = true; GUIManager.OnCustomGUIAvailable += OnCustomGuiAvailable; _subscribedGui = true; ServerDevcommandsAccess.Subscribe(OnAdminStatusChanged); _subscribedSdc = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Portal Atlas 1.2.5 loaded."); Debug("DebugLogging enabled."); } internal static void Debug(string message) { if (DebugEnabled && ModLogger != null) { ModLogger.LogInfo((object)("[DEBUG] " + message)); } } private void Update() { PortalRpc.TickRegister(); PortalScan.TickHostAutoDump(); if (GUIManager.IsHeadless()) { return; } if (!_commandRegistered) { TryRegisterCommands(); } if (_uiEnabled) { KnownPortalCache.Tick(); if (PortalMapPins.HasPendingAutoPins) { PortalMapPins.TickPendingAutoPins(); } PortalPanelUi.Tick(); } } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } if (_subscribedGui) { GUIManager.OnCustomGUIAvailable -= OnCustomGuiAvailable; _subscribedGui = false; } if (_subscribedSdc) { ServerDevcommandsAccess.Unsubscribe(); _subscribedSdc = false; } if (_uiEnabled) { PortalPanelUi.DestroyUi(); PortalMapPins.ClearOverlay(); } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static void OnCustomGuiAvailable() { PortalPanelUi.OnGuiReady(); } private static void OnAdminStatusChanged() { Debug("OnAdminStatusChanged (" + PortalAccess.DescribeRefreshAccess() + ")"); PortalPanelUi.OnAdminStatusChanged(); } private void TryRegisterCommands() { //IL_0033: 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_0029: Expected O, but got Unknown //IL_006c: 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_0062: Expected O, but got Unknown try { object obj = <>c.<>9__21_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { Debug($"Command: portallist canRefresh={PortalAccess.CanRefreshWorld()} isServer={(Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()}"); if (!PortalAccess.CanRefreshWorld() && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer())) { args.Context.AddString("Portal Atlas: need Server Devcommands admin (dedicated) or be the world host."); } else if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { PortalDumpResult portalDumpResult = PortalScan.DumpPortals(); args.Context.AddString($"Portal Atlas: wrote {portalDumpResult.Rows.Count} portal(s) to {portalDumpResult.CsvPath}"); } else { args.Context.AddString("Portal Atlas: run portallist on the host, or use Refresh world in the panel."); } }; <>c.<>9__21_0 = val; obj = (object)val; } new ConsoleCommand("portallist", "Export every portal to CSV under BepInEx/cache/PortalAtlas (host, or dedicated admin via Server Devcommands)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, true); object obj2 = <>c.<>9__21_1; if (obj2 == null) { ConsoleEvent val2 = delegate { Debug("Command: portals"); PortalMapPins.OpenLargeMap(); PortalPanelUi.Toggle(); }; <>c.<>9__21_1 = val2; obj2 = (object)val2; } new ConsoleCommand("portals", "Toggle the Portal Atlas panel", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered commands: portals, portallist"); _commandRegistered = true; } catch { } } } internal static class PortalMapPins { private const string OwnedMarker = "\u200b"; private static readonly List<object> OverlayPins = new List<object>(); private static readonly List<object> SavedPins = new List<object>(); private static readonly List<KnownPortalEntry> _pendingAutoPins = new List<KnownPortalEntry>(); internal static Color OverlayTint = new Color(1f, 0.55f, 0.1f, 1f); internal static bool HasPendingAutoPins => _pendingAutoPins.Count > 0; internal static void ClearOverlay() { int count = OverlayPins.Count; RemoveTrackedPins(OverlayPins); if (count > 0) { PortalAtlasPlugin.Debug($"ClearOverlay removed {count} temp pin(s)"); } } internal static void ShowOverlay(IEnumerable<PortalRow> rows) { //IL_007f: 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) ClearOverlay(); if (rows == null) { return; } Minimap instance = Minimap.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null) { PortalAtlasPlugin.Debug("ShowOverlay skipped — minimap/player missing"); return; } object portalPinType = GetPortalPinType(); long playerID = localPlayer.GetPlayerID(); int num = 0; int num2 = 0; Vector3 pos = default(Vector3); foreach (PortalRow row in rows) { ((Vector3)(ref pos))..ctor(row.X, row.Y, row.Z); string displayTag = row.DisplayTag; if (HasPermanentPinNamedNear(displayTag, pos, 1.5f)) { num2++; continue; } object obj = AddMinimapPin(instance, pos, portalPinType, ToOwnedName(displayTag), playerID, save: false); if (obj != null) { OverlayPins.Add(obj); num++; } } ForceUpdatePins(instance); RetintOverlay(); PortalAtlasPlugin.Debug($"ShowOverlay placed {num} temp pin(s), skipped {num2} (permanent already there)"); } internal static void RetintOverlay() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) foreach (object overlayPin in OverlayPins) { TryTintPin(overlayPin, OverlayTint); } } internal static void UpsertSavedPin(KnownPortalEntry entry) { //IL_0078: 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_00bf: 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_0096: 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_0114: Unknown result type (might be due to invalid IL or missing references) if (entry == null) { return; } Minimap instance = Minimap.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null) { PortalAtlasPlugin.Debug("Auto-pin deferred — minimap/player missing for tag='" + entry.Tag + "'"); QueuePendingAutoPin(entry); return; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(entry.X, entry.Y, entry.Z); string text = (string.IsNullOrEmpty(entry.Tag) ? "(untagged)" : entry.Tag); if (HasPermanentPinNamedNear(text, val, 1.5f)) { PortalAtlasPlugin.Debug($"Auto-pin skipped — permanent pin '{text}' already near ({val.x:0.#},{val.z:0.#})"); return; } RemoveOwnedNear(val, 1.5f); object portalPinType = GetPortalPinType(); object obj = AddMinimapPin(instance, val, portalPinType, ToOwnedName(text), localPlayer.GetPlayerID(), save: true); if (obj != null) { SavedPins.Add(obj); ForceUpdatePins(instance); PortalAtlasPlugin.Debug($"Auto-pin placed tag='{text}' prefab={entry.Prefab} at ({val.x:0.#},{val.z:0.#})"); } else { PortalAtlasPlugin.Debug("Auto-pin failed — AddPin returned null for tag='" + text + "'"); QueuePendingAutoPin(entry); } } internal static void TickPendingAutoPins() { if (_pendingAutoPins.Count == 0 || (Object)(object)Minimap.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } List<KnownPortalEntry> list = new List<KnownPortalEntry>(_pendingAutoPins); _pendingAutoPins.Clear(); foreach (KnownPortalEntry item in list) { UpsertSavedPin(item); } } internal static bool TryPinPortal(PortalRow row, out string message) { //IL_00f7: 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_01c0: 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) message = "Could not pin."; if (row == null) { return false; } KnownPortalEntry knownPortalEntry = new KnownPortalEntry { Uid = (row.Uid ?? string.Empty), Prefab = (row.Prefab ?? string.Empty), Tag = (row.Tag ?? string.Empty), X = row.X, Y = row.Y, Z = row.Z, TargetUid = (row.TargetUid ?? string.Empty), TargetX = row.TargetX, TargetY = row.TargetY, TargetZ = row.TargetZ, LastSeenUnix = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }; string text = (string.IsNullOrEmpty(knownPortalEntry.Tag) ? "(untagged)" : knownPortalEntry.Tag); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(knownPortalEntry.X, knownPortalEntry.Y, knownPortalEntry.Z); if (HasPermanentPinNamedNear(text, val, 1.5f)) { message = "Already pinned: " + text; return false; } Minimap instance = Minimap.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null) { QueuePendingAutoPin(knownPortalEntry); message = "Pin queued for " + text + " (map not ready yet)."; return true; } RemoveOwnedNear(val, 1.5f); object portalPinType = GetPortalPinType(); object obj = AddMinimapPin(instance, val, portalPinType, ToOwnedName(text), localPlayer.GetPlayerID(), save: true); if (obj == null) { QueuePendingAutoPin(knownPortalEntry); message = "Pin queued for " + text + " (AddPin failed)."; return false; } SavedPins.Add(obj); ForceUpdatePins(instance); message = "Pinned " + text + "."; PortalAtlasPlugin.Debug($"TryPinPortal ok tag='{text}' at ({val.x:0.#},{val.z:0.#})"); return true; } internal static void ClearSavedPins() { int count = SavedPins.Count; RemoveTrackedPins(SavedPins); RemoveAllOwnedSavedPinsFromMap(); PortalAtlasPlugin.Debug($"ClearSavedPins trackedRefs={count} (manual pins untouched)"); } internal static void Ping(Vector3 position) { //IL_0005: 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_0046: Unknown result type (might be due to invalid IL or missing references) OpenLargeMap(); CenterOn(position); try { if ((Object)(object)Chat.instance != (Object)null) { MethodInfo method = typeof(Chat).GetMethod("SendPing", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { method.Invoke(Chat.instance, new object[1] { position }); } } } catch { } PortalAtlasPlugin.Debug($"Ping + center map at ({position.x:0.#},{position.z:0.#})"); } internal static void CenterOn(Vector3 position) { //IL_0054: 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) Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return; } OpenLargeMap(); try { MethodInfo method = typeof(Minimap).GetMethod("ShowPointOnMap", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Vector3) }, null); if (method != null) { method.Invoke(instance, new object[1] { position }); return; } } catch { } try { MethodInfo method2 = typeof(Minimap).GetMethod("CenterMap", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Vector3) }, null); if (method2 != null) { method2.Invoke(instance, new object[1] { position }); } } catch { } } internal static void OpenLargeMap() { Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return; } try { MethodInfo method = typeof(Minimap).GetMethod("SetMapMode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { Type nestedType = typeof(Minimap).GetNestedType("MapMode", BindingFlags.Public | BindingFlags.NonPublic); if (nestedType != null) { object obj = Enum.Parse(nestedType, "Large", ignoreCase: true); method.Invoke(instance, new object[1] { obj }); return; } } } catch { } try { MethodInfo method2 = typeof(Minimap).GetMethod("ShowMap", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method2 != null) { method2.Invoke(instance, null); } } catch { } } internal static bool IsLargeMapOpen() { Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return false; } try { MethodInfo method = typeof(Minimap).GetMethod("IsOpen", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null) { return (bool)method.Invoke(instance, null); } } catch { } try { FieldInfo field = typeof(Minimap).GetField("m_largeRoot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value = field.GetValue(instance); GameObject val = (GameObject)((value is GameObject) ? value : null); return (Object)(object)val != (Object)null && val.activeInHierarchy; } } catch { } return false; } internal static Transform GetMapPanelRoot() { Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return null; } string[] array = new string[2] { "m_mapLarge", "m_largeRoot" }; foreach (string name in array) { FieldInfo field = typeof(Minimap).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { object value = field.GetValue(instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null && (Object)(object)val != (Object)null) { return val.transform; } Transform val2 = (Transform)((value is Transform) ? value : null); if (val2 != null && (Object)(object)val2 != (Object)null) { return val2; } Component val3 = (Component)((value is Component) ? value : null); if (val3 != null && (Object)(object)val3 != (Object)null) { return val3.transform; } } } return GetLargeMapRoot(); } internal static Transform GetLargeMapRoot() { Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return null; } string[] array = new string[4] { "m_mapLarge", "m_largeRoot", "m_mapRoot", "m_largeMap" }; foreach (string name in array) { FieldInfo field = typeof(Minimap).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { object value = field.GetValue(instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null) { return val.transform; } Transform val2 = (Transform)((value is Transform) ? value : null); if (val2 != null) { return val2; } Component val3 = (Component)((value is Component) ? value : null); if (val3 != null) { return val3.transform; } } } return ((Component)instance).transform; } internal static bool TryMapClickToWorld(out Vector3 world) { //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_0047: 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_0066: 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) world = Vector3.zero; Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return false; } try { MethodInfo method = typeof(Minimap).GetMethod("ScreenToWorldPoint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && method.Invoke(instance, new object[1] { Input.mousePosition }) is Vector3 val) { world = val; return true; } } catch { } return false; } private static string ToOwnedName(string displayTag) { return "\u200b" + (displayTag ?? string.Empty); } private static bool IsOwnedPin(object pin) { string pinName = GetPinName(pin); if (!string.IsNullOrEmpty(pinName)) { return pinName.StartsWith("\u200b", StringComparison.Ordinal); } return false; } private static bool HasPermanentPinNamedNear(string displayName, Vector3 pos, float radius) { //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) if (string.IsNullOrEmpty(displayName)) { return false; } foreach (object item in SnapshotMapPins()) { if (item == null || (IsOwnedPin(item) && IsPinSaveFlag(item) == false)) { continue; } string displayPinName = GetDisplayPinName(item); if (!string.IsNullOrEmpty(displayPinName) && string.Equals(displayPinName, displayName, StringComparison.OrdinalIgnoreCase)) { Vector3? pinPos = GetPinPos(item); if (pinPos.HasValue && Vector3.Distance(pinPos.Value, pos) <= radius) { return true; } } } return false; } private static string GetDisplayPinName(object pin) { string pinName = GetPinName(pin); if (string.IsNullOrEmpty(pinName)) { return string.Empty; } if (pinName.StartsWith("\u200b", StringComparison.Ordinal)) { return pinName.Substring("\u200b".Length); } return pinName; } private static void QueuePendingAutoPin(KnownPortalEntry entry) { if (entry == null || string.IsNullOrEmpty(entry.Uid)) { return; } for (int i = 0; i < _pendingAutoPins.Count; i++) { if (string.Equals(_pendingAutoPins[i].Uid, entry.Uid, StringComparison.OrdinalIgnoreCase)) { _pendingAutoPins[i] = entry; return; } } _pendingAutoPins.Add(entry); } private static void RemoveOwnedNear(Vector3 pos, float radius) { //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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) for (int num = SavedPins.Count - 1; num >= 0; num--) { object pin = SavedPins[num]; if (!IsOwnedPin(pin)) { SavedPins.RemoveAt(num); } else { Vector3? pinPos = GetPinPos(pin); if (pinPos.HasValue && Vector3.Distance(pinPos.Value, pos) <= radius) { RemoveOneIfOwned(pin); SavedPins.RemoveAt(num); } } } foreach (object item in SnapshotMapPins()) { if (IsOwnedPin(item)) { Vector3? pinPos2 = GetPinPos(item); if (pinPos2.HasValue && Vector3.Distance(pinPos2.Value, pos) <= radius) { RemoveOneIfOwned(item); } } } } private static void RemoveAllOwnedSavedPinsFromMap() { foreach (object item in SnapshotMapPins()) { if (IsOwnedPin(item) && IsPinSaveFlag(item) != false) { RemoveOneIfOwned(item); } } } private static List<object> SnapshotMapPins() { List<object> list = new List<object>(); Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return list; } try { FieldInfo field = typeof(Minimap).GetField("m_pins", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (((field != null) ? field.GetValue(instance) : null) is IEnumerable enumerable) { foreach (object item in enumerable) { if (item != null) { list.Add(item); } } } } catch { } return list; } private static bool? IsPinSaveFlag(object pin) { if (pin == null) { return null; } FieldInfo field = pin.GetType().GetField("m_save", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null || field.FieldType != typeof(bool)) { return null; } return (bool)field.GetValue(pin); } private static string GetPinName(object pin) { if (pin == null) { return null; } FieldInfo field = pin.GetType().GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } return field.GetValue(pin) as string; } private static Vector3? GetPinPos(object pin) { //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_0056: Unknown result type (might be due to invalid IL or missing references) if (pin == null) { return null; } FieldInfo field = pin.GetType().GetField("m_pos", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } object value = field.GetValue(pin); if (!(value is Vector3)) { return null; } return (Vector3)value; } private static void RemoveTrackedPins(List<object> pins) { for (int num = pins.Count - 1; num >= 0; num--) { RemoveOneIfOwned(pins[num]); pins.RemoveAt(num); } pins.Clear(); } private static void RemoveOneIfOwned(object pin) { if (pin == null || !IsOwnedPin(pin)) { return; } Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return; } try { instance.RemovePin((PinData)((pin is PinData) ? pin : null)); } catch { } } private static void TryTintPin(object pin, Color color) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (pin == null || !IsOwnedPin(pin)) { return; } Type type = pin.GetType(); try { string[] array = new string[4] { "m_icon", "m_iconElement", "m_uiElement", "m_pinIcon" }; foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null) && TintGraphic(field.GetValue(pin), color)) { break; } } } catch { } } private static bool TintGraphic(object value, Color color) { //IL_0010: 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_009a: Unknown result type (might be due to invalid IL or missing references) if (value == null) { return false; } Image val = (Image)((value is Image) ? value : null); if (val != null) { ((Graphic)val).color = color; return true; } Component val2 = (Component)((value is Component) ? value : null); if (val2 != null) { Image[] componentsInChildren = val2.GetComponentsInChildren<Image>(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { Image[] array = componentsInChildren; foreach (Image val3 in array) { if ((Object)(object)val3 != (Object)null) { ((Graphic)val3).color = color; } } return true; } } GameObject val4 = (GameObject)((value is GameObject) ? value : null); if (val4 != null) { Image[] componentsInChildren2 = val4.GetComponentsInChildren<Image>(true); if (componentsInChildren2 != null && componentsInChildren2.Length != 0) { Image[] array = componentsInChildren2; foreach (Image val5 in array) { if ((Object)(object)val5 != (Object)null) { ((Graphic)val5).color = color; } } return true; } } return false; } private static void ForceUpdatePins(Minimap map) { if ((Object)(object)map == (Object)null) { return; } string[] array = new string[2] { "UpdatePins", "UpdateDynamicPins" }; foreach (string name in array) { try { MethodInfo method = typeof(Minimap).GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(method == null)) { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0) { method.Invoke(map, null); break; } if (parameters.Length == 1 && parameters[0].ParameterType == typeof(float)) { method.Invoke(map, new object[1] { 0f }); break; } } } catch { } } } private static object GetPortalPinType() { Type nestedType = typeof(Minimap).GetNestedType("PinType", BindingFlags.Public | BindingFlags.NonPublic); if (nestedType == null || !nestedType.IsEnum) { return 4; } string[] array = new string[2] { "Portal", "Icon4" }; foreach (string value in array) { try { return Enum.Parse(nestedType, value, ignoreCase: true); } catch { } } return Enum.ToObject(nestedType, 4); } private static object AddMinimapPin(Minimap map, Vector3 pos, object pinType, string name, long playerId, bool save) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)map == (Object)null) { return null; } MethodInfo[] methods = typeof(Minimap).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!string.Equals(methodInfo.Name, "AddPin", StringComparison.Ordinal)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length < 5) { continue; } try { object[] array = new object[parameters.Length]; array[0] = pos; array[1] = pinType; array[2] = name ?? string.Empty; array[3] = save; array[4] = false; if (parameters.Length > 5 && (parameters[5].ParameterType == typeof(long) || parameters[5].ParameterType == typeof(int))) { array[5] = Convert.ChangeType(playerId, parameters[5].ParameterType, CultureInfo.InvariantCulture); } for (int j = 0; j < array.Length; j++) { if (array[j] == null) { Type parameterType = parameters[j].ParameterType; array[j] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null); } } return methodInfo.Invoke(map, array); } catch { } } return null; } } internal static class PortalMapZoomGuard { private static float _largeBefore; private static float _smallBefore; private static bool _guard; private static float _suppressUntil; internal static bool HasScrollInput() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Abs(Input.mouseScrollDelta.y) >= 0.01f) { return true; } try { return Mathf.Abs(Input.GetAxis("Mouse ScrollWheel")) >= 0.0001f; } catch { return false; } } internal static bool ShouldSuppressZoom() { if (!PortalPanelUi.IsOpen) { return false; } if (HasScrollInput() && PortalPanelUi.ShouldBlockMapZoom()) { _suppressUntil = Time.unscaledTime + 0.12f; return true; } if (Time.unscaledTime < _suppressUntil) { return PortalPanelUi.ShouldBlockMapZoom(); } return false; } internal static void BeginFrame(Minimap map) { _guard = false; if ((Object)(object)map == (Object)null || !ShouldSuppressZoom()) { return; } _guard = true; _largeBefore = ReadFloat(map, "m_largeZoom", delegate { try { return map.LargeZoom; } catch { return 0f; } }); _smallBefore = ReadFloat(map, "m_smallZoom", delegate { try { return map.SmallZoom; } catch { return 0f; } }); ClearInertia(map); } internal static void EndFrame(Minimap map) { if (!_guard || (Object)(object)map == (Object)null) { return; } WriteFloat(map, "m_largeZoom", _largeBefore, delegate(float v) { try { map.LargeZoom = v; } catch { } }); WriteFloat(map, "m_smallZoom", _smallBefore, delegate(float v) { try { map.SmallZoom = v; } catch { } }); ClearInertia(map); } internal static bool AllowZoomSetter() { return !ShouldSuppressZoom(); } private static void ClearInertia(Minimap map) { WriteFloat(map, "m_zoomInertia", 0f, null); try { FieldInfo field = typeof(Minimap).GetField("m_startedZooming", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(bool)) { field.SetValue(map, false); } } catch { } } private static float ReadFloat(Minimap map, string fieldName, Func<float> fallback) { try { FieldInfo field = typeof(Minimap).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(float)) { return (float)field.GetValue(map); } } catch { } return fallback?.Invoke() ?? 0f; } private static void WriteFloat(Minimap map, string fieldName, float value, Action<float> fallback) { try { FieldInfo field = typeof(Minimap).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(float)) { field.SetValue(map, value); return; } } catch { } fallback?.Invoke(value); } } [HarmonyPatch(typeof(Minimap), "Update")] internal static class Minimap_Update_ZoomGuard { private static void Prefix(Minimap __instance) { PortalMapZoomGuard.BeginFrame(__instance); } private static void Postfix(Minimap __instance) { PortalMapZoomGuard.EndFrame(__instance); } } [HarmonyPatch(typeof(Minimap), "set_LargeZoom")] internal static class Minimap_SetLargeZoom_Block { private static bool Prefix() { return PortalMapZoomGuard.AllowZoomSetter(); } } [HarmonyPatch(typeof(Minimap), "set_SmallZoom")] internal static class Minimap_SetSmallZoom_Block { private static bool Prefix() { return PortalMapZoomGuard.AllowZoomSetter(); } } internal sealed class PortalRow { public string Prefab; public string Tag; public string Uid; public float X; public float Y; public float Z; public string TargetUid; public bool Connected; public float? TargetX; public float? TargetY; public float? TargetZ; public int SameTagCount; public string Relationship; public string Issues; public string DisplayTag { get { if (!string.IsNullOrEmpty(Tag)) { return Tag; } return "(untagged)"; } } public string StatusLabel { get { if (string.Equals(Relationship, "Mutual pair", StringComparison.OrdinalIgnoreCase) || string.Equals(Relationship, "Connected", StringComparison.OrdinalIgnoreCase)) { return "connected"; } if (string.Equals(Relationship, "One-way link", StringComparison.OrdinalIgnoreCase)) { return "one-way"; } if (string.Equals(Relationship, "Tag twin (not linked yet)", StringComparison.OrdinalIgnoreCase)) { return "tag twin"; } if (Connected) { return "connected"; } return "unconnected"; } } public bool HasPartnerPosition { get { if (TargetX.HasValue && TargetY.HasValue && TargetZ.HasValue && !string.IsNullOrEmpty(TargetUid) && !TargetUid.Equals("None", StringComparison.OrdinalIgnoreCase)) { return !TargetUid.Equals("0:0", StringComparison.OrdinalIgnoreCase); } return false; } } } internal sealed class PortalDumpResult { public List<PortalRow> Rows = new List<PortalRow>(); public int PortalPrefabCount; public string CsvPath; public string SummaryCsvPath; public string TextPath; } internal sealed class KnownPortalEntry { public string Prefab; public string Tag; public string Uid; public float X; public float Y; public float Z; public string TargetUid; public float? TargetX; public float? TargetY; public float? TargetZ; public long LastSeenUnix; public PortalRow ToRow() { return new PortalRow { Prefab = (Prefab ?? string.Empty), Tag = (Tag ?? string.Empty), Uid = (Uid ?? string.Empty), X = X, Y = Y, Z = Z, TargetUid = (TargetUid ?? string.Empty), Connected = (!string.IsNullOrEmpty(TargetUid) && !TargetUid.Equals("None", StringComparison.OrdinalIgnoreCase) && !TargetUid.Equals("0:0", StringComparison.OrdinalIgnoreCase) && TargetX.HasValue), TargetX = TargetX, TargetY = TargetY, TargetZ = TargetZ }; } } internal sealed class KnownPortalFile { public string WorldId; public string CharacterId; public List<KnownPortalEntry> Portals = new List<KnownPortalEntry>(); } internal static class PortalPanelUi { [CompilerGenerated] private static class <>O { public static UnityAction <0>__Toggle; public static UnityAction <1>__Hide; public static UnityAction <2>__OnRefreshClicked; public static UnityAction <3>__OnShowKnown; public static UnityAction <4>__OnPinSelected; public static UnityAction <5>__OnPing; public static UnityAction <6>__OnPingExit; public static UnityAction <7>__OnAddToJournal; public static Action<List<PortalRow>> <8>__OnWorldList; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction<string> <>9__52_0; public static UnityAction <>9__52_1; public static UnityAction <>9__52_2; public static UnityAction <>9__52_3; public static UnityAction <>9__52_4; public static UnityAction<bool> <>9__52_5; internal void <EnsurePanel>b__52_0(string _) { RebuildList(); } internal void <EnsurePanel>b__52_1() { _sortByName = true; _sortByMapClick = false; _awaitingMapClick = false; RebuildList(); RefreshChrome(); } internal void <EnsurePanel>b__52_2() { _sortByName = false; _sortByMapClick = false; _mapClickOrigin = null; _awaitingMapClick = false; RebuildList(); RefreshChrome(); } internal void <EnsurePanel>b__52_3() { _sortByName = false; _sortByMapClick = true; _awaitingMapClick = true; SetStatus("Map click — next map click sets sort origin"); RefreshChrome(); } internal void <EnsurePanel>b__52_4() { PortalMapPins.ClearSavedPins(); SetStatus("Cleared this mod's saved portal pins (manual pins untouched)."); } internal void <EnsurePanel>b__52_5(bool v) { if (PortalAtlasPlugin.AutoPin != null) { PortalAtlasPlugin.AutoPin.Value = v; } PortalAtlasPlugin.Debug($"AutoPin toggle → {v}"); } } private const string PanelRootName = "PortalAtlas_Panel"; private const string MapButtonName = "PortalAtlas_MapButton"; private const float PanelWidth = 440f; private const float PanelHeight = 580f; private const float HeaderHeight = 220f; private const float FooterHeight = 150f; private const int UiFontSize = 14; private const int UiLayoutVersion = 5; private static GameObject _panelRoot; private static GameObject _mapButtonRoot; private static Text _statusText; private static InputField _filterInput; private static Transform _listContent; private static ScrollRect _listScroll; private static RectTransform _listScrollRect; private static Text _detailText; private static Button _refreshButton; private static Button _showKnownButton; private static Button _pinButton; private static Button _pingExitButton; private static Button _addJournalButton; private static Toggle _autoPinToggle; private static readonly List<GameObject> _rowObjects = new List<GameObject>(); private static List<PortalRow> _journalRows = new List<PortalRow>(); private static List<PortalRow> _worldRows; private static List<PortalRow> _visible = new List<PortalRow>(); private static PortalRow _selected; private static bool _guiReady; private static bool _panelOpen; private static bool _showingWorld; private static bool _sortByName; private static bool _sortByMapClick; private static Vector3? _mapClickOrigin; private static bool _inputBlocked; private static bool _awaitingRefresh; private static bool _awaitingMapClick; private static Text _sortHintText; private static int _builtLayoutVersion; private static bool _mapWasOpen; private static float _nextRetintTime; private static bool _lastCanRefresh; internal static bool IsOpen => _panelOpen; private static bool FilterFocused { get { if ((Object)(object)_filterInput != (Object)null) { return _filterInput.isFocused; } return false; } } internal static void OnGuiReady() { _guiReady = GUIManager.Instance != null && (Object)(object)GUIManager.CustomGUIFront != (Object)null; EnsureMapButton(); } internal static void OnAdminStatusChanged() { if (_panelOpen) { RefreshChrome(); } } internal static void Tick() { //IL_00fe: 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_012b: Unknown result type (might be due to invalid IL or missing references) if (!_guiReady && GUIManager.Instance != null) { _guiReady = true; } if (!_guiReady || GUIManager.IsHeadless()) { return; } bool flag = PortalMapPins.IsLargeMapOpen(); if (flag != _mapWasOpen) { _mapWasOpen = flag; EnsureMapButton(); if (_panelOpen && !flag) { Hide(); } } else if (flag && ((Object)(object)_mapButtonRoot == (Object)null || !_mapButtonRoot.activeSelf)) { EnsureMapButton(); } SyncBlockInput(); if (_panelOpen) { TryScrollListWithWheel(); bool flag2 = PortalAccess.CanRefreshWorld(); if (flag2 != _lastCanRefresh) { PortalAtlasPlugin.Debug($"Refresh access changed: {flag2} ({PortalAccess.DescribeRefreshAccess()})"); _lastCanRefresh = flag2; RefreshChrome(); } } if (_panelOpen && flag) { if (Time.unscaledTime >= _nextRetintTime) { _nextRetintTime = Time.unscaledTime + 0.5f; PortalMapPins.RetintOverlay(); } if (_awaitingMapClick && Input.GetMouseButtonDown(0) && !IsPointerOverOurPanel() && PortalMapPins.TryMapClickToWorld(out var world)) { _mapClickOrigin = world; _sortByMapClick = true; _sortByName = false; _awaitingMapClick = false; PortalAtlasPlugin.Debug($"UI map-click origin=({world.x:0.#},{world.z:0.#})"); RebuildList(); UpdateOverlay(); RefreshChrome(); } } } internal static void Toggle() { if (_panelOpen) { Hide(); } else { Show(); } } internal static void Show() { if (!GUIManager.IsHeadless()) { PortalAtlasPlugin.Debug("UI Show — journal view (" + PortalAccess.DescribeRefreshAccess() + ")"); EnsurePanel(); _panelOpen = true; _mapWasOpen = PortalMapPins.IsLargeMapOpen(); if ((Object)(object)_panelRoot != (Object)null) { _panelRoot.SetActive(true); } _showingWorld = false; _worldRows = null; ReloadJournal(); RefreshChrome(); RebuildList(); UpdateOverlay(); } } internal static void Hide() { PortalAtlasPlugin.Debug("UI Hide"); _panelOpen = false; _awaitingMapClick = false; if ((Object)(object)_panelRoot != (Object)null) { _panelRoot.SetActive(false); } PortalMapPins.ClearOverlay(); SetBlockInput(block: false); KnownPortalCache.FlushIfDirty(); } internal static void DestroyUi() { Hide(); if ((Object)(object)_panelRoot != (Object)null) { Object.Destroy((Object)(object)_panelRoot); _panelRoot = null; } if ((Object)(object)_mapButtonRoot != (Object)null) { Object.Destroy((Object)(object)_mapButtonRoot); _mapButtonRoot = null; } _rowObjects.Clear(); PortalAtlasPlugin.Debug("UI DestroyUi"); } internal static void OnWorldList(List<PortalRow> rows) { _awaitingRefresh = false; if (rows == null) { PortalAtlasPlugin.Debug("UI OnWorldList failed (null)"); SetStatus("Refresh failed."); return; } PortalAtlasPlugin.Debug($"UI OnWorldList session rows={rows.Count} (journal untouched)"); _worldRows = rows; _showingWorld = true; RefreshChrome(); RebuildList(); UpdateOverlay(); SetStatus($"World list · {rows.Count} portals (not added to journal)"); } private static void EnsureMapButton() { //IL_007b: 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_0099: 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_0155: 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_017b: 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_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_00ee: Expected O, but got Unknown if (GUIManager.IsHeadless() || GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null) { return; } if (!PortalMapPins.IsLargeMapOpen()) { if ((Object)(object)_mapButtonRoot != (Object)null) { _mapButtonRoot.SetActive(false); } return; } Transform val = PortalMapPins.GetMapPanelRoot(); if ((Object)(object)val == (Object)null) { val = GUIManager.CustomGUIFront.transform; } if ((Object)(object)_mapButtonRoot == (Object)null) { GameObject obj = GUIManager.Instance.CreateButton("Portals", val, new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(36f, 36f), 110f, 34f); ((Object)obj).name = "PortalAtlas_MapButton"; _mapButtonRoot = obj; Button component = obj.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { ButtonClickedEvent onClick = component.onClick; object obj2 = <>O.<0>__Toggle; if (obj2 == null) { UnityAction val2 = Toggle; <>O.<0>__Toggle = val2; obj2 = (object)val2; } ((UnityEvent)onClick).AddListener((UnityAction)obj2); } GUIManager.Instance.ApplyButtonStyle(component, 14); } if ((Object)(object)_mapButtonRoot.transform.parent != (Object)(object)val) { _mapButtonRoot.transform.SetParent(val, false); } RectTransform component2 = _mapButtonRoot.GetComponent<RectTransform>(); if ((Object)(object)component2 != (Object)null) { Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 0f); component2.anchorMax = val3; component2.anchorMin = val3; component2.pivot = new Vector2(0f, 0f); component2.anchoredPosition = new Vector2(36f, 36f); component2.sizeDelta = new Vector2(110f, 34f); } _mapButtonRoot.SetActive(true); _mapButtonRoot.transform.SetAsLastSibling(); } private static void EnsurePanel() { //IL_00b8: 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_00d6: 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_0135: 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_0168: 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_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_0206: 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_0220: 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_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Expected O, but got Unknown //IL_0293: 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_02ad: 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_0263: Expected O, but got Unknown //IL_0323: 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_033d: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Expected O, but got Unknown //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Expected O, but got Unknown //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Expected O, but got Unknown //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: 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_0521: Unknown result type (might be due to invalid IL or missing references) //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_0566: Unknown result type (might be due to invalid IL or missing references) //IL_05ac: Unknown result type (might be due to invalid IL or missing references) //IL_05b3: Unknown result type (might be due to invalid IL or missing references) //IL_05c6: Unknown result type (might be due to invalid IL or missing references) //IL_05d9: Unknown result type (might be due to invalid IL or missing references) //IL_05f5: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_044d: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Expected O, but got Unknown //IL_07b8: Unknown result type (might be due to invalid IL or missing references) //IL_07ee: Unknown result type (might be due to invalid IL or missing references) //IL_082f: Unknown result type (might be due to invalid IL or missing references) //IL_0803: Unknown result type (might be due to invalid IL or missing references) //IL_0808: Unknown result type (might be due to invalid IL or missing references) //IL_080e: Expected O, but got Unknown //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_0762: Expected O, but got Unknown //IL_0867: 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_0849: Unknown result type (might be due to invalid IL or missing references) //IL_084f: Expected O, but got Unknown //IL_06dd: Unknown result type (might be due to invalid IL or missing references) //IL_08b2: 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) //IL_0881: Unknown result type (might be due to invalid IL or missing references) //IL_0887: Expected O, but got Unknown //IL_08f3: Unknown result type (might be due to invalid IL or missing references) //IL_08c7: Unknown result type (might be due to invalid IL or missing references) //IL_08cc: Unknown result type (might be due to invalid IL or missing references) //IL_08d2: Expected O, but got Unknown //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_097e: Unknown result type (might be due to invalid IL or missing references) //IL_0990: 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_090c: Unknown result type (might be due to invalid IL or missing references) //IL_0911: Unknown result type (might be due to invalid IL or missing references) //IL_0917: Expected O, but got Unknown //IL_0a23: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_panelRoot != (Object)null && _builtLayoutVersion != 5) { Object.Destroy((Object)(object)_panelRoot); _panelRoot = null; _listContent = null; _listScroll = null; _listScrollRect = null; _statusText = null; _filterInput = null; _detailText = null; _sortHintText = null; _refreshButton = null; _showKnownButton = null; _pinButton = null; _pingExitButton = null; _addJournalButton = null; _autoPinToggle = null; _rowObjects.Clear(); } if ((Object)(object)_panelRoot != (Object)null || GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null) { return; } GameObject val = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(-220f, 20f), 440f, 580f, true); ((Object)val).name = "PortalAtlas_Panel"; _panelRoot = val; float num = 262f; Text obj = CreateLabel(val.transform, "Portals", new Vector2(0f, num), 200f, 28f, bold: true); obj.alignment = (TextAnchor)4; ((Graphic)obj).color = GUIManager.Instance.ValheimOrange; ButtonClickedEvent onClick = GUIManager.Instance.CreateButton("X", val.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(192f, num), 32f, 28f).GetComponent<Button>().onClick; object obj2 = <>O.<1>__Hide; if (obj2 == null) { UnityAction val2 = Hide; <>O.<1>__Hide = val2; obj2 = (object)val2; } ((UnityEvent)onClick).AddListener((UnityAction)obj2); num -= 28f; _statusText = CreateLabel(val.transform, "Known portals", new Vector2(0f, num), 400f, 22f, bold: false); num -= 32f; _refreshButton = GUIManager.Instance.CreateButton("Refresh world", val.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(-70f, num), 130f, 28f).GetComponent<Button>(); ButtonClickedEvent onClick2 = _refreshButton.onClick; object obj3 = <>O.<2>__OnRefreshClicked; if (obj3 == null) { UnityAction val3 = OnRefreshClicked; <>O.<2>__OnRefreshClicked = val3; obj3 = (object)val3; } ((UnityEvent)onClick2).AddListener((UnityAction)obj3); GUIManager.Instance.ApplyButtonStyle(_refreshButton, 14); _showKnownButton = GUIManager.Instance.CreateButton("Show known", val.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(70f, num), 120f, 28f).GetComponent<Button>(); ButtonClickedEvent onClick3 = _showKnownButton.onClick; object obj4 = <>O.<3>__OnShowKnown; if (obj4 == null) { UnityAction val4 = OnShowKnown; <>O.<3>__OnShowKnown = val4; obj4 = (object)val4; } ((UnityEvent)onClick3).AddListener((UnityAction)obj4); GUIManager.Instance.ApplyButtonStyle(_showKnownButton, 14); num -= 34f; _filterInput = GUIManager.Instance.CreateInputField(val.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, num), (ContentType)0, "Filter tags", 14, 392f, 28f).GetComponent<InputField>(); GUIManager.Instance.ApplyInputFieldStyle(_filterInput, 14); ((UnityEvent<string>)(object)_filterInput.onValueChanged).AddListener((UnityAction<string>)delegate { RebuildList(); }); num -= 30f; Transform transform = val.transform; Vector2 pos = new Vector2(-120f, num); object obj5 = <>c.<>9__52_1; if (obj5 == null) { UnityAction val5 = delegate { _sortByName = true; _sortByMapClick = false; _awaitingMapClick = false; RebuildList(); RefreshChrome(); }; <>c.<>9__52_1 = val5; obj5 = (object)val5; } CreateSortButton(transform, "Name", pos, (UnityAction)obj5); Transform transform2 = val.transform; Vector2 pos2 = new Vector2(0f, num); object obj6 = <>c.<>9__52_2; if (obj6 == null) { UnityAction val6 = delegate { _sortByName = false; _sortByMapClick = false; _mapClickOrigin = null; _awaitingMapClick = false; RebuildList(); RefreshChrome(); }; <>c.<>9__52_2 = val6; obj6 = (object)val6; } CreateSortButton(transform2, "To me", pos2, (UnityAction)obj6); Transform transform3 = val.transform; Vector2 pos3 = new Vector2(120f, num); object obj7 = <>c.<>9__52_3; if (obj7 == null) { UnityAction val7 = delegate { _sortByName = false; _sortByMapClick = true; _awaitingMapClick = true; SetStatus("Map click — next map click sets sort origin"); RefreshChrome(); }; <>c.<>9__52_3 = val7; obj7 = (object)val7; } CreateSortButton(transform3, "Map click", pos3, (UnityAction)obj7); num -= 22f; _sortHintText = CreateLabel(val.transform, "Sort: to me", new Vector2(0f, num), 400f, 20f, bold: false); _sortHintText.fontSize = 12; ((Graphic)_sortHintText).color = new Color(0.85f, 0.8f, 0.7f, 1f); float num2 = -140f; float num3 = 70f - num2; float num4 = (70f + num2) * 0.5f; ColorBlock defaultColorBlock = ColorBlock.defaultColorBlock; ((ColorBlock)(ref defaultColorBlock)).normalColor = new Color(0.6f, 0.35f, 0.12f, 1f); ((ColorBlock)(ref defaultColorBlock)).highlightedColor = GUIManager.Instance.ValheimOrange; ((ColorBlock)(ref defaultColorBlock)).pressedColor = new Color(0.9f, 0.55f, 0.15f, 1f); ((ColorBlock)(ref defaultColorBlock)).selectedColor = ((ColorBlock)(ref defaultColorBlock)).highlightedColor; GameObject val8 = GUIManager.Instance.CreateScrollView(val.transform, false, true, 10f, 3f, defaultColorBlock, new Color(0f, 0f, 0f, 0.45f), 400f, Mathf.Max(120f, num3)); ((Object)val8).name = "PortalListScroll"; RectTransform component = val8.GetComponent<RectTransform>(); Vector2 val9 = default(Vector2); ((Vector2)(ref val9))..ctor(0.5f, 0.5f); component.anchorMax = val9; component.anchorMin = val9; component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = new Vector2(0f, num4); component.sizeDelta = new Vector2(400f, Mathf.Max(120f, num3)); val8.transform.SetSiblingIndex(2); ScrollRect val10 = val8.GetComponentInChildren<ScrollRect>(true); if ((Object)(object)val10 == (Object)null) { val10 = val8.GetComponent<ScrollRect>(); } if ((Object)(object)val10 != (Object)null) { val10.horizontal = false; val10.vertical = true; val10.movementType = (MovementType)2; val10.scrollSensitivity = 40f; _listScroll = val10; _listContent = (Transform)(object)val10.content; _listScrollRect = ((Component)val10).GetComponent<RectTransform>(); if ((Object)(object)_listScrollRect == (Object)null) { _listScrollRect = component; } if ((Object)(object)val10.viewport != (Object)null) { Image val11 = ((Component)val10.viewport).GetComponent<Image>(); if ((Object)(object)val11 == (Object)null) { val11 = ((Component)val10.viewport).gameObject.AddComponent<Image>(); } ((Graphic)val11).color = new Color(0f, 0f, 0f, 0.01f); ((Graphic)val11).raycastTarget = true; } } if ((Object)(object)_listContent != (Object)null) { VerticalLayoutGroup val12 = ((Component)_listContent).GetComponent<VerticalLayoutGroup>(); if ((Object)(object)val12 == (Object)null) { val12 = ((Component)_listContent).gameObject.AddComponent<VerticalLayoutGroup>(); } ((HorizontalOrVerticalLayoutGroup)val12).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val12).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val12).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val12).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val12).spacing = 2f; ((LayoutGroup)val12).padding = new RectOffset(4, 4, 4, 4); ContentSizeFitter val13 = ((Component)_listContent).GetComponent<ContentSizeFitter>(); if ((Object)(object)val13 == (Object)null) { val13 = ((Component)_listContent).gameObject.AddComponent<ContentSizeFitter>(); } val13.horizontalFit = (FitMode)0; val13.verticalFit = (FitMode)2; } float num5 = -290f; _detailText = CreateLabel(val.transform, string.Empty, new Vector2(0f, num5 + 130f), 400f, 34f, bold: false); float num6 = num5 + 92f; Transform transform4 = val.transform; Vector2 pos4 = new Vector2(-130f, num6); object obj8 = <>O.<4>__OnPinSelected; if (obj8 == null) { UnityAction val14 = OnPinSelected; <>O.<4>__OnPinSelected = val14; obj8 = (object)val14; } _pinButton = CreateActionButton(transform4, "Pin", pos4, (UnityAction)obj8).GetComponent<Button>(); Transform transform5 = val.transform; Vector2 pos5 = new Vector2(0f, num6); object obj9 = <>O.<5>__OnPing; if (obj9 == null) { UnityAction val15 = OnPing; <>O.<5>__OnPing = val15; obj9 = (object)val15; } CreateActionButton(transform5, "Ping", pos5, (UnityAction)obj9); Transform transform6 = val.transform; Vector2 pos6 = new Vector2(130f, num6); object obj10 = <>O.<6>__OnPingExit; if (obj10 == null) { UnityAction val16 = OnPingExit; <>O.<6>__OnPingExit = val16; obj10 = (object)val16; } _pingExitButton = CreateActionButton(transform6, "Ping exit", pos6, (UnityAction)obj10).GetComponent<Button>(); float num7 = num5 + 58f; Transform transform7 = val.transform; Vector2 pos7 = new Vector2(-70f, num7); object obj11 = <>O.<7>__OnAddToJournal; if (obj11 == null) { UnityAction val17 = OnAddToJournal; <>O.<7>__OnAddToJournal = val17; obj11 = (object)val17; } _addJournalButton = CreateActionButton(transform7, "Add to journal", pos7, (UnityAction)obj11).GetComponent<Button>(); Transform transform8 = val.transform; Vector2 pos8 = new Vector2(70f, num7); object obj12 = <>c.<>9__52_4; if (obj12 == null) { UnityAction val18 = delegate { PortalMapPins.ClearSavedPins(); SetStatus("Cleared this mod's saved portal pins (manual pins untouched)."); }; <>c.<>9__52_4 = val18; obj12 = (object)val18; } CreateActionButton(transform8, "Clear saved", pos8, (UnityAction)obj12); float num8 = num5 + 24f; GameObject obj13 = GUIManager.Instance.CreateToggle(val.transform, 28f, 28f); ((Object)obj13).name = "AutoPin"; RectTransform component2 = obj13.GetComponent<RectTransform>(); ((Vector2)(ref val9))..ctor(0.5f, 0.5f); component2.anchorMax = val9; component2.anchorMin = val9; component2.pivot = new Vector2(0.5f, 0.5f); component2.anchoredPosition = new Vector2(-180f, num8); component2.sizeDelta = new Vector2(28f, 28f); _autoPinToggle = obj13.GetComponent<Toggle>(); if ((Object)(object)_autoPinToggle != (Object)null) { _autoPinToggle.isOn = PortalAtlasPlugin.AutoPin != null && PortalAtlasPlugin.AutoPin.Value; ((UnityEvent<bool>)(object)_autoPinToggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v) { if (PortalAtlasPlugin.AutoPin != null) { PortalAtlasPlugin.AutoPin.Value = v; } PortalAtlasPlugin.Debug($"AutoPin toggle → {v}"); }); } CreateLabel(val.transform, "Auto-pin when I approach a portal", new Vector2(18f, num8), 350f, 26f, bold: false).alignment = (TextAnchor)3; _panelRoot.SetActive(false); _builtLayoutVersion = 5; PortalRpc.OnWorldListReceived = OnWorldList; } private static GameObject CreateActionButton(Transform parent, string text, Vector2 pos, UnityAction action) { //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_0025: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateButton(text, parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), pos, 110f, 28f); Button component = obj.GetComponent<Button>(); ((UnityEvent)component.onClick).AddListener(action); GUIManager.Instance.ApplyButtonStyle(component, 14); return obj; } private static void CreateSortButton(Transform parent, string text, Vector2 pos, UnityAction action) { //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_0025: Unknown result type (might be due to invalid IL or missing references) GameObject val = GUIManager.Instance.CreateButton(text, parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), pos, 100f, 26f); ((UnityEvent)val.GetComponent<Button>().onClick).AddListener(action); GUIManager.Instance.ApplyButtonStyle(val.GetComponent<Button>(), 12); } private static Text CreateLabel(Transform parent, string text, Vector2 pos, float width, float height, bool bold) { //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_0037: 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_0056: 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_006a: 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) GameObject val = new GameObject("Label", new Type[2] { typeof(RectTransform), typeof(Text) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.5f); component.anchorMax = val2; component.anchorMin = val2; component.sizeDelta = new Vector2(width, height); component.anchoredPosition = pos; Text component2 = val.GetComponent<Text>(); component2.text = text; component2.alignment = (TextAnchor)4; component2.font = GUIManager.Instance.AveriaSerifBold; if ((Object)(object)component2.font == (Object)null) { component2.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); } component2.fontSize = (bold ? 18 : 14); ((Graphic)component2).color = Color.white; GUIManager.Instance.ApplyTextStyle(component2, bold ? 18 : 14); return component2; } private static void ReloadJournal() { KnownPortalCache.EnsureLoaded(); _journalRows = PortalScan.RowsFromKnown(KnownPortalCache.All); } private static void RebuildList() { //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) foreach (GameObject rowObject in _rowObjects) { if ((Object)(object)rowObject != (Object)null) { Object.Destroy((Object)(object)rowObject); } } _rowObjects.Clear(); List<PortalRow> obj = ((_showingWorld && _worldRows != null) ? _worldRows : _journalRows); string text = (((Object)(object)_filterInput != (Object)null) ? (_filterInput.text ?? string.Empty).Trim() : string.Empty); _visible = new List<PortalRow>(); foreach (PortalRow item in obj) { if (string.IsNullOrEmpty(text) || (item.Tag ?? string.Empty).IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0 || string.Equals(text, "(untagged)", StringComparison.OrdinalIgnoreCase)) { _visible.Add(item); } } Vector3 origin = GetSortOrigin(); _visible.Sort(delegate(PortalRow a, PortalRow b) { //IL_0020: 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) if (_sortByName) { int num = string.Compare(a.DisplayTag, b.DisplayTag, StringComparison.OrdinalIgnoreCase); if (num != 0) { return num; } } float num2 = DistXz(origin, a); float value = DistXz(origin, b); return num2.CompareTo(value); }); if (_visible.Count > 0) { if (_selected == null || !_visible.Contains(_selected)) { _selected = _visible[0]; } } else { _selected = null; } foreach (PortalRow item2 in _visible) { CreateRow(item2); } UpdateDetail(); RefreshChrome(); } private static void CreateRow(PortalRow row) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (