Decompiled source of OneMapToRuleThemAll v1.0.0
plugins/OneMapToRuleThemAll.dll
Decompiled 3 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Splatform; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("One Map To Rule Them All")] [assembly: AssemblyDescription("Valheim One Map To Rule Them All Mod by DrummerCraig")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("One Map To Rule Them All")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("6A5B7C8D-E9F0-1234-5678-9ABCDEF01234")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyVersion("1.0.0.0")] namespace OneMapToRuleThemAll; public class SharedPin { public string Name; public PinType Type; public Vector3 Pos; public bool Checked; public string OwnerId = ""; } public static class MapStateRepository { public const int MapSize = 2048; public const int MapSizeSquared = 4194304; public const string DiscoveryOwnerId = "auto"; private static List<SharedPin> ServerPins = new List<SharedPin>(); public static List<SharedPin> ClientPins = new List<SharedPin>(); public static bool[] Explored; public static bool InitialPinsReceived = false; public static ZPackage Default() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(2048); for (int i = 0; i < 4194304; i++) { val.Write(false); } val.Write(0); val.SetPos(0); return val; } public static ZPackage GetMapData() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(2048); bool[] explored = Explored; foreach (bool flag in explored) { val.Write(flag); } val.Write(ServerPins.Count); foreach (SharedPin serverPin in ServerPins) { val.Write(serverPin.Name); val.Write(serverPin.Pos); val.Write((int)serverPin.Type); val.Write(serverPin.Checked); val.Write(serverPin.OwnerId); } return val; } public static void SetMapData(ZPackage mapData) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) ServerPins.Clear(); mapData.SetPos(0); mapData.ReadInt(); int num = mapData.ReadInt(); bool[] array = new bool[num * num]; for (int i = 0; i < num * num; i++) { array[i] = mapData.ReadBool(); } int num2 = mapData.ReadInt(); for (int j = 0; j < num2; j++) { ServerPins.Add(new SharedPin { Name = mapData.ReadString(), Pos = mapData.ReadVector3(), Type = (PinType)mapData.ReadInt(), Checked = mapData.ReadBool(), OwnerId = mapData.ReadString() }); } Explored = array; } public static void SetExplored(int x, int y) { Explored[y * 2048 + x] = true; } public static bool[] GetExplorationArray() { return Explored; } public static void MergeExplorationArray(bool[] arr, int startIndex, int size) { for (int i = 0; i < size; i++) { Explored[startIndex + i] = arr[i] || Explored[startIndex + i]; } } public static ZPackage PackBoolArray(bool[] arr, int chunkId, int startIndex, int size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(chunkId); byte b = 0; int num = 0; for (int i = startIndex; i < startIndex + size; i++) { if (arr[i]) { b |= (byte)(1 << num); } num++; if (num >= 8) { val.Write(b); b = 0; num = 0; } } if (num > 0) { val.Write(b); } return val; } public static bool[] UnpackBoolArray(ZPackage z, int length) { bool[] array = new bool[length]; for (int i = 0; i < length; i += 8) { byte b = z.ReadByte(); array[i] = (b & 1) != 0; array[i + 1] = (b & 2) != 0; array[i + 2] = (b & 4) != 0; array[i + 3] = (b & 8) != 0; array[i + 4] = (b & 0x10) != 0; array[i + 5] = (b & 0x20) != 0; array[i + 6] = (b & 0x40) != 0; array[i + 7] = (b & 0x80) != 0; } return array; } public static ZPackage PackPin(SharedPin pin, bool skipSetPos = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0014: 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_002a: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(pin.Name); val.Write(pin.Pos); val.Write((int)pin.Type); val.Write(pin.Checked); val.Write(pin.OwnerId); if (!skipSetPos) { val.SetPos(0); } return val; } public static SharedPin UnpackPin(ZPackage z) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) return new SharedPin { Name = z.ReadString(), Pos = z.ReadVector3(), Type = (PinType)z.ReadInt(), Checked = z.ReadBool(), OwnerId = z.ReadString() }; } public static ZPackage PackPins(List<SharedPin> pins) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(pins.Count); foreach (SharedPin pin in pins) { val.Write(pin.Name); val.Write(pin.Pos); val.Write((int)pin.Type); val.Write(pin.Checked); val.Write(pin.OwnerId); } val.SetPos(0); return val; } public static List<SharedPin> UnpackPins(ZPackage z) { //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_0036: Unknown result type (might be due to invalid IL or missing references) List<SharedPin> list = new List<SharedPin>(); int num = z.ReadInt(); for (int i = 0; i < num; i++) { list.Add(new SharedPin { Name = z.ReadString(), Pos = z.ReadVector3(), Type = (PinType)z.ReadInt(), Checked = z.ReadBool(), OwnerId = z.ReadString() }); } return list; } public static List<SharedPin> GetPins() { return ServerPins; } public static void AddPin(SharedPin pin) { ServerPins.Add(pin); } public static void RemovePin(SharedPin needle) { ServerPins.RemoveAll((SharedPin p) => ArePinsEqual(p, needle)); } public static void SetPinState(SharedPin needle, bool state) { foreach (SharedPin serverPin in ServerPins) { if (ArePinsEqual(serverPin, needle)) { serverPin.Checked = state; } } } public static bool ArePinsEqual(SharedPin a, SharedPin b) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (a.Name == b.Name && a.Type == b.Type) { return ((Vector3)(ref a.Pos)).Equals(b.Pos); } return false; } public static bool ArePinsEqual(SharedPin a, PinData b) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (a.Name == b.m_name && a.Type == b.m_type) { return ((Vector3)(ref a.Pos)).Equals(b.m_pos); } return false; } } [HarmonyPatch] public static class ZNetProxy { [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNetAwake { private static void Postfix(ZNet __instance) { ZNetInstance = __instance; ModSettings.ModActive = true; if ((Object)(object)MinimapProxy.Instance != (Object)null && IsServer(__instance)) { MapPinSynchronizer.SendPinsToClient(null); } } } public static ZNet ZNetInstance; [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZNet), "IsServer")] public static bool IsServer(ZNet instance) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZNet), "IsDedicated")] public static bool IsDedicated(ZNet instance) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZNet), "GetServerRPC")] public static ZRpc GetServerRPC(ZNet instance) { throw new NotImplementedException(); } } [HarmonyPatch] public static class MinimapProxy { [HarmonyPatch(typeof(Minimap), "Awake")] private static class MinimapAwake { private static void Postfix(Minimap __instance) { Instance = __instance; object value = Traverse.Create((object)__instance).Field("m_fogTexture").GetValue(); FogTexture = (Texture2D)((value is Texture2D) ? value : null); } } public static Minimap Instance; public static Texture2D FogTexture; [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(int), typeof(int) })] public static bool Explore(Minimap instance, int x, int y) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "AddPin", new Type[] { typeof(Vector3), typeof(PinType), typeof(string), typeof(bool), typeof(bool), typeof(long), typeof(PlatformUserID) })] public static PinData AddPin(Minimap instance, Vector3 pos, PinType type, string name, bool save, bool isChecked, long owner, PlatformUserID author) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })] public static void RemovePin(Minimap instance, PinData pin) { throw new NotImplementedException(); } } public static class ExplorationSynchronizer { [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(Vector3), typeof(float) })] private class MinimapPatchExploreInterval { private static void Postfix(Minimap __instance) { if (_fogDirty) { _fogDirty = false; object value = Traverse.Create((object)__instance).Field("m_fogTexture").GetValue(); object obj = ((value is Texture2D) ? value : null); if (obj != null) { ((Texture2D)obj).Apply(); } } } } [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(int), typeof(int) })] private class MinimapPatchExplore { private static void Postfix(int x, int y, bool __result) { if (!__result || _blockExplore || !ModSettings.ModActive) { return; } if (ZNetProxy.IsServer(ZNetProxy.ZNetInstance)) { OnClientExplore(null, x, y); return; } ZRpc serverRPC = ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance); if (serverRPC != null) { serverRPC.Invoke("OM_ClientExplore", new object[2] { x, y }); } } } [HarmonyPatch(typeof(Minimap), "SetMapData", new Type[] { typeof(byte[]) })] private class MinimapPatchSetMapData { private static void Prefix() { _blockExplore = true; } private static void Postfix() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown _blockExplore = false; if (!ModSettings.ModActive) { return; } if (ZNetProxy.IsServer(ZNetProxy.ZNetInstance)) { SendChunkToClient(null, 0); return; } ZRpc serverRPC = ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance); if (serverRPC != null) { serverRPC.Invoke("OM_ClientRequestInitialMap", new object[1] { (object)new ZPackage() }); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class ZNetPatchRPCPeerInfo { private static void Postfix(ZRpc rpc, ZNet __instance) { if (ModSettings.ModActive && __instance.IsServer()) { SendChunkToClient(rpc, 0); rpc.Invoke("OM_ServerDiscoveryConfig", new object[1] { AutoPinConfig.PackDiscoveryConfig() }); rpc.Invoke("OM_ServerRadarConfig", new object[1] { RadarConfig.PackRadarConfig() }); } } } private static bool _blockExplore; private static bool _fogDirty; private const int Chunks = 64; public static void OnClientExplore(ZRpc client, int x, int y) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown if (!ModSettings.ModActive) { return; } MapStateRepository.SetExplored(x, y); List<ZNetPeer> obj = Traverse.Create((object)ZNet.instance).Field("m_peers").GetValue() as List<ZNetPeer>; int num = 0; foreach (ZNetPeer item in obj) { if (item.IsReady() && item.m_rpc != client) { ZPackage val = new ZPackage(); val.Write(x); val.Write(y); item.m_rpc.Invoke("OM_ServerMapData", new object[1] { val }); num++; } } if ((Object)(object)MinimapProxy.Instance != (Object)null) { MinimapProxy.Explore(MinimapProxy.Instance, x, y); _fogDirty = true; } } public static void OnClientRequestInitialMap(ZRpc client, ZPackage data) { if (ModSettings.ModActive) { SendChunkToClient(client, 0); } } public static void OnClientInitialMap(ZRpc client, ZPackage data) { if (ModSettings.ModActive) { data.SetPos(0); int num = data.ReadInt(); int num2 = 65536; int startIndex = num * num2; MapStateRepository.MergeExplorationArray(MapStateRepository.UnpackBoolArray(data, num2), startIndex, num2); SendChunkToClient(client, num + 1); } } public static void OnServerMapData(ZRpc rpc, ZPackage data) { if (ModSettings.ModActive) { data.SetPos(0); int x = data.ReadInt(); int y = data.ReadInt(); if (!((Object)(object)MinimapProxy.Instance == (Object)null)) { MinimapProxy.Explore(MinimapProxy.Instance, x, y); _fogDirty = true; } } } public static void OnServerMapInitial(ZRpc rpc, ZPackage data) { if (!ModSettings.ModActive) { return; } data.SetPos(0); int num = data.ReadInt(); int num2 = 65536; int num3 = num * num2; bool[] array = MapStateRepository.UnpackBoolArray(data, num2); for (int i = 0; i < array.Length; i++) { if (array[i]) { MinimapProxy.Explore(MinimapProxy.Instance, (num3 + i) % 2048, (num3 + i) / 2048); } } Texture2D fogTexture = MinimapProxy.FogTexture; if (fogTexture != null) { fogTexture.Apply(); } ((MonoBehaviour)ZNetProxy.ZNetInstance).StartCoroutine(SendChunkToServer(rpc, num)); } private static void SendChunkToClient(ZRpc client, int chunk) { if (chunk < 64) { int num = 65536; int startIndex = chunk * num; ZPackage val = MapStateRepository.PackBoolArray(MapStateRepository.GetExplorationArray(), chunk, startIndex, num); if (client == null) { OnServerMapInitial(null, val); return; } client.Invoke("OM_ServerMapInitial", new object[1] { val }); } } private static IEnumerator SendChunkToServer(ZRpc serverRpc, int chunk) { if (chunk >= 64) { yield break; } int num = 65536; int startIndex = chunk * num; bool[] arr = Traverse.Create((object)MinimapProxy.Instance).Field("m_explored").GetValue() as bool[]; ZPackage z = MapStateRepository.PackBoolArray(arr, chunk, startIndex, num); if (serverRpc == null) { OnClientInitialMap(null, z); yield break; } yield return (object)new WaitUntil((Func<bool>)(() => ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance) != null)); ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance).Invoke("OM_ClientInitialMap", new object[1] { z }); } } public static class MapPinSynchronizer { [HarmonyPatch(typeof(Minimap), "OnPinTextEntered")] private class MinimapPatchOnPinTextEntered { private static void Prefix(out PinData __state, PinData ___m_namePin) { __state = ___m_namePin; } private static void Postfix(PinData __state) { if (__state != null) { SendPinToServer(__state); } } } [HarmonyPatch(typeof(Minimap), "OnMapRightClick")] private class MinimapPatchOnMapRightClick { private static void Postfix() { //IL_0062: 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_007c: Unknown result type (might be due to invalid IL or missing references) if (LatestClosestPin == null) { return; } SharedPin clientPin = GetClientPin(LatestClosestPin); if (clientPin == null) { return; } if (clientPin.OwnerId == "auto") { if ((Object)(object)MinimapProxy.Instance != (Object)null) { string name = (AutoPinConfig.DiscoveryPinText.Value ? clientPin.Name : ""); string keywordForLabel = AutoPinConfig.GetKeywordForLabel(clientPin.Name); PinData mmPin = MinimapProxy.AddPin(MinimapProxy.Instance, clientPin.Pos, clientPin.Type, name, save: false, clientPin.Checked, 0L, new PlatformUserID("")); if (keywordForLabel != null) { AutoPinConfig.ApplyDiscoveryIcon(mmPin, keywordForLabel); } } } else { RemovePinFromServer(clientPin); } } } [HarmonyPatch(typeof(Minimap), "OnMapLeftClick")] private class MinimapPatchOnMapLeftClick { private static void Postfix() { if (LatestClosestPin != null) { SharedPin clientPin = GetClientPin(LatestClosestPin); if (clientPin != null) { clientPin.Checked = LatestClosestPin.m_checked; CheckPinOnServer(clientPin, clientPin.Checked); } } } } [HarmonyPatch(typeof(Minimap), "GetClosestPin", new Type[] { typeof(Vector3), typeof(float), typeof(bool) })] private class MinimapPatchGetClosestPin { private static void Postfix(ref PinData __result, Vector3 pos, float radius) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) if (!ModSettings.ModActive) { return; } LatestClosestPin = __result; SharedPin sharedPin = null; float num = 999999f; foreach (SharedPin clientPin in MapStateRepository.ClientPins) { float num2 = Utils.DistanceXZ(pos, clientPin.Pos); if (num2 < radius && (sharedPin == null || num2 < num)) { sharedPin = clientPin; num = num2; } } if (sharedPin != null) { PinData mapPin = GetMapPin(sharedPin); if (mapPin != null && (__result == null || Utils.DistanceXZ(pos, __result.m_pos) > num)) { __result = mapPin; LatestClosestPin = mapPin; } } } } [HarmonyPatch(typeof(Minimap), "ClearPins")] private class MinimapPatchClearPins { private static void Postfix() { AddPinsAfterClear(); } } [HarmonyPatch(typeof(Minimap), "UpdatePins")] private class MinimapPatchUpdateDiscoveryIcons { private static void Postfix(Minimap __instance) { if (!AutoPinConfig.DiscoveryPinObjectIcon.Value || MapStateRepository.ClientPins.Count == 0 || !(Traverse.Create((object)__instance).Field("m_pins").GetValue() is List<PinData> list) || list.Count == 0) { return; } foreach (SharedPin clientPin in MapStateRepository.ClientPins) { if (clientPin.OwnerId != "auto") { continue; } string keywordForLabel = AutoPinConfig.GetKeywordForLabel(clientPin.Name); if (keywordForLabel == null || !RadarIconLoader.TryGetIcon(keywordForLabel, out var sprite)) { continue; } foreach (PinData item in list) { if (MapStateRepository.ArePinsEqual(clientPin, item)) { item.m_icon = sprite; break; } } } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class ZNetPatchRPCPeerInfo { private static void Postfix(ZRpc rpc, ZNet __instance) { if (ModSettings.ModActive && __instance.IsServer()) { SendPinsToClient(rpc); rpc.Invoke("OM_ServerDiscoveryConfig", new object[1] { AutoPinConfig.PackDiscoveryConfig() }); rpc.Invoke("OM_ServerRadarConfig", new object[1] { RadarConfig.PackRadarConfig() }); } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ZNetPatchShutdown { private static void Postfix() { MapStateRepository.ClientPins.Clear(); MapStateRepository.InitialPinsReceived = false; AutoPinConfig.ResetToLocalConfig(); RadarConfig.ResetToLocalConfig(); RadarClusterManager.Clear(); } } [HarmonyPatch(typeof(Minimap), "SetMapData", new Type[] { typeof(byte[]) })] private class MinimapPatchSetMapData { private static void Postfix() { if (ModSettings.ModActive && !((Object)(object)ZNetProxy.ZNetInstance == (Object)null) && ZNetProxy.IsServer(ZNetProxy.ZNetInstance)) { SendPinsToClient(null); } } } private static PinData LatestClosestPin; public static void OnClientAddPin(ZRpc client, ZPackage data) { if (!ModSettings.ModActive) { return; } data.SetPos(0); SharedPin pin = MapStateRepository.UnpackPin(data); MapStateRepository.AddPin(pin); foreach (ZNetPeer item in Traverse.Create((object)ZNet.instance).Field("m_peers").GetValue() as List<ZNetPeer>) { if (item.IsReady() && item.m_rpc != client) { item.m_rpc.Invoke("OM_ServerAddPin", new object[1] { MapStateRepository.PackPin(pin) }); } } if (client != null && (Object)(object)MinimapProxy.Instance != (Object)null) { OnServerAddPin(null, MapStateRepository.PackPin(pin)); } } public static void OnClientRemovePin(ZRpc client, ZPackage data) { if (!ModSettings.ModActive) { return; } data.SetPos(0); SharedPin sharedPin = MapStateRepository.UnpackPin(data); if (client != null && !ClientCanRemovePin(client, sharedPin)) { return; } MapStateRepository.RemovePin(sharedPin); List<ZNetPeer> obj = Traverse.Create((object)ZNet.instance).Field("m_peers").GetValue() as List<ZNetPeer>; bool flag = sharedPin.OwnerId == "auto"; foreach (ZNetPeer item in obj) { if (item.IsReady() && (flag || item.m_rpc != client)) { item.m_rpc.Invoke("OM_ServerRemovePin", new object[1] { MapStateRepository.PackPin(sharedPin) }); } } if (flag || client != null) { OnServerRemovePin(null, MapStateRepository.PackPin(sharedPin)); } } public static void OnClientCheckPin(ZRpc client, ZPackage data) { if (!ModSettings.ModActive) { return; } data.SetPos(0); SharedPin sharedPin = MapStateRepository.UnpackPin(data); bool flag = data.ReadBool(); MapStateRepository.SetPinState(sharedPin, flag); foreach (ZNetPeer item in Traverse.Create((object)ZNet.instance).Field("m_peers").GetValue() as List<ZNetPeer>) { if (item.IsReady() && item.m_rpc != client) { ZPackage val = MapStateRepository.PackPin(sharedPin, skipSetPos: true); val.Write(flag); item.m_rpc.Invoke("OM_ServerCheckPin", new object[1] { val }); } } if (client != null) { ZPackage val2 = MapStateRepository.PackPin(sharedPin, skipSetPos: true); val2.Write(flag); OnServerCheckPin(null, val2); } } private static bool ClientCanRemovePin(ZRpc client, SharedPin pin) { if (pin.OwnerId == "auto") { return false; } if (AdminCommands.IsAdmin(client)) { return true; } ZNetPeer val = (Traverse.Create((object)ZNet.instance).Field("m_peers").GetValue() as List<ZNetPeer>)?.FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.m_rpc == client)); if (val == null) { return false; } string text = val.m_uid.ToString(); if (!(pin.OwnerId == text)) { return pin.OwnerId == string.Empty; } return true; } public static void OnServerInitialPins(ZRpc rpc, ZPackage data) { if (ModSettings.ModActive) { data.SetPos(0); MapStateRepository.ClientPins = MapStateRepository.UnpackPins(data); MapStateRepository.InitialPinsReceived = true; AppendPins(); } } public static void OnServerAddPin(ZRpc rpc, ZPackage data) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (!ModSettings.ModActive) { return; } data.SetPos(0); SharedPin sharedPin = MapStateRepository.UnpackPin(data); string text = ZNet.GetUID().ToString(); MapStateRepository.ClientPins.Add(sharedPin); string text2 = null; if (sharedPin.OwnerId != "auto") { if (!ModSettings.ShowOtherPlayerPins.Value && sharedPin.OwnerId != "" && sharedPin.OwnerId != text) { return; } } else { text2 = AutoPinConfig.GetKeywordForLabel(sharedPin.Name); if (text2 != null && !WorldObjectConfig.IsKeywordDiscoveryVisible(text2)) { return; } } string name = ((sharedPin.OwnerId == "auto" && !AutoPinConfig.DiscoveryPinText.Value) ? "" : sharedPin.Name); PinData mmPin = MinimapProxy.AddPin(MinimapProxy.Instance, sharedPin.Pos, sharedPin.Type, name, save: false, sharedPin.Checked, 0L, new PlatformUserID("")); if (text2 != null) { AutoPinConfig.ApplyDiscoveryIcon(mmPin, text2); } } public static void OnServerRemovePin(ZRpc rpc, ZPackage data) { if (!ModSettings.ModActive) { return; } data.SetPos(0); SharedPin pin = MapStateRepository.UnpackPin(data); MapStateRepository.ClientPins.RemoveAll((SharedPin p) => MapStateRepository.ArePinsEqual(p, pin)); if (!((Object)(object)MinimapProxy.Instance == (Object)null) && Traverse.Create((object)MinimapProxy.Instance).Field("m_pins").GetValue() is List<PinData> mmPins) { PinData mapPin = GetMapPin(pin); if (mapPin != null) { DestroyPinEntry(mmPins, mapPin); } } } public static void OnServerCheckPin(ZRpc rpc, ZPackage data) { if (!ModSettings.ModActive) { return; } data.SetPos(0); SharedPin b = MapStateRepository.UnpackPin(data); bool @checked = data.ReadBool(); foreach (SharedPin clientPin in MapStateRepository.ClientPins) { if (MapStateRepository.ArePinsEqual(clientPin, b)) { clientPin.Checked = @checked; PinData mapPin = GetMapPin(clientPin); if (mapPin != null) { mapPin.m_checked = @checked; } } } } public static void SendPinToServer(PinData pin, bool isDiscovery = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!ModSettings.ModActive) { return; } SharedPin sharedPin = new SharedPin { Name = pin.m_name, Pos = pin.m_pos, Type = pin.m_type, Checked = pin.m_checked, OwnerId = (isDiscovery ? "auto" : ZNet.GetUID().ToString()) }; MapStateRepository.ClientPins.Add(sharedPin); ZPackage val = MapStateRepository.PackPin(sharedPin); if (ZNetProxy.IsServer(ZNetProxy.ZNetInstance)) { OnClientAddPin(null, val); return; } ZRpc serverRPC = ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance); if (serverRPC != null) { serverRPC.Invoke("OM_ClientAddPin", new object[1] { val }); } } public static void RemovePinFromServer(SharedPin pin) { if (!ModSettings.ModActive) { return; } MapStateRepository.ClientPins.Remove(pin); ZPackage val = MapStateRepository.PackPin(pin); if (ZNetProxy.IsServer(ZNetProxy.ZNetInstance)) { OnClientRemovePin(null, val); return; } ZRpc serverRPC = ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance); if (serverRPC != null) { serverRPC.Invoke("OM_ClientRemovePin", new object[1] { val }); } } public static void CheckPinOnServer(SharedPin pin, bool state) { if (!ModSettings.ModActive) { return; } ZPackage val = MapStateRepository.PackPin(pin, skipSetPos: true); val.Write(state); val.SetPos(0); if (ZNetProxy.IsServer(ZNetProxy.ZNetInstance)) { OnClientCheckPin(null, val); return; } ZRpc serverRPC = ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance); if (serverRPC != null) { serverRPC.Invoke("OM_ClientCheckPin", new object[1] { val }); } } public static void SendPinsToClient(ZRpc client) { if (ModSettings.ModActive) { ZPackage val = MapStateRepository.PackPins(MapStateRepository.GetPins()); if (client == null) { OnServerInitialPins(null, val); return; } client.Invoke("OM_ServerInitialPins", new object[1] { val }); } } public static void AppendPins() { //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) if (!ModSettings.ModActive || (Object)(object)MinimapProxy.Instance == (Object)null || !(Traverse.Create((object)MinimapProxy.Instance).Field("m_pins").GetValue() is List<PinData> list)) { return; } string text = ZNet.GetUID().ToString(); foreach (SharedPin pin in MapStateRepository.ClientPins) { PinData val = ((!(pin.OwnerId == "auto")) ? ((IEnumerable<PinData>)list).FirstOrDefault((Func<PinData, bool>)((PinData p) => MapStateRepository.ArePinsEqual(pin, p))) : ((IEnumerable<PinData>)list).FirstOrDefault((Func<PinData, bool>)((PinData p) => p.m_type == pin.Type && Utils.DistanceXZ(pin.Pos, p.m_pos) < 1f))); if (val != null) { DestroyPinEntry(list, val); } string text2 = null; bool flag; if (pin.OwnerId == "auto") { text2 = AutoPinConfig.GetKeywordForLabel(pin.Name); flag = text2 == null || WorldObjectConfig.IsKeywordDiscoveryVisible(text2); } else { flag = ModSettings.ShowOtherPlayerPins.Value || pin.OwnerId == "" || pin.OwnerId == text; } if (flag) { string name = ((pin.OwnerId == "auto" && !AutoPinConfig.DiscoveryPinText.Value) ? "" : pin.Name); PinData mmPin = MinimapProxy.AddPin(MinimapProxy.Instance, pin.Pos, pin.Type, name, save: false, pin.Checked, 0L, new PlatformUserID("")); if (text2 != null) { AutoPinConfig.ApplyDiscoveryIcon(mmPin, text2); } } } } private static void AddPinsAfterClear() { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) if (!ModSettings.ModActive || (Object)(object)MinimapProxy.Instance == (Object)null) { return; } string text = ZNet.GetUID().ToString(); foreach (SharedPin clientPin in MapStateRepository.ClientPins) { string text2 = null; bool flag; if (clientPin.OwnerId == "auto") { text2 = AutoPinConfig.GetKeywordForLabel(clientPin.Name); flag = text2 == null || WorldObjectConfig.IsKeywordDiscoveryVisible(text2); } else { flag = ModSettings.ShowOtherPlayerPins.Value || clientPin.OwnerId == "" || clientPin.OwnerId == text; } if (flag) { string name = ((clientPin.OwnerId == "auto" && !AutoPinConfig.DiscoveryPinText.Value) ? "" : clientPin.Name); PinData mmPin = MinimapProxy.AddPin(MinimapProxy.Instance, clientPin.Pos, clientPin.Type, name, save: false, clientPin.Checked, 0L, new PlatformUserID("")); if (text2 != null) { AutoPinConfig.ApplyDiscoveryIcon(mmPin, text2); } } } } private static void DestroyPinEntry(List<PinData> mmPins, PinData mmPin) { FieldInfo[] fields = typeof(PinData).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType != typeof(RectTransform))) { object? value = fieldInfo.GetValue(mmPin); RectTransform val = (RectTransform)((value is RectTransform) ? value : null); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } break; } } mmPins.Remove(mmPin); } private static PinData GetMapPin(SharedPin needle) { //IL_0083: 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_0092: 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) if (!(Traverse.Create((object)MinimapProxy.Instance).Field("m_pins").GetValue() is List<PinData> list)) { return null; } foreach (PinData item in list) { if (MapStateRepository.ArePinsEqual(needle, item)) { return item; } } if (needle.OwnerId == "auto") { foreach (PinData item2 in list) { if (needle.Type == item2.m_type && Utils.DistanceXZ(needle.Pos, item2.m_pos) < 1f) { return item2; } } } return null; } private static SharedPin GetClientPin(PinData needle) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) foreach (SharedPin clientPin in MapStateRepository.ClientPins) { if (MapStateRepository.ArePinsEqual(clientPin, needle)) { return clientPin; } } foreach (SharedPin clientPin2 in MapStateRepository.ClientPins) { if (clientPin2.OwnerId == "auto" && clientPin2.Type == needle.m_type && Utils.DistanceXZ(clientPin2.Pos, needle.m_pos) < 1f) { return clientPin2; } } return null; } } [BepInPlugin("drummercraig.one_map_to_rule_them_all", "One Map To Rule Them All", "1.0.0")] public class OneMapToRuleThemAllPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private class ZNetPatchOnNewConnection { private static void Postfix(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { ModSettings.ModActive = true; } if (ModSettings.ModActive) { if (__instance.IsServer()) { peer.m_rpc.Register<int, int>("OM_ClientExplore", (Action<ZRpc, int, int>)ExplorationSynchronizer.OnClientExplore); peer.m_rpc.Register<ZPackage>("OM_ClientInitialMap", (Action<ZRpc, ZPackage>)ExplorationSynchronizer.OnClientInitialMap); peer.m_rpc.Register<ZPackage>("OM_ClientRequestInitialMap", (Action<ZRpc, ZPackage>)ExplorationSynchronizer.OnClientRequestInitialMap); peer.m_rpc.Register<ZPackage>("OM_ClientAddPin", (Action<ZRpc, ZPackage>)MapPinSynchronizer.OnClientAddPin); peer.m_rpc.Register<ZPackage>("OM_ClientRemovePin", (Action<ZRpc, ZPackage>)MapPinSynchronizer.OnClientRemovePin); peer.m_rpc.Register<ZPackage>("OM_ClientCheckPin", (Action<ZRpc, ZPackage>)MapPinSynchronizer.OnClientCheckPin); peer.m_rpc.Register<ZPackage>("OM_AdminClearArea", (Action<ZRpc, ZPackage>)AdminCommands.OnAdminClearArea); peer.m_rpc.Register<ZPackage>("OM_AdminClearAll", (Action<ZRpc, ZPackage>)AdminCommands.OnAdminClearAll); peer.m_rpc.Register<ZPackage>("OM_AdminRenameAbbr", (Action<ZRpc, ZPackage>)AdminCommands.OnAdminRenameAbbr); peer.m_rpc.Register<ZPackage>("OM_AdminUpdateDiscoveryConfig", (Action<ZRpc, ZPackage>)AdminCommands.OnAdminUpdateDiscoveryConfig); } else { peer.m_rpc.Register<ZPackage>("OM_ServerMapData", (Action<ZRpc, ZPackage>)ExplorationSynchronizer.OnServerMapData); peer.m_rpc.Register<ZPackage>("OM_ServerMapInitial", (Action<ZRpc, ZPackage>)ExplorationSynchronizer.OnServerMapInitial); peer.m_rpc.Register<ZPackage>("OM_ServerInitialPins", (Action<ZRpc, ZPackage>)MapPinSynchronizer.OnServerInitialPins); peer.m_rpc.Register<ZPackage>("OM_ServerAddPin", (Action<ZRpc, ZPackage>)MapPinSynchronizer.OnServerAddPin); peer.m_rpc.Register<ZPackage>("OM_ServerRemovePin", (Action<ZRpc, ZPackage>)MapPinSynchronizer.OnServerRemovePin); peer.m_rpc.Register<ZPackage>("OM_ServerCheckPin", (Action<ZRpc, ZPackage>)MapPinSynchronizer.OnServerCheckPin); peer.m_rpc.Register<ZPackage>("OM_ServerDiscoveryConfig", (Action<ZRpc, ZPackage>)AutoPinConfig.OnServerDiscoveryConfig); peer.m_rpc.Register<ZPackage>("OM_ServerRadarConfig", (Action<ZRpc, ZPackage>)RadarConfig.OnServerRadarConfig); } } } } private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown ModSettings.Log = ((BaseUnityPlugin)this).Logger; Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); ConfigFile serverConfig = new ConfigFile(Path.Combine(Paths.ConfigPath, "One_Map_To_Rule_Them_All_Settings.cfg"), true); ModSettings.ResetToDefaults = serverConfig.Bind<bool>("General", "ResetToDefaults", false, "Set to true to reset ALL settings to their default values. Resets itself to false automatically."); ModSettings.ResetToDefaults.SettingChanged += delegate { if (!ModSettings.ResetToDefaults.Value) { return; } foreach (ConfigDefinition key in serverConfig.Keys) { serverConfig[key].BoxedValue = serverConfig[key].DefaultValue; } }; ModSettings.ShowOtherPlayerPins = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "ShowOtherPlayerPins", true, "Show map pins created by other players on your minimap."); AutoPinConfig.Bind(serverConfig, ((BaseUnityPlugin)this).Config); WorldObjectConfig.DiscoveryVisibilityChanged += MapPinSynchronizer.AppendPins; AutoPinConfig.DiscoveryPinObjectIcon.SettingChanged += delegate { MapPinSynchronizer.AppendPins(); }; AutoPinConfig.DiscoveryPinText.SettingChanged += delegate { MapPinSynchronizer.AppendPins(); }; RadarConfig.Bind(serverConfig, ((BaseUnityPlugin)this).Config); ModSettings.ShowOtherPlayerPins.SettingChanged += delegate { MapPinSynchronizer.AppendPins(); }; } } public static class MapFilePersistence { [HarmonyPatch(typeof(ZNet), "LoadWorld")] private class ZNetPatchLoadWorld { private static void Postfix(ZNet __instance) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown object value = Traverse.Create(typeof(ZNet)).Field("m_world").GetValue(); string dBPath = ((World)((value is World) ? value : null)).GetDBPath(); string text = Path.ChangeExtension(Utils.GetSaveDataPath((FileSource)1) + dBPath, null); string text2 = (_savePath = text + ".one_map_to_rule_them_all.explored"); ManualLogSource log = ModSettings.Log; if (log != null) { log.LogInfo((object)$"[MapFilePersistence] LoadWorld — savePath={text2} exists={File.Exists(text2)}"); } if (File.Exists(text2)) { try { MapStateRepository.SetMapData(new ZPackage(File.ReadAllBytes(text2))); ManualLogSource log2 = ModSettings.Log; if (log2 != null) { log2.LogInfo((object)$"[MapFilePersistence] Loaded {MapStateRepository.GetPins().Count} pins from save file."); } return; } catch (Exception ex) { ManualLogSource log3 = ModSettings.Log; if (log3 != null) { log3.LogWarning((object)("[MapFilePersistence] Failed to read save file: " + ex.Message)); } } } ZPackage val = TryMigrateFromServerSideMap(text); if (val != null) { MapStateRepository.SetMapData(val); File.WriteAllBytes(text2, MapStateRepository.GetMapData().GetArray()); } else { MapStateRepository.SetMapData(MapStateRepository.Default()); } } } [HarmonyPatch(typeof(ZNet), "SaveWorldThread")] private class ZNetPatchSaveWorldThread { private static void Postfix() { SaveMapData(); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ZNetPatchShutdownSave { private static void Prefix() { ManualLogSource log = ModSettings.Log; if (log != null) { log.LogInfo((object)$"[MapFilePersistence] ZNet.Shutdown Prefix — ServerPins={MapStateRepository.GetPins().Count} savePath={_savePath}"); } SaveMapData(); } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] private class ZNetPatchOnDestroySave { private static void Prefix() { ManualLogSource log = ModSettings.Log; if (log != null) { log.LogInfo((object)$"[MapFilePersistence] ZNet.OnDestroy Prefix — ServerPins={MapStateRepository.GetPins().Count} savePath={_savePath}"); } SaveMapData(); } } private static string _savePath; private static void SaveMapData() { if (MapStateRepository.Explored == null) { ManualLogSource log = ModSettings.Log; if (log != null) { log.LogWarning((object)"[MapFilePersistence] SaveMapData skipped — Explored is null."); } return; } if (_savePath == null) { ManualLogSource log2 = ModSettings.Log; if (log2 != null) { log2.LogWarning((object)"[MapFilePersistence] SaveMapData skipped — _savePath is null."); } return; } try { List<SharedPin> pins = MapStateRepository.GetPins(); byte[] array = MapStateRepository.GetMapData().GetArray(); File.WriteAllBytes(_savePath, array); ManualLogSource log3 = ModSettings.Log; if (log3 != null) { log3.LogInfo((object)$"[MapFilePersistence] Saved {pins.Count} pins ({array.Length} bytes) to {_savePath}"); } } catch (Exception ex) { ManualLogSource log4 = ModSettings.Log; if (log4 != null) { log4.LogError((object)("[MapFilePersistence] Save failed: " + ex.Message)); } } } private static ZPackage TryMigrateFromServerSideMap(string basePath) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) string path = basePath + ".mod.serversidemap.explored"; if (!File.Exists(path)) { return null; } try { ZPackage val = new ZPackage(File.ReadAllBytes(path)); val.SetPos(0); val.ReadInt(); int num = val.ReadInt(); bool[] array = new bool[num * num]; for (int i = 0; i < array.Length; i++) { array[i] = val.ReadBool(); } int num2 = val.ReadInt(); string[] array2 = new string[num2]; Vector3[] array3 = (Vector3[])(object)new Vector3[num2]; int[] array4 = new int[num2]; bool[] array5 = new bool[num2]; for (int j = 0; j < num2; j++) { array2[j] = val.ReadString(); array3[j] = val.ReadVector3(); array4[j] = val.ReadInt(); array5[j] = val.ReadBool(); } string text = ZNet.GetUID().ToString(); ZPackage val2 = new ZPackage(); val2.Write(1); val2.Write(num); bool[] array6 = array; foreach (bool flag in array6) { val2.Write(flag); } val2.Write(num2); for (int l = 0; l < num2; l++) { val2.Write(array2[l]); val2.Write(array3[l]); val2.Write(array4[l]); val2.Write(array5[l]); val2.Write(text); } val2.SetPos(0); return val2; } catch { return null; } } } public static class ModSettings { public static ConfigEntry<bool> ResetToDefaults; public static ConfigEntry<bool> ShowOtherPlayerPins; public static bool ModActive = true; public static ManualLogSource Log; public static bool IsServer() { return ZNetProxy.IsServer(ZNetProxy.ZNetInstance); } } public class BiomeCritterCategory { public string CategoryName; public ConfigEntry<float> RadarRadiusEntry; public List<(string MatchKeyword, string DisplayName, string IconName)> CreatureDefinitions = new List<(string, string, string)>(); public float ActiveRadarRadius; public List<(string InternalId, string DisplayName)> ActiveOrderedCreatures = new List<(string, string)>(); public string[] Keywords = Array.Empty<string>(); } public class PickableCategory { public string CategoryName; public ConfigEntry<float> DiscoveryRadiusEntry; public ConfigEntry<float> RadarRadiusEntry; public ConfigEntry<string> TrackedDiscoveryEntry; public ConfigEntry<string> TrackedRadarEntry; public float ActiveDiscoveryRadius; public float ActiveRadarRadius; public string[] DiscoveryKeywords = Array.Empty<string>(); public string[] RadarKeywords = Array.Empty<string>(); } public static class WorldObjectConfig { public static readonly List<PickableCategory> PickableCategories = new List<PickableCategory>(); public static ConfigEntry<float> OresDiscoveryRadius; public static ConfigEntry<float> OresRadarRadius; public static ConfigEntry<string> TrackedOresDiscovery; public static ConfigEntry<string> TrackedOresRadar; public static ConfigEntry<float> LocationsDiscoveryRadius; public static ConfigEntry<float> LocationsRadarRadius; public static ConfigEntry<string> TrackedLocationsDiscovery; public static ConfigEntry<string> TrackedLocationsRadar; public static readonly List<BiomeCritterCategory> BiomeCritterCategories = new List<BiomeCritterCategory>(); public static float ActiveOresDiscoveryRadius; public static float ActiveOresRadarRadius; public static float ActiveLocationsDiscoveryRadius; public static float ActiveLocationsRadarRadius; public static string[] PickablesDiscovery = Array.Empty<string>(); public static string[] PickablesRadar = Array.Empty<string>(); public static string[] OresDiscovery = Array.Empty<string>(); public static string[] OresRadar = Array.Empty<string>(); public static string[] LocationsDiscovery = Array.Empty<string>(); public static string[] LocationsRadar = Array.Empty<string>(); private static readonly Dictionary<string, ConfigEntry<bool>> DiscoveryVisibilityEntries = new Dictionary<string, ConfigEntry<bool>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, ConfigEntry<bool>> RadarVisibilityEntries = new Dictionary<string, ConfigEntry<bool>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, ConfigEntry<bool>> _sectionToggleAllEntries = new Dictionary<string, ConfigEntry<bool>>(StringComparer.OrdinalIgnoreCase); private static ConfigFile _config; public static bool UsingServerConfig = false; public static event Action DiscoveryVisibilityChanged; public static event Action RadarVisibilityChanged; public static string DeriveMatchKeyword(string iconName) { if (!iconName.StartsWith("Trophy", StringComparison.OrdinalIgnoreCase)) { return iconName; } return iconName.Substring(6); } public static string NormalizeForMatch(string s) { return s?.Replace("_", "").Replace(" ", "").ToLower() ?? ""; } public static Dictionary<string, string> GetCreatureIconMap() { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { foreach (var creatureDefinition in biomeCritterCategory.CreatureDefinitions) { string item = creatureDefinition.DisplayName; string item2 = creatureDefinition.IconName; if (!dictionary.ContainsKey(item)) { dictionary[item] = item2; } } } return dictionary; } public static bool IsKeywordDiscoveryVisible(string keyword) { if (DiscoveryVisibilityEntries.TryGetValue(keyword, out var value)) { return value.Value; } return true; } public static bool IsKeywordRadarVisible(string keyword) { if (RadarVisibilityEntries.TryGetValue(keyword, out var value)) { return value.Value; } return true; } public static (string displayName, BiomeCritterCategory category) MatchCreatureKeyword(string objectName) { string text = NormalizeForMatch(objectName); foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { foreach (var (s, item) in biomeCritterCategory.ActiveOrderedCreatures) { if (text.Contains(NormalizeForMatch(s))) { return (item, biomeCritterCategory); } } } return (null, null); } public static string GetInternalIdForCreature(string displayName) { foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { foreach (var activeOrderedCreature in biomeCritterCategory.ActiveOrderedCreatures) { var (result, _) = activeOrderedCreature; if (string.Equals(activeOrderedCreature.DisplayName, displayName, StringComparison.OrdinalIgnoreCase)) { return result; } } } return displayName; } public static float GetPickableDiscoveryRadius(string keyword) { if (keyword == null) { return 6f; } foreach (PickableCategory pickableCategory in PickableCategories) { string[] discoveryKeywords = pickableCategory.DiscoveryKeywords; for (int i = 0; i < discoveryKeywords.Length; i++) { if (string.Equals(discoveryKeywords[i], keyword, StringComparison.OrdinalIgnoreCase)) { return pickableCategory.ActiveDiscoveryRadius; } } discoveryKeywords = pickableCategory.RadarKeywords; for (int i = 0; i < discoveryKeywords.Length; i++) { if (string.Equals(discoveryKeywords[i], keyword, StringComparison.OrdinalIgnoreCase)) { return pickableCategory.ActiveDiscoveryRadius; } } } return 6f; } public static void EnsureVisibilityEntries() { string[] discoveryKeywords; foreach (PickableCategory pickableCategory in PickableCategories) { string section = "MapPin.Pickables." + pickableCategory.CategoryName; string section2 = "Radar.Pickables." + pickableCategory.CategoryName; EnsureToggleAllEntry(section); EnsureToggleAllEntry(section2); discoveryKeywords = pickableCategory.DiscoveryKeywords; for (int i = 0; i < discoveryKeywords.Length; i++) { EnsureDiscoveryVisibilityEntry(discoveryKeywords[i], section); } discoveryKeywords = pickableCategory.RadarKeywords; for (int i = 0; i < discoveryKeywords.Length; i++) { EnsureRadarVisibilityEntry(discoveryKeywords[i], section2); } } EnsureToggleAllEntry("MapPin.Ores"); EnsureToggleAllEntry("Radar.Ores"); EnsureToggleAllEntry("MapPin.Locations"); EnsureToggleAllEntry("Radar.Locations"); discoveryKeywords = OresDiscovery; for (int i = 0; i < discoveryKeywords.Length; i++) { EnsureDiscoveryVisibilityEntry(discoveryKeywords[i], "MapPin.Ores"); } discoveryKeywords = OresRadar; for (int i = 0; i < discoveryKeywords.Length; i++) { EnsureRadarVisibilityEntry(discoveryKeywords[i], "Radar.Ores"); } discoveryKeywords = LocationsDiscovery; for (int i = 0; i < discoveryKeywords.Length; i++) { EnsureDiscoveryVisibilityEntry(discoveryKeywords[i], "MapPin.Locations"); } discoveryKeywords = LocationsRadar; for (int i = 0; i < discoveryKeywords.Length; i++) { EnsureRadarVisibilityEntry(discoveryKeywords[i], "Radar.Locations"); } foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { string section3 = "Radar.Critters." + biomeCritterCategory.CategoryName.Replace(" ", "_"); EnsureToggleAllEntry(section3); discoveryKeywords = biomeCritterCategory.Keywords; for (int i = 0; i < discoveryKeywords.Length; i++) { EnsureRadarVisibilityEntry(discoveryKeywords[i], section3); } } } private static void BindToggleAll(ConfigFile config, string section) { if (!_sectionToggleAllEntries.ContainsKey(section)) { _sectionToggleAllEntries[section] = config.Bind<bool>(section, "_ToggleAll", true, "Set all entries in this section on or off at once."); } } private static void EnsureToggleAllEntry(string section) { if (!_sectionToggleAllEntries.ContainsKey(section)) { BindToggleAll(_config, section); } } private static void EnsureDiscoveryVisibilityEntry(string keyword, string section) { if (!DiscoveryVisibilityEntries.ContainsKey(keyword)) { DiscoveryVisibilityEntries[keyword] = _config.Bind<bool>(section, keyword, true, "Show '" + keyword + "' discovery pins on your minimap. Pins are still created and shared; this only controls local visibility."); } } private static void EnsureRadarVisibilityEntry(string keyword, string section) { if (!RadarVisibilityEntries.ContainsKey(keyword)) { RadarVisibilityEntries[keyword] = _config.Bind<bool>(section, keyword, true, "Show '" + keyword + "' radar pins on your minimap. Client-only — never overridden by the server."); } } public static void Bind(ConfigFile serverConfig, ConfigFile clientConfig) { _config = clientConfig; PickableCategories.Clear(); (string, string)[] array = new(string, string)[8] { ("Meadows", "Raspberry,Dandelion,Flint,Mushroom"), ("BlackForest", "Blueberry,Thistle,Carrot"), ("Swamp", "SurtlingCore,Turnip"), ("Mountain", "Crystal,Onion"), ("Plains", "Cloudberry,Barley,Flax"), ("Ocean", "Chitin"), ("Mistlands", "JotunPuff,Magecap"), ("AshLands", "BlackCore") }; for (int i = 0; i < array.Length; i++) { (string, string) tuple = array[i]; string item = tuple.Item1; string item2 = tuple.Item2; string text = "Pickables." + item; PickableCategory pickableCategory = new PickableCategory { CategoryName = item }; pickableCategory.DiscoveryRadiusEntry = serverConfig.Bind<float>(text, "DiscoveryRadius", 6f, "How close (meters) the player must approach a " + item + " pickable to trigger a discovery pin. Maximum 150."); pickableCategory.RadarRadiusEntry = serverConfig.Bind<float>(text, "RadarRadius", 50f, "How close (meters) the player must be to a " + item + " pickable for its radar pin to appear. Maximum 150."); pickableCategory.TrackedDiscoveryEntry = serverConfig.Bind<string>(text, "TrackedDiscovery", item2, "Comma-separated keywords for " + item + " pickables that trigger a permanent discovery pin."); pickableCategory.TrackedRadarEntry = serverConfig.Bind<string>(text, "TrackedRadar", item2, "Comma-separated keywords for " + item + " pickables that appear as radar (transient proximity) pins."); pickableCategory.ActiveDiscoveryRadius = pickableCategory.DiscoveryRadiusEntry.Value; pickableCategory.ActiveRadarRadius = pickableCategory.RadarRadiusEntry.Value; pickableCategory.DiscoveryKeywords = AutoPinConfig.ParseKeywordList(pickableCategory.TrackedDiscoveryEntry.Value); pickableCategory.RadarKeywords = AutoPinConfig.ParseKeywordList(pickableCategory.TrackedRadarEntry.Value); PickableCategories.Add(pickableCategory); } OresDiscoveryRadius = serverConfig.Bind<float>("Ores", "DiscoveryRadius", 6f, "How close (meters) the player must approach an ore deposit to trigger a discovery pin. Maximum 150."); OresRadarRadius = serverConfig.Bind<float>("Ores", "RadarRadius", 50f, "How close (meters) the player must be to an ore deposit for its radar pin to appear. Maximum 150."); TrackedOresDiscovery = serverConfig.Bind<string>("Ores", "TrackedDiscovery", "Copper,Tin,Iron,Silver,Obsidian,BlackMarble,Meteorite,Flametal", "Comma-separated keywords for ore deposits that trigger a permanent discovery pin."); TrackedOresRadar = serverConfig.Bind<string>("Ores", "TrackedRadar", "Copper,Tin,Iron,Silver,Obsidian,BlackMarble,Meteorite,Flametal", "Comma-separated keywords for ore deposits that appear as radar pins."); LocationsDiscoveryRadius = serverConfig.Bind<float>("Locations", "DiscoveryRadius", 6f, "How close (meters) the player must approach a location to trigger a discovery pin. Maximum 150."); LocationsRadarRadius = serverConfig.Bind<float>("Locations", "RadarRadius", 50f, "How close (meters) the player must be to a location for its radar pin to appear. Maximum 150."); TrackedLocationsDiscovery = serverConfig.Bind<string>("Locations", "TrackedDiscovery", "Eikthyr,Hildir,Runestone,GDKing,TrollCave,Vendor,Bonemass,SunkenCrypt,Crypt,MudPile,BogWitch,DragonQueen,MountainCave,DrakeNest,FrostCave,GoblinKing,TarPit,Henge,GoblinCamp,WoodFarm,ShipWreck,SeekerQueen,InfestedMine,DvergrTown,Fader", "Comma-separated keywords for locations that trigger a permanent discovery pin."); TrackedLocationsRadar = serverConfig.Bind<string>("Locations", "TrackedRadar", "Eikthyr,Hildir,Runestone,GDKing,TrollCave,Vendor,Bonemass,SunkenCrypt,Crypt,MudPile,BogWitch,DragonQueen,MountainCave,DrakeNest,FrostCave,GoblinKing,TarPit,Henge,GoblinCamp,WoodFarm,ShipWreck,SeekerQueen,InfestedMine,DvergrTown,Fader", "Comma-separated keywords for locations that appear as radar pins."); string path = Path.Combine(Paths.ConfigPath, "OneMapToRuleThemAll.creatures.txt"); if (!File.Exists(path)) { WriteDefaultCreaturesFile(path); } LoadCreaturesFile(path); Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase) { { "Meadows", 50f }, { "BlackForest", 50f }, { "Swamp", 50f }, { "Mountain", 50f }, { "Plains", 50f }, { "Mistlands", 50f }, { "AshLands", 50f }, { "Ocean", 50f }, { "Bosses", 50f }, { "Minibosses", 50f }, { "General", 50f } }; foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { string text2 = "Critters." + biomeCritterCategory.CategoryName.Replace(" ", "_"); float value; float num = (dictionary.TryGetValue(biomeCritterCategory.CategoryName, out value) ? value : 40f); biomeCritterCategory.RadarRadiusEntry = serverConfig.Bind<float>(text2, "RadarRadius", num, "Detection radius (meters) for " + biomeCritterCategory.CategoryName + " creatures to show as radar pins. Maximum 150."); biomeCritterCategory.ActiveRadarRadius = biomeCritterCategory.RadarRadiusEntry.Value; RebuildBiomeCreatureState(biomeCritterCategory); } BindDiscoveryVisibility(clientConfig); BindRadarVisibility(clientConfig); clientConfig.SettingChanged += delegate(object _, SettingChangedEventArgs e) { string section = e.ChangedSetting.Definition.Section; if (e.ChangedSetting.Definition.Key == "_ToggleAll") { bool value2 = (bool)e.ChangedSetting.BoxedValue; foreach (ConfigEntry<bool> value3 in DiscoveryVisibilityEntries.Values) { if (((ConfigEntryBase)value3).Definition.Section == section) { value3.Value = value2; } } { foreach (ConfigEntry<bool> value4 in RadarVisibilityEntries.Values) { if (((ConfigEntryBase)value4).Definition.Section == section) { value4.Value = value2; } } return; } } if (section.StartsWith("MapPin.")) { WorldObjectConfig.DiscoveryVisibilityChanged?.Invoke(); } if (section.StartsWith("Radar.")) { WorldObjectConfig.RadarVisibilityChanged?.Invoke(); } Reload(); }; serverConfig.SettingChanged += delegate { Reload(); }; Reload(); } private static void BindDiscoveryVisibility(ConfigFile config) { string[] discoveryKeywords; foreach (PickableCategory pickableCategory in PickableCategories) { string text = "MapPin.Pickables." + pickableCategory.CategoryName; BindToggleAll(config, text); discoveryKeywords = pickableCategory.DiscoveryKeywords; foreach (string text2 in discoveryKeywords) { DiscoveryVisibilityEntries[text2] = config.Bind<bool>(text, text2, true, "Show '" + text2 + "' discovery pins on your minimap. Pins are still created and shared; this only controls local visibility."); } } string[] array = new string[8] { "Copper", "Tin", "Iron", "Silver", "Obsidian", "BlackMarble", "Meteorite", "Flametal" }; string[] array2 = new string[25] { "Eikthyr", "Hildir", "Runestone", "GDKing", "TrollCave", "Vendor", "Bonemass", "SunkenCrypt", "Crypt", "MudPile", "BogWitch", "DragonQueen", "MountainCave", "DrakeNest", "FrostCave", "GoblinKing", "TarPit", "Henge", "GoblinCamp", "WoodFarm", "ShipWreck", "SeekerQueen", "InfestedMine", "DvergrTown", "Fader" }; BindToggleAll(config, "MapPin.Ores"); discoveryKeywords = array; foreach (string text3 in discoveryKeywords) { DiscoveryVisibilityEntries[text3] = config.Bind<bool>("MapPin.Ores", text3, true, "Show '" + text3 + "' discovery pins on your minimap. Pins are still created and shared; this only controls local visibility."); } BindToggleAll(config, "MapPin.Locations"); discoveryKeywords = array2; foreach (string text4 in discoveryKeywords) { DiscoveryVisibilityEntries[text4] = config.Bind<bool>("MapPin.Locations", text4, true, "Show '" + text4 + "' discovery pins on your minimap. Pins are still created and shared; this only controls local visibility."); } } private static void BindRadarVisibility(ConfigFile config) { string[] radarKeywords; foreach (PickableCategory pickableCategory in PickableCategories) { string text = "Radar.Pickables." + pickableCategory.CategoryName; BindToggleAll(config, text); radarKeywords = pickableCategory.RadarKeywords; foreach (string text2 in radarKeywords) { RadarVisibilityEntries[text2] = config.Bind<bool>(text, text2, true, "Show '" + text2 + "' radar pins on your minimap. Client-only — never overridden by the server."); } } string[] array = new string[8] { "Copper", "Tin", "Iron", "Silver", "Obsidian", "BlackMarble", "Meteorite", "Flametal" }; string[] array2 = new string[25] { "Eikthyr", "Hildir", "Runestone", "GDKing", "TrollCave", "Vendor", "Bonemass", "SunkenCrypt", "Crypt", "MudPile", "BogWitch", "DragonQueen", "MountainCave", "DrakeNest", "FrostCave", "GoblinKing", "TarPit", "Henge", "GoblinCamp", "WoodFarm", "ShipWreck", "SeekerQueen", "InfestedMine", "DvergrTown", "Fader" }; BindToggleAll(config, "Radar.Ores"); radarKeywords = array; foreach (string text3 in radarKeywords) { RadarVisibilityEntries[text3] = config.Bind<bool>("Radar.Ores", text3, true, "Show '" + text3 + "' radar pins on your minimap. Client-only — never overridden by the server."); } BindToggleAll(config, "Radar.Locations"); radarKeywords = array2; foreach (string text4 in radarKeywords) { RadarVisibilityEntries[text4] = config.Bind<bool>("Radar.Locations", text4, true, "Show '" + text4 + "' radar pins on your minimap. Client-only — never overridden by the server."); } foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { string text5 = "Radar.Critters." + biomeCritterCategory.CategoryName.Replace(" ", "_"); BindToggleAll(config, text5); foreach (var creatureDefinition in biomeCritterCategory.CreatureDefinitions) { string item = creatureDefinition.DisplayName; RadarVisibilityEntries[item] = config.Bind<bool>(text5, item, true, "Show '" + item + "' radar pins on your minimap. Client-only — never overridden by the server."); } } } public static void Reload() { if (OresDiscoveryRadius.Value > 150f) { OresDiscoveryRadius.Value = 150f; } if (OresRadarRadius.Value > 150f) { OresRadarRadius.Value = 150f; } if (LocationsDiscoveryRadius.Value > 150f) { LocationsDiscoveryRadius.Value = 150f; } if (LocationsRadarRadius.Value > 150f) { LocationsRadarRadius.Value = 150f; } foreach (PickableCategory pickableCategory in PickableCategories) { if (pickableCategory.DiscoveryRadiusEntry != null) { if (pickableCategory.DiscoveryRadiusEntry.Value > 150f) { pickableCategory.DiscoveryRadiusEntry.Value = 150f; } if (!UsingServerConfig) { pickableCategory.ActiveDiscoveryRadius = pickableCategory.DiscoveryRadiusEntry.Value; } } if (pickableCategory.RadarRadiusEntry != null) { if (pickableCategory.RadarRadiusEntry.Value > 150f) { pickableCategory.RadarRadiusEntry.Value = 150f; } if (!UsingServerConfig) { pickableCategory.ActiveRadarRadius = pickableCategory.RadarRadiusEntry.Value; } } if (!UsingServerConfig) { if (pickableCategory.TrackedDiscoveryEntry != null) { pickableCategory.DiscoveryKeywords = AutoPinConfig.ParseKeywordList(pickableCategory.TrackedDiscoveryEntry.Value); } if (pickableCategory.TrackedRadarEntry != null) { pickableCategory.RadarKeywords = AutoPinConfig.ParseKeywordList(pickableCategory.TrackedRadarEntry.Value); } } } PickablesDiscovery = PickableCategories.SelectMany((PickableCategory c) => c.DiscoveryKeywords).ToArray(); PickablesRadar = PickableCategories.SelectMany((PickableCategory c) => c.RadarKeywords).ToArray(); if (!UsingServerConfig) { ActiveOresDiscoveryRadius = OresDiscoveryRadius.Value; ActiveOresRadarRadius = OresRadarRadius.Value; OresDiscovery = AutoPinConfig.ParseKeywordList(TrackedOresDiscovery.Value); OresRadar = AutoPinConfig.ParseKeywordList(TrackedOresRadar.Value); ActiveLocationsDiscoveryRadius = LocationsDiscoveryRadius.Value; ActiveLocationsRadarRadius = LocationsRadarRadius.Value; LocationsDiscovery = AutoPinConfig.ParseKeywordList(TrackedLocationsDiscovery.Value); LocationsRadar = AutoPinConfig.ParseKeywordList(TrackedLocationsRadar.Value); } foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { if (biomeCritterCategory.RadarRadiusEntry != null) { if (biomeCritterCategory.RadarRadiusEntry.Value > 150f) { biomeCritterCategory.RadarRadiusEntry.Value = 150f; } if (!UsingServerConfig) { biomeCritterCategory.ActiveRadarRadius = biomeCritterCategory.RadarRadiusEntry.Value; } } if (!UsingServerConfig) { RebuildBiomeCreatureState(biomeCritterCategory); } } WorldObjectPatches.ReScanForKeywordChanges(); } public static void ResetToLocalConfig() { UsingServerConfig = false; Reload(); } private static void RebuildBiomeCreatureState(BiomeCritterCategory cat) { cat.ActiveOrderedCreatures.Clear(); List<string> list = new List<string>(); foreach (var (text, text2, _) in cat.CreatureDefinitions) { if (!string.IsNullOrEmpty(text)) { cat.ActiveOrderedCreatures.Add((text, text2)); list.Add(text2); } } cat.Keywords = list.ToArray(); } public static void PackCategoryData(ZPackage z) { z.Write(PickableCategories.Count); foreach (PickableCategory pickableCategory in PickableCategories) { z.Write(pickableCategory.CategoryName); z.Write(pickableCategory.DiscoveryRadiusEntry?.Value ?? pickableCategory.ActiveDiscoveryRadius); z.Write(pickableCategory.RadarRadiusEntry?.Value ?? pickableCategory.ActiveRadarRadius); z.Write(pickableCategory.TrackedDiscoveryEntry?.Value ?? string.Join(",", pickableCategory.DiscoveryKeywords)); z.Write(pickableCategory.TrackedRadarEntry?.Value ?? string.Join(",", pickableCategory.RadarKeywords)); } z.Write(OresDiscoveryRadius.Value); z.Write(OresRadarRadius.Value); z.Write(TrackedOresDiscovery.Value); z.Write(TrackedOresRadar.Value); z.Write(LocationsDiscoveryRadius.Value); z.Write(LocationsRadarRadius.Value); z.Write(TrackedLocationsDiscovery.Value); z.Write(TrackedLocationsRadar.Value); z.Write(BiomeCritterCategories.Count); foreach (BiomeCritterCategory biomeCritterCategory in BiomeCritterCategories) { z.Write(biomeCritterCategory.CategoryName); z.Write(biomeCritterCategory.RadarRadiusEntry?.Value ?? biomeCritterCategory.ActiveRadarRadius); z.Write(biomeCritterCategory.CreatureDefinitions.Count); foreach (var (text, text2, text3) in biomeCritterCategory.CreatureDefinitions) { z.Write(text2); z.Write(text); z.Write(text3); } } } public static void UnpackCategoryDataIntoEntries(ZPackage z) { int num = z.ReadInt(); for (int i = 0; i < num; i++) { string name2 = z.ReadString(); float value = z.ReadSingle(); float value2 = z.ReadSingle(); string value3 = z.ReadString(); string value4 = z.ReadString(); PickableCategory pickableCategory = PickableCategories.FirstOrDefault((PickableCategory c) => string.Equals(c.CategoryName, name2, StringComparison.OrdinalIgnoreCase)); if (pickableCategory != null) { if (pickableCategory.DiscoveryRadiusEntry != null) { pickableCategory.DiscoveryRadiusEntry.Value = value; } if (pickableCategory.RadarRadiusEntry != null) { pickableCategory.RadarRadiusEntry.Value = value2; } if (pickableCategory.TrackedDiscoveryEntry != null) { pickableCategory.TrackedDiscoveryEntry.Value = value3; } if (pickableCategory.TrackedRadarEntry != null) { pickableCategory.TrackedRadarEntry.Value = value4; } } } OresDiscoveryRadius.Value = z.ReadSingle(); OresRadarRadius.Value = z.ReadSingle(); TrackedOresDiscovery.Value = z.ReadString(); TrackedOresRadar.Value = z.ReadString(); LocationsDiscoveryRadius.Value = z.ReadSingle(); LocationsRadarRadius.Value = z.ReadSingle(); TrackedLocationsDiscovery.Value = z.ReadString(); TrackedLocationsRadar.Value = z.ReadString(); int num2 = z.ReadInt(); for (int j = 0; j < num2; j++) { string name = z.ReadString(); float value5 = z.ReadSingle(); int num3 = z.ReadInt(); for (int k = 0; k < num3; k++) { z.ReadString(); z.ReadString(); z.ReadString(); } BiomeCritterCategory biomeCritterCategory = BiomeCritterCategories.FirstOrDefault((BiomeCritterCategory c) => string.Equals(c.CategoryName, name, StringComparison.OrdinalIgnoreCase)); if (biomeCritterCategory?.RadarRadiusEntry != null) { biomeCritterCategory.RadarRadiusEntry.Value = value5; } } } public static void ApplyCategoryData(ZPackage z) { if (!ModSettings.IsServer()) { UsingServerConfig = true; } int num = z.ReadInt(); PickableCategories.Clear(); for (int i = 0; i < num; i++) { string categoryName = z.ReadString(); float activeDiscoveryRadius = z.ReadSingle(); float activeRadarRadius = z.ReadSingle(); string csv = z.ReadString(); string csv2 = z.ReadString(); PickableCategory item = new PickableCategory { CategoryName = categoryName, ActiveDiscoveryRadius = activeDiscoveryRadius, ActiveRadarRadius = activeRadarRadius, DiscoveryKeywords = AutoPinConfig.ParseKeywordList(csv), RadarKeywords = AutoPinConfig.ParseKeywordList(csv2) }; PickableCategories.Add(item); } PickablesDiscovery = PickableCategories.SelectMany((PickableCategory c) => c.DiscoveryKeywords).ToArray(); PickablesRadar = PickableCategories.SelectMany((PickableCategory c) => c.RadarKeywords).ToArray(); ActiveOresDiscoveryRadius = z.ReadSingle(); ActiveOresRadarRadius = z.ReadSingle(); OresDiscovery = AutoPinConfig.ParseKeywordList(z.ReadString()); OresRadar = AutoPinConfig.ParseKeywordList(z.ReadString()); ActiveLocationsDiscoveryRadius = z.ReadSingle(); ActiveLocationsRadarRadius = z.ReadSingle(); LocationsDiscovery = AutoPinConfig.ParseKeywordList(z.ReadString()); LocationsRadar = AutoPinConfig.ParseKeywordList(z.ReadString()); int num2 = z.ReadInt(); BiomeCritterCategories.Clear(); for (int j = 0; j < num2; j++) { string categoryName2 = z.ReadString(); float activeRadarRadius2 = z.ReadSingle(); BiomeCritterCategory biomeCritterCategory = new BiomeCritterCategory { CategoryName = categoryName2, ActiveRadarRadius = activeRadarRadius2 }; int num3 = z.ReadInt(); for (int k = 0; k < num3; k++) { string item2 = z.ReadString(); string text = z.ReadString(); string item3 = z.ReadString(); biomeCritterCategory.CreatureDefinitions.Add((text, item2, item3)); if (!string.IsNullOrEmpty(text)) { biomeCritterCategory.ActiveOrderedCreatures.Add((text, item2)); } } biomeCritterCategory.Keywords = biomeCritterCategory.ActiveOrderedCreatures.Select(((string InternalId, string DisplayName) x) => x.DisplayName).ToArray(); BiomeCritterCategories.Add(biomeCritterCategory); } EnsureVisibilityEntries(); WorldObjectPatches.ReScanForKeywordChanges(); } private static void LoadCreaturesFile(string path) { BiomeCritterCategories.Clear(); Dictionary<string, BiomeCritterCategory> dictionary = new Dictionary<string, BiomeCritterCategory>(StringComparer.OrdinalIgnoreCase); List<string> list = new List<string>(); string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (string.IsNullOrEmpty(text) || text.StartsWith("#")) { continue; } string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length < 3) { continue; } string text2 = array2[0].Trim(); string text3 = array2[1].Trim(); string text4 = array2[2].Trim(); string item = ((array2.Length >= 4) ? array2[3].Trim() : text4); if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(text3) && !string.IsNullOrEmpty(text4)) { string item2 = DeriveMatchKeyword(text4); if (!dictionary.TryGetValue(text2, out var value)) { value = (dictionary[text2] = new BiomeCritterCategory { CategoryName = text2 }); list.Add(text2); } value.CreatureDefinitions.Add((item2, text3, item)); } } foreach (string item3 in list) { BiomeCritterCategories.Add(dictionary[item3]); } } private static void WriteDefaultCreaturesFile(string path) { File.WriteAllText(path, "# OneMapToRuleThemAll — Creature Definitions\n# Format: category:displayname:internalname[:iconoverride]\n#\n# internalname = used to derive the match keyword ('Trophy' prefix stripped if present).\n# iconoverride = optional 4th field; ObjectDB item name for the icon when the creature\n# has no trophy. If omitted, internalname is also used for the icon lookup.\n# Matching is normalized (case-insensitive, underscores/spaces ignored), so\n# 'GreydwarfShaman' matches the game object 'Greydwarf_Shaman'.\n#\n# ORDER MATTERS: more-specific entries must appear before less-specific ones within\n# and across categories. Bosses and Minibosses are listed first so their specific\n# prefab names are checked before generic biome keywords.\n#\n# Radar radius per category is configured in One_Map_To_Rule_Them_All_Settings.cfg\n# under [Critters.<CategoryName>] RadarRadius.\n\n# ── Bosses ────────────────────────────────────────────────────────────────────\nBosses:Eikthyr:TrophyEikthyr\nBosses:The Elder:TrophyTheElder\nBosses:Bonemass:TrophyBonemass\nBosses:Moder:TrophyDragonQueen\nBosses:Yagluth:TrophyGoblinKing\nBosses:The Queen:TrophySeekerQueen\nBosses:Fader:TrophyFader\n\n# ── Minibosses ────────────────────────────────────────────────────────────────\n# Listed before biome categories so specific prefab names match before generic ones.\n# e.g. GoblinBruteBros must match before GoblinBrute (Fuling Berserker).\nMinibosses:Brenna:TrophySkeletonHildir\nMinibosses:Geirrhafa:TrophyCultist_Hildir\nMinibosses:Zil & Thungr:GoblinBruteBros\nMinibosses:Lord Reto:Charred_Melee_Dyrnwyn\n\n# ── Meadows ───────────────────────────────────────────────────────────────────\nMeadows:Deer:TrophyDeer\nMeadows:Boar:TrophyBoar\nMeadows:Neck:TrophyNeck\nMeadows:Greyling:Greyling:TrophyGreydwarf\n\n# ── Black Forest ──────────────────────────────────────────────────────────────\n# Category name 'BlackForest' (no space) matches the existing config section [Critters.BlackForest].\n# Greydwarf shaman must appear before Greydwarf (shaman's keyword is a substring check).\n# Rancid remains (SkeletonPoison) must appear before Skeleton.\nBlackForest:Greydwarf shaman:TrophyGreydwarfShaman\nBlackForest:Greydwarf:TrophyGreydwarf\nBlackForest:Rancid remains:TrophySkeletonPoison\nBlackForest:Skeleton:TrophySkeleton\nBlackForest:Troll:TrophyFrostTroll\nBlackForest:Ghost:TrophyGhost\nBlackForest:Bear:TrophyBjorn\n\n# ── Swamp ─────────────────────────────────────────────────────────────────────\n# Oozer (BlobElite) before Blob. Draugr elite before Draugr.\nSwamp:Abomination:TrophyAbomination\nSwamp:Oozer:BlobElite\nSwamp:Blob:TrophyBlob\nSwamp:Draugr elite:TrophyDraugrElite\nSwamp:Draugr:TrophyDraugr\nSwamp:Leech:TrophyLeech\nSwamp:Leech (cave variant):TrophyLeech\nSwamp:Surtling:TrophySurtling\nSwamp:Wraith:TrophyWraith\n\n# ── Mountain ──────────────────────────────────────────────────────────────────\n# Cultist (Fenring_Cultist) must appear before Fenring.\nMountain:Wolf:TrophyWolf\nMountain:Drake:TrophyHatchling\nMountain:Stone Golem:TrophySGolem\nMountain:Cultist:TrophyCultist\nMountain:Fenring:TrophyFenring\nMountain:Ulv:TrophyUlv\n\n# ── Plains ────────────────────────────────────────────────────────────────────\n# Fuling Berserker and Fuling shaman must appear before generic Fuling (Goblin).\nPlains:Fuling Berserker:TrophyGoblinBrute\nPlains:Fuling shaman:TrophyGoblinShaman\nPlains:Fuling:TrophyGoblin\nPlains:Deathsquito:TrophyDeathsquito\nPlains:Lox:TrophyLox\nPlains:Growth:TrophyGrowth\nPlains:Vile:TrophyBjornUndead\n\n# ── Mistlands ─────────────────────────────────────────────────────────────────\n# Seeker Soldier and Seeker Brood must appear before generic Seeker.\n# All Dvergr entries derive the same match keyword; first listed wins for all variants.\nMistlands:Seeker Soldier:TrophySeekerBrute\nMistlands:Seeker Brood:SeekerBrood\nMistlands:Seeker:TrophySeeker\nMistlands:Gjall:TrophyGjall\nMistlands:Tick:TrophyTick\nMistlands:Dvergr mage (Fire Variant):TrophyDvergr\nMistlands:Dvergr mage (Ice Variant):TrophyDvergr\nMistlands:Dvergr mage (Support Variant):TrophyDvergr\nMistlands:Dvergr mage:TrophyDvergr\nMistlands:Dvergr rogue:TrophyDvergr\nMistlands:Hare:TrophyHare\n\n# ── Ashlands ──────────────────────────────────────────────────────────────────\n# Category name 'AshLands' matches the existing config section [Critters.AshLands].\n# Specific Charred variants before any generic 'Charred' entry.\nAshLands:Charred Warlock:TrophyCharredMage\nAshLands:Charred Warrior:TrophyCharredMelee\nAshLands:Charred Marksman:TrophyCharredArcher\nAshLands:Charred Twitcher:Charred_Twitcher\nAshLands:Bonemaw:TrophyBonemawSerpent\nAshLands:Lava Blob:BlobLava\nAshLands:Fallen Valkyrie:TrophyFallenValkyrie\nAshLands:Volture:TrophyVolture\nAshLands:Morgen:TrophyMorgen\nAshLands:Asksvin:TrophyAsksvin\n# Skugg: icon is a building piece; if Skugg is not detected, check its in-game prefab name.\nAshLands:Skugg:piece_Charred_Balista\n\n# ── Ocean ─────────────────────────────────────────────────────────────────────\n# Fish10-12 must appear before Fish1 (Fish10 contains 'Fish1' as a substring).\nOcean:Northern salmon:Fish10\nOcean:Magmafish:Fish11\nOcean:Pufferfish:Fish12\nOcean:Perch:Fish1\nOcean:Pike:Fish2\nOcean:Tuna:Fish3\nOcean:Tetra:Fish4_cave\nOcean:Trollfish:Fish5\nOcean:Giant herring:Fish6\nOcean:Grouper:Fish7\nOcean:Coral cod:Fish8\nOcean:Anglerfish:Fish9\nOcean:Serpent:TrophySerpent\nOcean:Leviathan:Leviathan\n\n# ── General ───────────────────────────────────────────────────────────────────\nGeneral:Chicken:Chicken\nGeneral:Hen:Hen\n"); } } public static class AutoPinConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<float> QuantitySearchRadius; public static bool ActiveEnabled; public static float ActiveQuantitySearchRadius; public static bool UsingServerConfig = false; private static readonly Dictionary<string, ConfigEntry<string>> AbbreviationEntries = new Dictionary<string, ConfigEntry<string>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, string> Abbreviations = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public static ConfigEntry<bool> DiscoveryPinObjectIcon; public static ConfigEntry<bool> DiscoveryPinText; public static void Bind(ConfigFile serverConfig, ConfigFile clientConfig) { WorldObjectConfig.Bind(serverConfig, clientConfig); DiscoveryPinObjectIcon = clientConfig.Bind<bool>("Client", "DiscoveryPinObjectIcon", true, "Replace the standard pin icon on discovery pins with the item sprite from ObjectDB. Client-only — does not affect other players."); DiscoveryPinText = clientConfig.Bind<bool>("Client", "DiscoveryPinText", true, "Show the abbreviation label on auto-discovery pins. Set to false to show only the pin icon. Client-only — does not affect other players."); Enabled = serverConfig.Bind<bool>("Discovery", "Enabled", true, "Master switch for the automatic discovery pin system."); QuantitySearchRadius = serverConfig.Bind<float>("Discovery", "QuantitySearchRadius", 16f, "Radius (centered on the discovered object) searched for nearby objects of the same type. The count is appended to the pin label, e.g. 'RB 4'. Also defines the cluster boundary — objects within this radius share one pin. Keep larger than the per-category DiscoveryRadius."); BindAbbreviations(serverConfig); serverConfig.SettingChanged += delegate { if (WorldObjectConfig.UsingServerConfig) { PushDiscoveryConfigToServer(); } else { Reload(); } }; clientConfig.SettingChanged += delegate { Reload(); }; Reload(); } private static void BindAbbreviations(ConfigFile serverConfig) { (string, string)[] array = new(string, string)[97] { ("Raspberry", "Rb"), ("Blueberry", "Bb"), ("Mushroom", "Mu"), ("Thistle", "Th"), ("Cloudberry", "Cb"), ("Barley", "Br"), ("Flax", "Fl"), ("Onion", "On"), ("Carrot", "Ca"), ("Turnip", "Tu"), ("Chitin", "Ch"), ("Crystal", "Cr"), ("SurtlingCore", "Su"), ("BlackCore", "Bc"), ("JotunPuff", "JP"), ("Magecap", "Mc"), ("Dandelion", "Dan"), ("Flint", "Fli"), ("Copper", "Cu"), ("Tin", "Sn"), ("Silver", "Ag"), ("Iron", "Fe"), ("Obsidian", "Ob"), ("Flametal", "Fm"), ("Meteorite", "Met"), ("BlackMarble", "BkM"), ("SunkenCrypt", "SCrypt"), ("Crypt", "Crypt"), ("MountainCave", "MCave"), ("TrollCave", "TCave"), ("MudPile", "Mud"), ("Vendor", "Shop"), ("DrakeNest", "DNest"), ("TarPit", "Tar"), ("Henge", "Henge"), ("Eikthyr", "Eik"), ("GDKing", "Elder"), ("Bonemass", "Bone"), ("DragonQueen", "Moder"), ("GoblinKing", "Yag"), ("SeekerQueen", "Queen"), ("Fader", "Fader"), ("FrostCave", "FCave"), ("InfestedMine", "IMine"), ("Hildir", "Hild"), ("BogWitch", "Witch"), ("GoblinCamp", "GCamp"), ("WoodFarm", "WFarm"), ("DvergrTown", "Dtown"), ("ShipWreck", "Ship"), ("Runestone", "Rune"), ("Beehive", "BHive"), ("Greyling", "Grl"), ("Boar", "Boar"), ("Deer", "Deer"), ("Neck", "Neck"), ("Chicken", "Hen"), ("Hare", "Hare"), ("GreydwarfElite", "GdwE"), ("GreydwarfShaman", "GdwS"), ("Greydwarf", "Gdw"), ("Troll", "Trl"), ("Skeleton", "Skel"), ("DraugrElite", "DrE"), ("Draugr", "Dr"), ("Leech", "Lch"), ("Blob", "Blob"), ("Wraith", "Wra"), ("Surtling", "Srt"), ("Abomination", "Abom"), ("Ghost", "Gst"), ("Wolf", "Wolf"), ("Drake", "Drk"), ("StoneGolem", "Glm"), ("Fenring", "Fen"), ("Cultist", "Cult"), ("Bat", "Bat"), ("FulingBerserker", "FulB"), ("FulingShaman", "FulS"), ("FulingArcher", "FulA"), ("Fuling", "Ful"), ("Deathsquito", "Dsq"), ("Lox", "Lox"), ("SeekerBrood", "SkrB"), ("Seeker", "Skr"), ("Gjall", "Gjl"), ("Tick", "Tick"), ("DvergrMage", "DvrM"), ("Dvergr", "Dvr"), ("Ulv", "Ulv"), ("Charred", "Chr"), ("Morgen", "Mrg"), ("Asksvin", "Ask"), ("Volture", "Vlt"), ("Serpent", "Spt"), ("Leviathan", "Lev"), ("Fish", "Fish") }; for (int i = 0; i < array.Length; i++) { (string, string) tuple = array[i]; string item = tuple.Item1; string item2 = tuple.Item2; ConfigEntry<string> value = serverConfig.Bind<string>("Discovery.Abbreviations", item, item2, "Pin-label abbreviation used when a '" + item + "' object is discovered."); AbbreviationEntries[item] = value; } } public static string GetKeywordForLabel(string pinLabel) { foreach (KeyValuePair<string, string> abbreviation in Abbreviations) { string value = abbreviation.Value; if (string.Equals(pinLabel, value, StringComparison.OrdinalIgnoreCase) || pinLabel.StartsWith(value + " ", StringComparison.OrdinalIgnoreCase)) { return abbreviation.Key; } } return null; } public static void ApplyDiscoveryIcon(PinData mmPin, string keyword) { if (mmPin != null && DiscoveryPinObjectIcon.Value && RadarIconLoader.TryGetIcon(keyword, out var sprite)) { mmPin.m_icon = sprite; } } public static void Reload() { if (QuantitySearchRadius.Value > 150f) { QuantitySearchRadius.Value = 150f; } WorldObjectConfig.Reload(); if (!UsingServerConfig) { ActiveEnabled = Enabled.Value; ActiveQuantitySearchRadius = QuantitySearchRadius.Value; Abbreviations.Clear(); foreach (KeyValuePair<string, ConfigEntry<string>> abbreviationEntry in AbbreviationEntries) { Abbreviations[abbreviationEntry.Key] = abbreviationEntry.Value.Value; } } if (!ModSettings.ModActive || !ModSettings.IsServer() || !((Object)(object)ZNetProxy.ZNetInstance != (Object)null) || !(Traverse.Create((object)ZNetProxy.ZNetInstance).Field("m_peers").GetValue() is List<ZNetPeer> list)) { return; } foreach (ZNetPeer item in list) { if (item.IsReady()) { item.m_rpc.Invoke("OM_ServerDiscoveryConfig", new object[1] { PackDiscoveryConfig() }); } } } public static string GetAbbreviation(string keyword) { if (Abbreviations.TryGetValue(keyword, out var value) && !string.IsNullOrWhiteSpace(value)) { return value; } if (keyword.Length <= 6) { return keyword; } return keyword.Substring(0, 6); } public static string MatchKeyword(string objectName, string[] keywords) { foreach (string text in keywords) { if (objectName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { return text; } } return null; } internal static string[] ParseKeywordList(string csv) { return (from s in csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim() into s where s.Length > 0 select s).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray(); } public static ZPackage PackDiscoveryConfig() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(Enabled.Value); val.Write(QuantitySearchRadius.Value); WorldObjectConfig.PackCategoryData(val); val.Write(AbbreviationEntries.Count); foreach (KeyValuePair<string, ConfigEntry<string>> abbreviationEntry in AbbreviationEntries) { val.Write(abbreviationEntry.Key); val.Write(abbreviationEntry.Value.Value); } val.SetPos(0); return val; } private static void PushDiscoveryConfigToServer() { ZRpc serverRPC = ZNetProxy.GetServerRPC(ZNetProxy.ZNetInstance); if (serverRPC != null) { serverRPC.Invoke("OM_AdminUpdateDiscoveryConfig", new object[1] { PackDiscoveryConfig() }); } } public static void ApplyPackedConfigToEntries(ZPackage z) { Enabled.Value = z.ReadBool(); QuantitySearchRadius.Value = z.ReadSingle(); WorldObjectConfig.UnpackCategoryDataIntoEntries(z); int num = z.ReadInt(); for (int i = 0; i < num; i++) { string key = z.ReadString(); string value = z.ReadString(); if (AbbreviationEntries.TryGetValue(key, out var value2)) { value2.Value = value; } } } public static void OnServerDiscoveryConfig(ZRpc rpc, ZPackage z) { z.SetPos(0); if (!ModSettings.IsServer()) { UsingServerConfig = true; } ActiveEnabled = z.ReadBool(); ActiveQuantitySearchRadius = z.ReadSingle(); WorldObjectConfig.ApplyCategoryData(z); int num = z.ReadInt(); Abbreviations.Clear(); for (int i = 0; i < num; i++) { Abbreviations[z.ReadString()] = z.ReadString(); } } public static void ResetToLocalConfig() { UsingServerConfig = false; WorldObjectConfig.ResetToLocalConfig(); Reload(); } } public class ProximityWatcher : MonoBehaviour { private string _keyword; private float _detectionRadius; private bool _inRange; public string Keyword => _keyword; public void Initialize(string keyword, float detectionRadius) { _keyword = keyword; _detectionRadius = detectionRadius; } private void Update() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if (!ModSettings.ModActive || !AutoPinConfig.ActiveEnabled) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Vector3 val = ((Component)localPlayer).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude > _detectionRadius * _detectionRadius) { _inRange = false; } else { if (_inRange || !MapStateRepository.InitialPinsReceived) { return; } _inRange = true; SharedPin sharedPin = AutoPinPlacer.FindNearbyPin(((Component)this).transform.position, _keyword); int num = AutoPinPlacer.CountNearbyObjects(sharedPin?.Pos ?? ((Component)this).transform.position, _keyword, AutoPinConfig.ActiveQuantitySearchRadius); string abbreviation = AutoPinConfig.GetAbbreviation(_keyword); string text = ((num > 1) ? $"{abbreviation} {num}" : abbreviation); if (sharedPin != null) { if (sharedPin.Name != text) { AutoPinPlacer.UpdateDiscoveryPin(sharedPin, text, _keyword); } } else { AutoPinPlacer.PlaceDiscoveryPin(((Component)this).transform.position, text, _keyword); } } } } public static class AutoPinPlacer { private static readonly Collider[] _overlapBuffer = (Collider[])(object)new Collider[512]; public static SharedPin FindNearbyPin(Vector3 position, string keyword) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) float activeQuantitySearchRadius = AutoPinConfig.ActiveQuantitySearchRadius; string abbreviation = AutoPinConfig.GetAbbreviation(keyword); SharedPin result = null; float num = float.MaxValue; foreach (SharedPin clientPin in MapStateRepository.ClientPins) { if (LabelMatchesAbbreviation(clientPin.Name, abbreviation)) { float num2 = Vector3.Distance(clientPin.Pos, position); if (num2 < activeQuantitySearchRadius && num2 < num) { result = clientPin; num = num2; } } } return result; } public static void UpdateDiscoveryPin(SharedPin existing, string newLabel, string keyword) { //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (ModSettings.ModActive) { if ((Object)(object)MinimapProxy.Instance != (Object)null) { PinData val = (Traverse.Create((object)MinimapProxy.Instance).Field("m_pins").GetValue() as List<PinData>)?.FirstOrDefault((Func<PinData, bool>)((PinData p) => MapStateRepository.ArePinsEqual(existing, p))); if (val != null) { Traverse.Create((object)MinimapProxy.Instance).Method("RemovePin", new object[1] { val }).GetValue(); } } MapPinSynchronizer.RemovePinFromServer(existing); } else { MapStateRepository.ClientPins.Remove(existing); if ((Object)(object)MinimapProxy.Instance != (Object)null) { PinData val2 = (Traverse.Create((object)MinimapProxy.Instance).Field("m_pins").GetValue() as List<PinData>)?.FirstOrDefault((Func<PinData, bool>)((PinData p) => MapStateRepository.ArePinsEqual(existing, p))); if (val2 != null) { Traverse.Create((object)MinimapProxy.Instance).Method("RemovePin", new object[1] { val2 }).GetValue(); } } } PlaceDiscoveryPin(existing.Pos, newLabel, keyword); } public static int CountNearbyObjects(Vector3 origin, string keyword, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) string internalIdForCreature = WorldObjectConfig.GetInternalIdForCreature(keyword); int num = Physics.OverlapSphereNonAlloc(origin, radius, _overlapBuffer); HashSet<GameObject> hashSet = new HashSet<GameObject>(); for (int i = 0; i < num; i++) { GameObject gameObject = ((Component)((Component)_overlapBuffer[i]).transform.root).gameObject; if (((Object)gameObject).name.IndexOf(internalIdForCreature, StringComparison.OrdinalIgnoreCase) >= 0) { hashSet.Add(gameObject); } } return Mathf.Max(1, hashSet.Count); } public static void PlaceDiscoveryPin(Vector3 position, string label, string keyword) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_00c4: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MinimapProxy.Instance == (Object)null) { return; } bool flag = WorldObjectConfig.IsKeywordDiscoveryVisible(keyword); if (ModSettings.ModActive) { MapPinSynchronizer.SendPinToServer(new PinData { m_name = label, m_pos = position, m_type = (PinType)3, m_checked = false, m_ownerID = 0L }, isDiscovery: true); if (flag) { AutoPinConfig.ApplyDiscoveryIcon(MinimapProxy.AddPin(MinimapProxy.Instance, position, (PinType)3, AutoPinConfig.DiscoveryPinText.Value ? label : "", save: false, isChecked: false, 0L, new PlatformUserID("")), keyword); } } else { MapStateRepository.ClientPins.Add(new SharedPin { Name = label, Pos = position, Type = (PinType)3, Checked = false, OwnerId = "auto" }); if (flag) { AutoPinConfig.ApplyDiscoveryIcon(MinimapProxy.AddPin(MinimapProxy.Instance, position, (PinType)3, AutoPinConfig.DiscoveryPinText.Value ? label : "", save: true, isChecked: false, 0L, new PlatformUserID("")), keyword); } } } public static void SetNearbyPinChecked(Vector3 position, string keyword, bool state) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) SharedPin pin = FindNearbyPin(position, keyword); if (pin == null || pin.Checked == state) { return; } pin.Checked = state; if ((Object)(object)MinimapProxy.Instance != (Object)null) { PinData val = (Traverse.Create((object)MinimapProxy.Instance).Field("m_pins").GetValue() as List<PinData>)?.FirstOrDefault((Func<PinData, bool>)((PinData p) => MapStateRepository.ArePinsEqual(pin, p))); if (val != null) { val.m_checked = state; } } MapPinSynchronizer.CheckPinOnServer(pin, state); } private static bool LabelMatchesAbbreviation(string pinLabel, string abbr) { if (!string.Equals(pinLabel, abbr, StringComparison.OrdinalIgnoreCase)) { return pinLabel.StartsWith(abbr + " ", StringComparison.OrdinalIgnoreCase); } return true; } } public static class WorldObjectPatches { [HarmonyPatch(typeof(ObjectDB), "Awake")] private class ObjectDBAwakeHook { private static void Postfix(ObjectDB __instance) { RadarIconLoader.LoadAll(__instance); } } [HarmonyPatch(typeof(Pickable), "Awake")] private class PickableAwakeHook { private static void Postfix(Pickable __instance) { if (__instance.CanBePicked()) { string text = AutoPinConfig.MatchKeyword(((Object)__instance).name, WorldObjectConfig.PickablesDiscovery); string text2 = AutoPinConfig.MatchKeyword(((Object)__instance).name, WorldObjectConfig.PickablesRadar); if (text != null || text2 != null) { AttachTrackers(((Component)__instance).gameObject, text, text2, WorldObjectConfig.GetPickableDiscoveryRadius(text ?? text2)); } } } } [HarmonyPatch(typeof(Pickable), "SetPicked")] private class PickableSetPickedHook { private static void Postfix(Pickable __instance, bool picked) { //IL_0085: 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) string text = AutoPinConfig.MatchKeyword(((Object)__instance).name, WorldObjectConfig.PickablesDiscovery); string text2 = AutoPinConfig.MatchKeyword(((Object)__instance).name, WorldObjectConfig.PickablesRadar); if (text == null && text2 == null) { return; } if (picked) { ProximityWatcher component = ((Component)__instance).GetComponent<ProximityWatcher>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } RadarPinComponent component2 = ((Component)__instance).GetComponent<RadarPinComponent>(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } if (text != null && AutoPinConfig.ActiveEnabled) { AutoPinPlacer.SetNearbyPinChecked(((Component)__instance).transform.position, text, state: true); } } else { if (text != null && AutoPinConfig.ActiveEnabled) { AutoPinPlacer.SetNearbyPinChecked(((Component)__instance).transform.position, text, state: false); } AttachTrackers(((Component)__instance).gameObject, text, text2, WorldObjectConfig.GetPickableDiscoveryRadius(text ?? text2)); } } } [HarmonyPatch(typeof(Destructible), "Awake")] private class DestructibleAwakeHook { private static void Postfix(Destructible __instance) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) string text = AutoPinConfig.MatchKeyword(((Object)__instance).name, WorldObjectConfig.OresDiscovery); string text2 = AutoPinConfig.MatchKeyword(((Object)__instance).name, WorldObjectConfig.OresRadar); if (text != null || text2 != null) { if (text != null && AutoPinConfig.ActiveEnabled) { AutoPinPlacer.SetNearbyPinChecked(((Component)__instance).transform.position, text, state: false); } AttachTrackers(((Component)__instance).gameObject, text, text2, WorldObjectConfig.ActiveOresDiscoveryRadius); } } } [HarmonyPatch(typeof(Destructible), "Destroy")] private class D