Decompiled source of Auto Mapping v1.1.4

QuietMap.dll

Decompiled 13 hours ago
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.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OctoberJemini.QuietMap
{
	[BepInPlugin("OctoberJemini.QuietMap", "Auto Mapping", "1.1.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
		private static class ExplorationScopePatch
		{
			private static void Prefix(Player __1)
			{
				if ((Object)(object)Instance != (Object)null)
				{
					Instance.localExploration = Object.op_Implicit((Object)(object)__1) && (Object)(object)__1 == (Object)(object)Player.m_localPlayer;
				}
			}

			private static void Finalizer()
			{
				if ((Object)(object)Instance != (Object)null)
				{
					Instance.localExploration = false;
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
		{
			typeof(Vector3),
			typeof(float)
		})]
		private static class ExplorationRadiusPatch
		{
			private static void Postfix(float __1)
			{
				Plugin instance = Instance;
				if ((Object)(object)instance != (Object)null && instance.localExploration && __1 > 0f && !float.IsNaN(__1) && !float.IsInfinity(__1))
				{
					instance.effectiveRadius = __1;
				}
			}
		}

		private sealed class Pin
		{
			public PinData Data;

			public List<string> Keys;

			public string Kind;

			public bool Borrowed;
		}

		[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
		private static class PortalDestroyedPatch
		{
			private static void Postfix(ZDOID __0)
			{
				//IL_0048: 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_00af: Unknown result type (might be due to invalid IL or missing references)
				Plugin instance = Instance;
				if ((Object)(object)instance == (Object)null || !instance.ready || instance.loadFailed || instance.session == null)
				{
					return;
				}
				try
				{
					if ((ZDOMan.instance == null || ZDOMan.instance.GetZDO(__0) == null) && instance.records.TryGetValue(Key(__0), out var value) && !(value.Kind != "Portal"))
					{
						value.Available = false;
						instance.missing.Remove(value.Key);
						instance.dirty = true;
						if (Object.op_Implicit((Object)(object)instance.map) && Object.op_Implicit((Object)(object)Player.m_localPlayer))
						{
							instance.Render(((Component)Player.m_localPlayer).transform.position);
						}
						instance.Save();
					}
				}
				catch (Exception e)
				{
					instance.Warn("destroyed portal marker", e);
				}
			}
		}

		[HarmonyPatch(typeof(TeleportWorld), "Interact")]
		private static class PortalInteractPatch
		{
			private static void Postfix(TeleportWorld __instance, Humanoid __0, bool __1)
			{
				if (!__1)
				{
					Instance?.PortalInteraction(__instance, __0);
				}
			}
		}

		[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
		private static class PortalUsePatch
		{
			private static void Prefix(TeleportWorld __instance, Player __0)
			{
				Instance?.PortalInteraction(__instance, (Humanoid)(object)__0);
			}
		}

		[HarmonyPatch(typeof(TeleportWorld), "SetText")]
		private static class PortalRenamePatch
		{
			private static void Postfix(TeleportWorld __instance)
			{
				Instance?.PortalInteraction(__instance, (Humanoid)(object)Player.m_localPlayer);
			}
		}

		[HarmonyPatch(typeof(Teleport), "Interact")]
		private static class DungeonEntryPatch
		{
			private static void Postfix(Teleport __instance, Humanoid __0, bool __result)
			{
				Instance?.EnterDungeon(__instance, __0, __result);
			}
		}

		[HarmonyPatch(typeof(Minimap), "UpdatePins")]
		private static class StylePatch
		{
			private static void Postfix()
			{
				if ((Object)(object)Instance != (Object)null && Instance.ready)
				{
					Instance.Style();
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })]
		private static class RemovePatch
		{
			private static void Prefix(PinData __0)
			{
				Plugin instance = Instance;
				if ((Object)(object)instance == (Object)null || instance.internalRemove)
				{
					return;
				}
				Pin pin = instance.pins.Values.FirstOrDefault((Pin p) => p.Data == __0);
				if (pin == null || pin.Borrowed)
				{
					return;
				}
				foreach (string key in pin.Keys)
				{
					if (instance.records.TryGetValue(key, out var value))
					{
						value.Deleted = true;
						instance.dirty = true;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "SaveMapData")]
		private static class SavePatch
		{
			private static void Prefix()
			{
				Instance?.Save();
			}
		}

		public const string Guid = "OctoberJemini.QuietMap";

		internal static Plugin Instance;

		private ConfigEntry<bool> enabledSetting;

		private ConfigEntry<bool> dungeons;

		private ConfigEntry<bool> portals;

		private ConfigEntry<bool> markVisited;

		private ConfigEntry<float> portalScale;

		private ConfigEntry<float> landmarkScale;

		private ConfigEntry<float> visitedOpacity;

		private ConfigEntry<string> extraDungeons;

		private readonly Dictionary<string, Record> records = new Dictionary<string, Record>();

		private readonly Dictionary<string, Pin> pins = new Dictionary<string, Pin>();

		private readonly Dictionary<string, int> missing = new Dictionary<string, int>();

		private readonly HashSet<string> warned = new HashSet<string>();

		private readonly HashSet<string> insideLocations = new HashSet<string>();

		private static readonly FieldInfo Instances = AccessTools.Field(typeof(ZNetScene), "m_instances");

		private static readonly FieldInfo Locations = AccessTools.Field(typeof(Location), "s_allLocations");

		private static readonly FieldInfo GamePins = AccessTools.Field(typeof(Minimap), "m_pins");

		private static readonly FieldInfo LocationPins = AccessTools.Field(typeof(Minimap), "m_locationPins");

		private readonly HashSet<PinData> vendorPins = new HashSet<PinData>();

		private readonly Dictionary<Transform, Vector3> nativeScales = new Dictionary<Transform, Vector3>();

		private float nextLandmarkCheck;

		private static readonly MethodInfo MapData = AccessTools.Method(typeof(Minimap), "GetMapData", (Type[])null, (Type[])null);

		private Harmony harmony;

		private string session;

		private string path;

		private Minimap map;

		private float nextTick;

		private float nextSave;

		private float effectiveRadius;

		private bool localExploration;

		private bool dirty;

		private bool internalRemove;

		private bool ready;

		private bool loadFailed;

		private float DiscoveryRadius
		{
			get
			{
				if (!(effectiveRadius > 0f))
				{
					if (!Object.op_Implicit((Object)(object)map))
					{
						return 0f;
					}
					return map.m_exploreRadius;
				}
				return effectiveRadius;
			}
		}

		private static bool WithinDiscovery(Vector3 point, Vector3 player, float distance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			if (Character.InInterior(point) != Character.InInterior(player))
			{
				return false;
			}
			float num = point.x - player.x;
			float num2 = point.z - player.z;
			if (distance > 0f)
			{
				return num * num + num2 * num2 <= distance * distance;
			}
			return false;
		}

		public void Awake()
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			Instance = this;
			enabledSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Automatically maintain discovered map markers. No other map mod is required.");
			dungeons = ((BaseUnityPlugin)this).Config.Bind<bool>("Tracking", "Dungeons", true, "Pin encountered dungeons, outdoor landmarks and More World Locations POIs. No resource scans.");
			portals = ((BaseUnityPlugin)this).Config.Bind<bool>("Tracking", "Portals", true, "Automatically pin placed or discovered portals, update their tag, and remove destroyed portals.");
			markVisited = ((BaseUnityPlugin)this).Config.Bind<bool>("Tracking", "Cross off visited locations", true, "Apply the normal map X when entering a dungeon or outdoor landmark. Visited, not fully looted. Portals, bosses, traders and ports are not auto-crossed.");
			visitedOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "Visited pin opacity", 0.4f, new ConfigDescription("Opacity of crossed-out location icons and labels; the X stays visible.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
			portalScale = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "Portal icon scale", 0.85f, new ConfigDescription("Size of the game's familiar portal symbol.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.4f, 1.5f), Array.Empty<object>()));
			landmarkScale = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "Boss and vendor icon scale", 1f, new ConfigDescription("Final icon size relative to a standard map pin, compensating for oversized vanilla markers. Default is slightly larger than Quiet Map's 0.85 portal icons. Artwork and pin labels are preserved.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1.5f), Array.Empty<object>()));
			extraDungeons = ((BaseUnityPlugin)this).Config.Bind<string>("Additional objects", "Dungeon prefabs", "", "Comma-separated location prefab names to recognize as dungeons.");
			string[] array = new string[3] { "digi.valheim.automappins", "com.noodle.autopoi", "com.oathorse.DWMP" };
			foreach (string text in array)
			{
				if (Chainloader.PluginInfos.ContainsKey(text))
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Quiet Map inactive to prevent duplicate pins. Disable " + text + " and restart."));
					return;
				}
			}
			try
			{
				if (Instances == null || Locations == null || GamePins == null)
				{
					throw new MissingMemberException("Game map/object tracking API changed");
				}
				harmony = new Harmony("OctoberJemini.QuietMap");
				harmony.PatchAll(typeof(Plugin).Assembly);
				ready = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto Mapping landmark mode ready. No chest, ore, pickup or dungeon-loot scanning.");
			}
			catch (Exception ex)
			{
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				((BaseUnityPlugin)this).Logger.LogError((object)("Quiet Map inactive: " + ex));
			}
		}

		private static string Clean(string name)
		{
			return (name ?? "").Replace("(Clone)", "").Trim();
		}

		private static string Key(ZDOID id)
		{
			return "z:" + ((ZDOID)(ref id)).UserID.ToString(CultureInfo.InvariantCulture) + ":" + ((ZDOID)(ref id)).ID.ToString(CultureInfo.InvariantCulture);
		}

		private static Vector3 Position(Record r)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(r.X, r.Y, r.Z);
		}

		private static bool Extra(ConfigEntry<string> entry, string name)
		{
			return entry.Value.Split(',').Any((string s) => string.Equals(s.Trim(), name, StringComparison.OrdinalIgnoreCase));
		}

		private static string Display(string raw)
		{
			if (string.IsNullOrEmpty(raw))
			{
				return "Unknown";
			}
			string text = ((Localization.instance != null) ? Localization.instance.Localize(raw) : raw);
			if (!text.StartsWith("$"))
			{
				return text;
			}
			return Regex.Replace(text.TrimStart('$').Replace("piece_", "").Replace("item_", "")
				.Replace('_', ' '), "([a-z])([A-Z])", "$1 $2");
		}

		private static string Readable(string raw)
		{
			return Regex.Replace(Clean(raw).Replace('_', ' '), "([a-z])([A-Z])", "$1 $2");
		}

		private static string DungeonName(string raw)
		{
			string text = raw.ToLowerInvariant();
			if (text.StartsWith("sunkencrypt"))
			{
				return "Sunken Crypt";
			}
			if (text.StartsWith("crypt"))
			{
				return "Burial Chambers";
			}
			if (text.StartsWith("trollcave"))
			{
				return "Troll Cave";
			}
			if (text.StartsWith("mountaincave"))
			{
				return "Frost Cave";
			}
			if (text.Contains("dvergrtownentrance"))
			{
				return "Infested Mine";
			}
			if (text.StartsWith("hildir_crypt"))
			{
				return "Smouldering Tomb";
			}
			if (text.StartsWith("hildir_cave"))
			{
				return "Howling Cavern";
			}
			if (text.StartsWith("hildir_plainsfortress"))
			{
				return "Sealed Tower";
			}
			if (text.StartsWith("morgenhole"))
			{
				return "Putrid Hole";
			}
			if (text.StartsWith("morkborg") || text.Contains("morkhalla"))
			{
				return "Mörkhalla";
			}
			if (text.StartsWith("thehole") || text.StartsWith("the_hole"))
			{
				return "Winding Tunnels";
			}
			if (text.StartsWith("bearcave"))
			{
				return "Bear Cave";
			}
			return Readable(raw);
		}

		private void Update()
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			if (!ready)
			{
				return;
			}
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)Minimap.instance) || !Object.op_Implicit((Object)(object)ZNet.instance))
				{
					if (session != null)
					{
						EndSession();
					}
					return;
				}
				string text = ZNet.instance.GetWorldUID().ToString(CultureInfo.InvariantCulture) + "-" + localPlayer.GetPlayerID().ToString(CultureInfo.InvariantCulture);
				if (session != text || (Object)(object)map != (Object)(object)Minimap.instance)
				{
					EndSession();
					StartSession(text);
				}
				if (!loadFailed && !(Time.unscaledTime < nextTick))
				{
					nextTick = Time.unscaledTime + 2f;
					if (enabledSetting.Value)
					{
						Scan(((Component)localPlayer).transform.position);
						Render(((Component)localPlayer).transform.position);
					}
					else
					{
						ClearPins();
					}
					if (Time.unscaledTime >= nextSave)
					{
						nextSave = Time.unscaledTime + 10f;
						Save();
					}
				}
			}
			catch (Exception e)
			{
				Warn("tick", e);
			}
		}

		private void StartSession(string key)
		{
			session = key;
			map = Minimap.instance;
			path = Path.Combine(Paths.ConfigPath, "QuietMap", key + ".json");
			loadFailed = false;
			if (File.Exists(path))
			{
				try
				{
					SaveData saveData = JsonConvert.DeserializeObject<SaveData>(File.ReadAllText(path));
					if (saveData == null || saveData.Version != 1)
					{
						throw new InvalidDataException("Unsupported or empty map save");
					}
					foreach (Record record2 in saveData.Records)
					{
						if (record2 != null && !string.IsNullOrEmpty(record2.Key))
						{
							records[record2.Key] = record2;
						}
					}
				}
				catch (Exception e)
				{
					loadFailed = true;
					Warn("load", e);
					return;
				}
			}
			else
			{
				ImportPriorDiscoveries();
			}
			Record[] array = records.Values.ToArray();
			foreach (Record record in array)
			{
				if (!LandmarkPolicy.KeepRecord(record.Kind))
				{
					records.Remove(record.Key);
					dirty = true;
				}
				else if (record.Kind != "Portal" && !string.IsNullOrEmpty(record.CompletionReason))
				{
					record.Available = true;
					record.Visited = true;
					record.CompletionReason = null;
					dirty = true;
				}
			}
			Save();
			nextTick = 0f;
			nextSave = Time.unscaledTime + 10f;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Quiet Map loaded " + records.Count + " known markers for world/character " + key));
		}

		private static string FileKey(string value)
		{
			return new string((value ?? "").Select((char c) => (!char.IsLetterOrDigit(c) && c != '_' && c != '-') ? '_' : c).ToArray());
		}

		private void ImportPriorDiscoveries()
		{
			try
			{
				PlayerProfile val = (Object.op_Implicit((Object)(object)Game.instance) ? Game.instance.GetPlayerProfile() : null);
				if (val == null)
				{
					return;
				}
				string text = Path.Combine(Paths.ConfigPath, "DigiAutoMapPins", FileKey(ZNet.instance.GetWorldName()) + "-" + ZNet.instance.GetWorldUID() + "." + FileKey(val.GetFilename()) + ".txt");
				if (!File.Exists(text))
				{
					return;
				}
				string[] array = File.ReadAllLines(text);
				for (int i = 0; i < array.Length; i++)
				{
					Record record = Migration.Read(array[i]);
					if (record != null)
					{
						if (record.Kind == "Dungeon")
						{
							record.Name = DungeonName(record.Prefab);
						}
						records[record.Key] = record;
						dirty = true;
					}
				}
				Save();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Imported " + records.Count + " known portal/dungeon markers from this character's former map tracker; original file retained."));
			}
			catch (Exception e)
			{
				Warn("prior map import", e);
			}
		}

		private void EndSession()
		{
			effectiveRadius = 0f;
			localExploration = false;
			Save();
			ClearPins();
			RestoreNativeSizes();
			vendorPins.Clear();
			nextLandmarkCheck = 0f;
			records.Clear();
			missing.Clear();
			insideLocations.Clear();
			session = null;
			path = null;
			map = null;
			dirty = false;
			loadFailed = false;
		}

		private void Save()
		{
			if (!dirty || path == null || loadFailed)
			{
				return;
			}
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(path));
				string sourceFileName = path + ".tmp";
				File.WriteAllText(sourceFileName, JsonConvert.SerializeObject((object)new SaveData
				{
					Records = records.Values.ToList()
				}, (Formatting)1));
				if (File.Exists(path))
				{
					File.Replace(sourceFileName, path, path + ".bak");
				}
				else
				{
					File.Move(sourceFileName, path);
				}
				dirty = false;
			}
			catch (Exception e)
			{
				Warn("save", e);
			}
		}

		private void Warn(string context, Exception e)
		{
			if (warned.Add(context))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Quiet Map " + context + ": " + e));
			}
		}

		private void Observe(string key, string kind, string name, string prefab, Vector3 pos, bool available, ZDO zdo = null)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			if (!records.TryGetValue(key, out var value))
			{
				Record record = records.Values.FirstOrDefault(delegate(Record p)
				{
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_0037: Unknown result type (might be due to invalid IL or missing references)
					if (p.Key.StartsWith("legacy:", StringComparison.Ordinal) && p.Kind == kind)
					{
						Vector3 val2 = Position(p) - pos;
						return ((Vector3)(ref val2)).sqrMagnitude < 4f;
					}
					return false;
				});
				if (record != null)
				{
					records.Remove(record.Key);
					record.Key = key;
					value = record;
					records[key] = value;
					if (zdo != null)
					{
						value.User = ((ZDOID)(ref zdo.m_uid)).UserID;
						value.Id = ((ZDOID)(ref zdo.m_uid)).ID;
					}
					dirty = true;
				}
			}
			if (value == null)
			{
				value = new Record
				{
					Key = key,
					Kind = kind,
					Name = name,
					Prefab = prefab,
					X = pos.x,
					Y = pos.y,
					Z = pos.z
				};
				if (zdo != null)
				{
					value.User = ((ZDOID)(ref zdo.m_uid)).UserID;
					value.Id = ((ZDOID)(ref zdo.m_uid)).ID;
				}
				records.Add(key, value);
				dirty = true;
			}
			if (value.Available == available && !(value.Name != name))
			{
				Vector3 val = Position(value) - pos;
				if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f))
				{
					goto IL_01ba;
				}
			}
			value.Available = available;
			value.Name = name;
			value.X = pos.x;
			value.Y = pos.y;
			value.Z = pos.z;
			dirty = true;
			goto IL_01ba;
			IL_01ba:
			missing.Remove(key);
		}

		private void Scan(Vector3 player)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			ZNetScene instance = ZNetScene.instance;
			if (!Object.op_Implicit((Object)(object)instance) || !(Instances.GetValue(instance) is Dictionary<ZDO, ZNetView> source))
			{
				return;
			}
			if (portals.Value)
			{
				KeyValuePair<ZDO, ZNetView>[] array = source.ToArray();
				foreach (KeyValuePair<ZDO, ZNetView> keyValuePair in array)
				{
					ZNetView value = keyValuePair.Value;
					if (Object.op_Implicit((Object)(object)value) && value.IsValid() && WithinDiscovery(((Component)value).transform.position, player, DiscoveryRadius))
					{
						TeleportWorld component = ((Component)value).GetComponent<TeleportWorld>();
						if (Object.op_Implicit((Object)(object)component))
						{
							TrackPortal(component, interacted: false);
						}
					}
				}
			}
			ScanLocations(player);
			Record[] array2 = records.Values.Where((Record r) => r.Kind == "Portal" && r.Id != 0 && r.Available).ToArray();
			foreach (Record record in array2)
			{
				Vector3 val = Position(record) - player;
				bool flag = ((Vector3)(ref val)).sqrMagnitude < 1600f;
				if (flag && Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.IsZoneLoaded(Position(record)))
				{
					ZDOMan instance2 = ZDOMan.instance;
					ZDO val2 = ((instance2 != null) ? instance2.GetZDO(new ZDOID(record.User, record.Id)) : null);
					int num;
					if (val2 != null && (record.Prefab == "portal" || val2.GetPrefab() == StringExtensionMethods.GetStableHashCode(record.Prefab)))
					{
						val = val2.GetPosition() - Position(record);
						num = ((((Vector3)(ref val)).sqrMagnitude < 4f) ? 1 : 0);
					}
					else
					{
						num = 0;
					}
					bool flag2 = (byte)num != 0;
					int value2;
					int num2 = ((!flag2) ? ((!missing.TryGetValue(record.Key, out value2)) ? 1 : (value2 + 1)) : 0);
					missing[record.Key] = num2;
					if (Policy.MissingMeansDestroyed(flag, zoneLoaded: true, flag2, num2))
					{
						record.Available = false;
						dirty = true;
					}
				}
			}
		}

		private void TrackPortal(TeleportWorld portal, bool interacted)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			if (!ready || loadFailed || session == null || !enabledSetting.Value || !portals.Value || !Object.op_Implicit((Object)(object)portal))
			{
				return;
			}
			ZNetView component = ((Component)portal).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			string key = Key(zDO.m_uid);
			string text = Clean(((Object)((Component)component).gameObject).name);
			string text2 = zDO.GetString(ZDOVars.s_tag, "");
			Observe(key, "Portal", string.IsNullOrWhiteSpace(text2) ? "Portal" : text2, text, ((Component)component).transform.position, available: true, zDO);
			Record record = records[key];
			if (Policy.RestorePortal(record, interacted))
			{
				record.Deleted = false;
				dirty = true;
			}
			if (record.Prefab != text)
			{
				record.Prefab = text;
				dirty = true;
			}
			if (interacted)
			{
				nextTick = 0f;
				Save();
				if (Object.op_Implicit((Object)(object)map) && Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					Render(((Component)Player.m_localPlayer).transform.position);
				}
			}
		}

		private void PortalInteraction(TeleportWorld portal, Humanoid user)
		{
			if (!Object.op_Implicit((Object)(object)user) || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				TrackPortal(portal, interacted: true);
			}
			catch (Exception e)
			{
				Warn("portal interaction", e);
			}
		}

		private string LocationName(string name)
		{
			if (LandmarkPolicy.Aio.TryGetValue(name ?? "", out var value))
			{
				return value.Name;
			}
			string text;
			if (!Policy.IsDungeonName(name))
			{
				text = LandmarkPolicy.OutdoorName(name);
				if (text == null)
				{
					return DungeonName(name);
				}
			}
			else
			{
				text = DungeonName(name);
			}
			return text;
		}

		private bool Recognized(string name)
		{
			if (!LandmarkPolicy.Aio.ContainsKey(name ?? "") && LandmarkPolicy.OutdoorName(name) == null && !Policy.IsDungeonName(name))
			{
				return Extra(extraDungeons, name);
			}
			return true;
		}

		private Record ObserveLandmark(string name, Vector3 pos)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			Record record = records.Values.FirstOrDefault(delegate(Record r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				if (r.Kind != "Portal")
				{
					Vector3 val = Position(r) - pos;
					return ((Vector3)(ref val)).sqrMagnitude < 100f;
				}
				return false;
			});
			if (record != null)
			{
				string text = LocationName(name);
				if (record.Name != text)
				{
					record.Name = text;
					dirty = true;
				}
				return record;
			}
			string key = "place:" + Mathf.RoundToInt(pos.x) + ":" + Mathf.RoundToInt(pos.z);
			Observe(key, "Landmark", LocationName(name), name, pos, available: true);
			return records[key];
		}

		private void SetVisited(Record record)
		{
			if (!markVisited.Value || record == null || LandmarkPolicy.IsService(record.Prefab))
			{
				return;
			}
			if (!record.Visited)
			{
				record.Visited = true;
				dirty = true;
			}
			foreach (Pin value in pins.Values)
			{
				if (value.Keys.Contains(record.Key))
				{
					value.Data.m_checked = true;
				}
			}
		}

		private void ScanLocations(Vector3 player)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			if (!dungeons.Value || !Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				insideLocations.Clear();
				return;
			}
			bool flag = Character.InInterior(player);
			Location val = (flag ? Location.GetLocation(player, true) : null);
			List<Location> list = Locations.GetValue(null) as List<Location>;
			HashSet<string> hashSet = new HashSet<string>();
			foreach (LocationInstance location in ZoneSystem.instance.GetLocationList())
			{
				if (!location.m_placed || location.m_location == null)
				{
					continue;
				}
				string prefabName = location.m_location.m_prefabName;
				if (!Recognized(prefabName))
				{
					continue;
				}
				Vector3 pos = location.m_position;
				int num;
				if (Object.op_Implicit((Object)(object)val))
				{
					Vector3 val2 = ((Component)val).transform.position - pos;
					num = ((((Vector3)(ref val2)).sqrMagnitude < 100f) ? 1 : 0);
				}
				else
				{
					num = 0;
				}
				bool flag2 = (byte)num != 0;
				if (!flag2 && !WithinDiscovery(pos, player, DiscoveryRadius))
				{
					continue;
				}
				Record record = ObserveLandmark(prefabName, pos);
				Location val3 = list?.FirstOrDefault((Func<Location, bool>)delegate(Location l)
				{
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0014: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_001e: Unknown result type (might be due to invalid IL or missing references)
					if (Object.op_Implicit((Object)(object)l))
					{
						Vector3 val4 = ((Component)l).transform.position - pos;
						return ((Vector3)(ref val4)).sqrMagnitude < 100f;
					}
					return false;
				});
				bool interiorLocation = (Object.op_Implicit((Object)(object)val3) ? val3.m_hasInterior : (location.m_location.m_interiorRadius > 0f));
				float num2 = player.x - pos.x;
				float num3 = player.z - pos.z;
				float radius = LandmarkPolicy.EnterRadius(location.m_location.m_exteriorRadius);
				if (LandmarkPolicy.Entered(interiorLocation, flag, flag2, num2 * num2 + num3 * num3, radius, player.y - pos.y))
				{
					hashSet.Add(record.Key);
					if (!insideLocations.Contains(record.Key))
					{
						SetVisited(record);
					}
				}
			}
			if (Object.op_Implicit((Object)(object)val) && val.m_hasInterior)
			{
				Record record2 = ObserveLandmark(Clean(((Object)((Component)val).gameObject).name), ((Component)val).transform.position);
				hashSet.Add(record2.Key);
				if (!insideLocations.Contains(record2.Key))
				{
					SetVisited(record2);
				}
			}
			insideLocations.Clear();
			foreach (string item in hashSet)
			{
				insideLocations.Add(item);
			}
		}

		private void EnterDungeon(Teleport entrance, Humanoid user, bool succeeded)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (!ready || !enabledSetting.Value || !dungeons.Value || !markVisited.Value || session == null || loadFailed || !succeeded || (Object)(object)user != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)entrance) || !Object.op_Implicit((Object)(object)entrance.m_targetPoint) || Character.InInterior(((Component)entrance).transform.position) || !Character.InInterior(((Component)entrance.m_targetPoint).transform.position))
			{
				return;
			}
			try
			{
				Location location = Location.GetLocation(((Component)entrance).transform.position, true);
				if (Object.op_Implicit((Object)(object)location) && location.m_hasInterior)
				{
					SetVisited(ObserveLandmark(Clean(((Object)((Component)location).gameObject).name), ((Component)location).transform.position));
					Save();
				}
			}
			catch (Exception e)
			{
				Warn("dungeon entry", e);
			}
		}

		private bool CategoryOn(string kind)
		{
			switch (kind)
			{
			case "Dungeon":
			case "Landmark":
				return dungeons.Value;
			default:
				return false;
			case "Portal":
				return portals.Value;
			}
		}

		private void Render(Vector3 player)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)map))
			{
				return;
			}
			Dictionary<string, List<Record>> dictionary = ResourceGrouping.Build(records.Values.Where((Record r) => CategoryOn(r.Kind) && Policy.Show(r.Kind, r.Available, r.Deleted, r.Y > 3000f, player.y > 3000f)));
			string[] array = pins.Keys.ToArray();
			foreach (string key in array)
			{
				if (!dictionary.ContainsKey(key))
				{
					RemovePin(key);
				}
			}
			List<PinData> list = GamePins.GetValue(map) as List<PinData>;
			foreach (KeyValuePair<string, List<Record>> item in dictionary)
			{
				List<Record> value = item.Value;
				Record first = value[0];
				Vector3 pos = new Vector3(value.Average((Record r) => r.X), value.Average((Record r) => r.Y), value.Average((Record r) => r.Z));
				string label = first.Name;
				if (pins.TryGetValue(item.Key, out var value2) && value2.Borrowed && list != null && !list.Contains(value2.Data))
				{
					RemovePin(item.Key);
				}
				if (!pins.TryGetValue(item.Key, out var value3))
				{
					Dictionary<Vector3, PinData> dictionary2 = LocationPins?.GetValue(map) as Dictionary<Vector3, PinData>;
					PinData val = ((first.Kind != "Portal" && dictionary2 != null) ? ((IEnumerable<PinData>)dictionary2.Values).FirstOrDefault((Func<PinData, bool>)delegate(PinData p)
					{
						//IL_0001: Unknown result type (might be due to invalid IL or missing references)
						//IL_0008: Invalid comparison between Unknown and I4
						//IL_000b: Unknown result type (might be due to invalid IL or missing references)
						//IL_0011: Unknown result type (might be due to invalid IL or missing references)
						//IL_0016: Unknown result type (might be due to invalid IL or missing references)
						//IL_001b: Unknown result type (might be due to invalid IL or missing references)
						if ((int)p.m_type != 9)
						{
							Vector3 val4 = p.m_pos - pos;
							return ((Vector3)(ref val4)).sqrMagnitude < 100f;
						}
						return false;
					}) : null);
					if (first.Kind != "Portal" && val == null && list != null)
					{
						val = ((IEnumerable<PinData>)list).FirstOrDefault((Func<PinData, bool>)delegate(PinData p)
						{
							//IL_0009: Unknown result type (might be due to invalid IL or missing references)
							//IL_0010: Invalid comparison between Unknown and I4
							//IL_0013: Unknown result type (might be due to invalid IL or missing references)
							//IL_0019: Invalid comparison between Unknown and I4
							//IL_001c: Unknown result type (might be due to invalid IL or missing references)
							//IL_0022: Unknown result type (might be due to invalid IL or missing references)
							//IL_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 (p.m_save && (int)p.m_type != 9 && (int)p.m_type != 6)
							{
								Vector3 val4 = p.m_pos - pos;
								if (((Vector3)(ref val4)).sqrMagnitude < 225f)
								{
									return LandmarkPolicy.MatchingSavedPin(p.m_name, label, first.Prefab);
								}
							}
							return false;
						});
					}
					if (first.Kind != "Portal" && val == null && list != null && list.Any(delegate(PinData p)
					{
						//IL_0009: Unknown result type (might be due to invalid IL or missing references)
						//IL_000f: Unknown result type (might be due to invalid IL or missing references)
						//IL_0014: Unknown result type (might be due to invalid IL or missing references)
						//IL_0019: Unknown result type (might be due to invalid IL or missing references)
						if (p.m_save)
						{
							Vector3 val4 = p.m_pos - pos;
							return ((Vector3)(ref val4)).sqrMagnitude < 225f;
						}
						return false;
					}))
					{
						continue;
					}
					PinData val2 = ((first.Kind == "Portal" && list != null) ? ((IEnumerable<PinData>)list).FirstOrDefault((Func<PinData, bool>)delegate(PinData p)
					{
						//IL_0009: Unknown result type (might be due to invalid IL or missing references)
						//IL_000f: Invalid comparison between Unknown and I4
						//IL_0012: Unknown result type (might be due to invalid IL or missing references)
						//IL_0018: Unknown result type (might be due to invalid IL or missing references)
						//IL_001d: Unknown result type (might be due to invalid IL or missing references)
						//IL_0022: Unknown result type (might be due to invalid IL or missing references)
						if (p.m_save && (int)p.m_type == 6)
						{
							Vector3 val4 = p.m_pos - pos;
							if (((Vector3)(ref val4)).sqrMagnitude < 4f)
							{
								return p.m_name == label;
							}
						}
						return false;
					}) : null);
					PinType val3 = (PinType)((first.Kind == "Portal") ? 6 : 3);
					if (val2 != null)
					{
						if (!BackupMap())
						{
							continue;
						}
						Save();
						if (dirty)
						{
							continue;
						}
						val2.m_save = false;
					}
					value3 = new Pin
					{
						Borrowed = (val != null),
						Data = (val ?? val2 ?? map.AddPin(pos, val3, label, false, first.Visited, 0L, default(PlatformUserID))),
						Keys = value.Select((Record r) => r.Key).ToList(),
						Kind = first.Kind
					};
					pins.Add(item.Key, value3);
					if (val != null)
					{
						if (val.m_checked && !first.Visited)
						{
							first.Visited = true;
							dirty = true;
						}
						value3.Data.m_checked = first.Visited;
					}
					continue;
				}
				value3.Keys = value.Select((Record r) => r.Key).ToList();
				if (!value3.Borrowed && value3.Data.m_name != label)
				{
					RemovePin(item.Key);
					continue;
				}
				if (!value3.Borrowed)
				{
					value3.Data.m_pos = pos;
				}
				value3.Data.m_checked = first.Visited;
			}
		}

		private bool BackupMap()
		{
			try
			{
				string text = path + ".native-map-before-portals.bin";
				if (File.Exists(text))
				{
					return true;
				}
				if (MapData == null)
				{
					return false;
				}
				Directory.CreateDirectory(Path.GetDirectoryName(text));
				File.WriteAllBytes(text, (byte[])MapData.Invoke(map, null));
				return true;
			}
			catch (Exception e)
			{
				Warn("portal migration backup", e);
				return false;
			}
		}

		private void RemovePin(string key)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (!pins.TryGetValue(key, out var value))
			{
				return;
			}
			if (value.Borrowed)
			{
				if (Object.op_Implicit((Object)(object)value.Data.m_iconElement))
				{
					Color color = ((Graphic)value.Data.m_iconElement).color;
					color.a = 1f;
					((Graphic)value.Data.m_iconElement).color = color;
				}
				PinNameData namePinData = value.Data.m_NamePinData;
				TMP_Text val = ((namePinData != null) ? namePinData.PinNameText : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					Color color2 = ((Graphic)val).color;
					color2.a = 1f;
					((Graphic)val).color = color2;
				}
			}
			internalRemove = true;
			try
			{
				if (Object.op_Implicit((Object)(object)map) && !value.Borrowed)
				{
					map.RemovePin(value.Data);
				}
			}
			finally
			{
				internalRemove = false;
				pins.Remove(key);
			}
		}

		private void ClearPins()
		{
			string[] array = pins.Keys.ToArray();
			foreach (string key in array)
			{
				RemovePin(key);
			}
		}

		private void Style()
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			if (!enabledSetting.Value)
			{
				RestoreNativeSizes();
				return;
			}
			StyleLandmarks();
			foreach (Pin value2 in pins.Values)
			{
				float num = ((value2.Kind == "Portal") ? portalScale.Value : (landmarkScale.Value / (value2.Data.m_doubleSize ? 2f : 1f)));
				if (Object.op_Implicit((Object)(object)value2.Data.m_uiElement))
				{
					((Transform)value2.Data.m_uiElement).localScale = new Vector3(num, num, 1f);
				}
				float a = LandmarkPolicy.Alpha(value2.Data.m_checked && value2.Kind != "Portal", visitedOpacity.Value);
				if (Object.op_Implicit((Object)(object)value2.Data.m_iconElement))
				{
					Color color = ((Graphic)value2.Data.m_iconElement).color;
					color.a = a;
					((Graphic)value2.Data.m_iconElement).color = color;
				}
				PinNameData namePinData = value2.Data.m_NamePinData;
				TMP_Text val = ((namePinData != null) ? namePinData.PinNameText : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					val.transform.localScale = Vector3.one;
					Color color2 = ((Graphic)val).color;
					color2.a = a;
					((Graphic)val).color = color2;
				}
				foreach (string key in value2.Keys)
				{
					if (records.TryGetValue(key, out var value) && value.Visited != value2.Data.m_checked)
					{
						value.Visited = value2.Data.m_checked;
						dirty = true;
					}
				}
			}
		}

		private void StyleLandmarks()
		{
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)map))
			{
				return;
			}
			if (Time.unscaledTime >= nextLandmarkCheck)
			{
				nextLandmarkCheck = Time.unscaledTime + 2f;
				vendorPins.Clear();
				Dictionary<Vector3, string> dictionary = new Dictionary<Vector3, string>();
				if (Object.op_Implicit((Object)(object)ZoneSystem.instance))
				{
					ZoneSystem.instance.GetLocationIcons(dictionary);
				}
				if (LocationPins?.GetValue(map) is Dictionary<Vector3, PinData> dictionary2)
				{
					foreach (KeyValuePair<Vector3, PinData> item in dictionary2)
					{
						if (dictionary.TryGetValue(item.Key, out var value) && !string.IsNullOrEmpty((value ?? "").ToLowerInvariant()))
						{
							vendorPins.Add(item.Value);
						}
					}
				}
				Type type = AccessTools.TypeByName("More_World_Locations_AIO.PortMap");
				IEnumerable enumerable = ((type == null) ? null : (AccessTools.Field(type, "s_entries")?.GetValue(null) as IEnumerable));
				if (enumerable != null)
				{
					foreach (object item2 in enumerable)
					{
						if (item2 != null)
						{
							object? obj = AccessTools.Field(item2.GetType(), "Pin")?.GetValue(item2);
							PinData val = (PinData)((obj is PinData) ? obj : null);
							if (val != null)
							{
								vendorPins.Add(val);
							}
						}
					}
				}
				Transform[] array = nativeScales.Keys.Where((Transform t) => !Object.op_Implicit((Object)(object)t)).ToArray();
				foreach (Transform key in array)
				{
					nativeScales.Remove(key);
				}
			}
			if (!(GamePins.GetValue(map) is List<PinData> list))
			{
				return;
			}
			foreach (PinData item3 in list)
			{
				if (((int)item3.m_type == 9 || vendorPins.Contains(item3)) && Object.op_Implicit((Object)(object)item3.m_uiElement) && !(item3.m_worldSize > 0f))
				{
					Transform uiElement = (Transform)(object)item3.m_uiElement;
					if (!nativeScales.ContainsKey(uiElement))
					{
						nativeScales.Add(uiElement, uiElement.localScale);
					}
					float num2 = landmarkScale.Value / (item3.m_doubleSize ? 2f : 1f);
					uiElement.localScale = new Vector3(num2, num2, 1f);
				}
			}
		}

		private void RestoreNativeSizes()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<Transform, Vector3> nativeScale in nativeScales)
			{
				if (Object.op_Implicit((Object)(object)nativeScale.Key))
				{
					nativeScale.Key.localScale = nativeScale.Value;
				}
			}
			nativeScales.Clear();
		}

		private void OnDestroy()
		{
			EndSession();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
	internal static class Policy
	{
		private static readonly HashSet<string> Valuable = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"SurtlingCore", "BlackCore", "MoltenCore", "FrostCore", "RoyalJelly", "GoblinTotem", "DragonEgg", "VoltureEgg", "Tar", "SulfurStone",
			"WolfHairBundle", "Crystal", "IronOre", "TinOre", "CopperOre", "SilverOre", "Obsidian", "DyrnwynHiltFragment", "DyrnwynBladeFragment", "DyrnwynTipFragment",
			"GemstoneBlue", "GemstoneGreen", "GemstoneRed", "AncientGemstoneBlack", "AncientGemstoneGreen", "AncientGemstoneOrange", "AncientGemstonePurple"
		};

		private static readonly HashSet<string> Minerals = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"CopperOre", "TinOre", "SilverOre", "IronScrap", "IronOre", "Iron", "CopperScrap", "Obsidian", "FlametalOre", "FlametalOreNew",
			"BlackMarble", "Softtissue", "Guck", "Chitin", "ProustitePowder", "BellFragment", "GoldOre", "GoldNugget"
		};

		internal static bool IsValuable(string name)
		{
			if (name != null)
			{
				if (!Valuable.Contains(name))
				{
					return string.Equals(name, "DvergrNeedle", StringComparison.OrdinalIgnoreCase);
				}
				return true;
			}
			return false;
		}

		internal static bool IsMineral(string name)
		{
			if (name != null)
			{
				return Minerals.Contains(name);
			}
			return false;
		}

		internal static bool IsCompletionLoot(string name)
		{
			if (!IsValuable(name) && !IsMineral(name))
			{
				switch (name)
				{
				default:
					return name == "SilverNecklace";
				case "Coins":
				case "Amber":
				case "AmberPearl":
				case "Ruby":
					break;
				}
			}
			return true;
		}

		internal static bool IsGeneratedPoi(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				if (!name.StartsWith("MWL_", StringComparison.OrdinalIgnoreCase))
				{
					return name.Equals("BFD_Exterior", StringComparison.OrdinalIgnoreCase);
				}
				return true;
			}
			return false;
		}

		internal static bool HideResourceInPoi(string kind, bool inside)
		{
			if (inside)
			{
				if (!(kind == "Loot"))
				{
					return kind == "Ore";
				}
				return true;
			}
			return false;
		}

		internal static bool DepositPrefab(string name)
		{
			string text = (name ?? "").ToLowerInvariant();
			if (!text.StartsWith("mudpile") && !text.StartsWith("mineable") && !text.StartsWith("rock") && !text.StartsWith("guck") && !text.StartsWith("giant_brain") && !text.StartsWith("giant_helmet"))
			{
				return text.StartsWith("giant_sword");
			}
			return true;
		}

		internal static bool LootCrate(string name)
		{
			if (!string.Equals(name, "piece_dvergr_crate", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(name, "dvergrprops_crate", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		internal static bool RestorePortal(Record r, bool interacted)
		{
			if (r.Kind == "Portal" && r.Deleted)
			{
				if (!interacted)
				{
					return r.Prefab == "portal";
				}
				return true;
			}
			return false;
		}

		internal static bool IsTar(Record r)
		{
			if (r.Kind == "Loot")
			{
				if (!string.Equals(r.Name, "Tar", StringComparison.OrdinalIgnoreCase) && !string.Equals(r.Prefab, "Pickable_Tar", StringComparison.OrdinalIgnoreCase) && !string.Equals(r.Prefab, "Pickable_TarBig", StringComparison.OrdinalIgnoreCase))
				{
					return string.Equals(r.Prefab, "Tar", StringComparison.OrdinalIgnoreCase);
				}
				return true;
			}
			return false;
		}

		internal static bool Small(string kind)
		{
			if (!(kind == "Ore") && !(kind == "Chest"))
			{
				return kind == "Loot";
			}
			return true;
		}

		internal static bool Show(string kind, bool available, bool deleted, bool interior, bool playerInterior)
		{
			if (available && !deleted)
			{
				if (!(!interior || playerInterior))
				{
					return kind == "Portal";
				}
				return true;
			}
			return false;
		}

		internal static bool MissingMeansDestroyed(bool inRange, bool zoneLoaded, bool hasZdo, int misses)
		{
			if (inRange && zoneLoaded && !hasZdo)
			{
				return misses >= 3;
			}
			return false;
		}

		internal static bool IsDungeonName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			string text = name.ToLowerInvariant();
			if (!text.Contains("crypt") && !text.Contains("trollcave") && !text.Contains("mountaincave") && !text.Contains("dvergrtownentrance") && !text.Contains("morgenhole") && !text.Contains("charredfortress") && !text.Contains("morkhalla") && !text.StartsWith("morkborg") && !text.Contains("hildir_cave") && !text.Contains("hildir_plainsfortress") && !text.Contains("tomb") && !text.Contains("dungeon") && !text.Contains("bearcave") && !text.StartsWith("thehole") && !text.StartsWith("the_hole"))
			{
				return text.StartsWith("thedarkesthole");
			}
			return true;
		}
	}
	public sealed class Record
	{
		public string Key;

		public string Kind;

		public string Name;

		public string Prefab;

		public long User;

		public uint Id;

		public float X;

		public float Y;

		public float Z;

		public bool Available = true;

		public bool Deleted;

		public bool Visited;

		public bool DungeonSurveyed;

		public string CompletionReason;
	}
	public sealed class SaveData
	{
		public int Version = 1;

		public List<Record> Records = new List<Record>();
	}
	internal static class Migration
	{
		internal static Record Read(string line)
		{
			if (string.IsNullOrEmpty(line) || line.StartsWith("#"))
			{
				return null;
			}
			string[] array = line.Split('\t');
			if (array.Length < 10)
			{
				return null;
			}
			string text = array[0];
			string text2 = ((text == "portal") ? "Portal" : ((text.StartsWith("place:") && Policy.IsDungeonName(text.Substring(6))) ? "Dungeon" : null));
			if (text2 == null)
			{
				return null;
			}
			if (!float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				return null;
			}
			if (float.IsNaN(result) || float.IsInfinity(result) || float.IsNaN(result2) || float.IsInfinity(result2) || float.IsNaN(result3) || float.IsInfinity(result3))
			{
				return null;
			}
			Record record = new Record();
			record.Key = "legacy:" + text + ":" + array[2] + ":" + array[4];
			record.Kind = text2;
			record.Name = (string.IsNullOrWhiteSpace(array[8]) ? text2 : array[8]);
			record.Prefab = (text.StartsWith("place:") ? text.Substring(6) : "portal");
			record.X = result;
			record.Y = result2;
			record.Z = result3;
			record.Available = !array[6].Contains("E");
			record.Deleted = array[6].Contains("D");
			record.Visited = array[6].Contains("C");
			return record;
		}
	}
	internal static class LandmarkPolicy
	{
		internal sealed class Entry
		{
			internal string Name;

			internal string Category;

			internal bool Service
			{
				get
				{
					if (!(Category == "Ports") && !(Category == "Traders"))
					{
						return Category == "Trainers";
					}
					return true;
				}
			}
		}

		internal static readonly Dictionary<string, Entry> Aio = Load();

		private static Dictionary<string, Entry> Load()
		{
			Dictionary<string, Entry> dictionary = new Dictionary<string, Entry>(StringComparer.OrdinalIgnoreCase);
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("QuietMap.AioLandmarks");
			if (stream == null)
			{
				throw new InvalidDataException("AIO landmark catalog missing");
			}
			using StreamReader streamReader = new StreamReader(stream);
			string text;
			while ((text = streamReader.ReadLine()) != null)
			{
				string[] array = text.Split('\t');
				if (array.Length == 3)
				{
					dictionary.Add(array[1], new Entry
					{
						Category = array[0],
						Name = array[2]
					});
				}
			}
			return dictionary;
		}

		internal static string OutdoorName(string prefab)
		{
			string text = (prefab ?? "").ToLowerInvariant();
			if (text.StartsWith("tarpit"))
			{
				return "Tar Pit";
			}
			if (text.StartsWith("goblincamp"))
			{
				return "Fuling Village";
			}
			if (text.StartsWith("woodvillage") || text.StartsWith("draugrvillage"))
			{
				return "Draugr Village";
			}
			if (text.StartsWith("greydwarf_camp"))
			{
				return "Greydwarf Nest";
			}
			if (text.StartsWith("firehole"))
			{
				return "Surtling Geyser";
			}
			if (text.StartsWith("mistlands_dvergrtown") && !text.Contains("entrance"))
			{
				return "Dvergr Settlement";
			}
			if (text.StartsWith("mistlands_guardtower") || text.StartsWith("mistlands_dvergrguardtower"))
			{
				return "Dvergr Tower";
			}
			if (text.StartsWith("mistlands_harbour") || text.StartsWith("mistlands_dvergrharbour"))
			{
				return "Dvergr Harbour";
			}
			if (text.StartsWith("mistlands_viaduct"))
			{
				return "Ruined Aqueduct";
			}
			if (text.StartsWith("shipwreck"))
			{
				return "Shipwreck";
			}
			return VanillaName(prefab);
		}

		private static string VanillaName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			if (name.StartsWith("Mistlands_GuardTower1_ruined_new", StringComparison.OrdinalIgnoreCase))
			{
				return "Guard tower 1 ruined new";
			}
			if (name.StartsWith("Mistlands_GuardTower3_ruined_new", StringComparison.OrdinalIgnoreCase))
			{
				return "Guard tower 3 ruined new";
			}
			if (name.StartsWith("Mistlands_DvergrTownEntrance", StringComparison.OrdinalIgnoreCase))
			{
				return "Infested Mine";
			}
			if (name.StartsWith("Mistlands_GuardTower1_new", StringComparison.OrdinalIgnoreCase))
			{
				return "Guard tower 1 new";
			}
			if (name.StartsWith("Mistlands_GuardTower2_new", StringComparison.OrdinalIgnoreCase))
			{
				return "Guard tower 2 new";
			}
			if (name.StartsWith("Mistlands_GuardTower3_new", StringComparison.OrdinalIgnoreCase))
			{
				return "Guard tower 3 new";
			}
			if (name.StartsWith("Mistlands_Lighthouse1_new", StringComparison.OrdinalIgnoreCase))
			{
				return "Lighthouse 1 new";
			}
			if (name.StartsWith("CharredTowerRuins1_dvergr", StringComparison.OrdinalIgnoreCase))
			{
				return "Charred tower ruins 1 dvergr";
			}
			if (name.StartsWith("StoneTowerRuins07_sunk", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone tower ruins 07 sunk";
			}
			if (name.StartsWith("StoneTowerRuins08_sunk", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone tower ruins 08 sunk";
			}
			if (name.StartsWith("StoneTowerRuins09_sunk", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone tower ruins 09 sunk";
			}
			if (name.StartsWith("StoneTowerRuins10_sunk", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone tower ruins 10 sunk";
			}
			if (name.StartsWith("StoneTowerRuins05_leet", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone tower ruins 05 leet";
			}
			if (name.StartsWith("AncientUpgradeStation", StringComparison.OrdinalIgnoreCase))
			{
				return "Ancient upgrade station";
			}
			if (name.StartsWith("Mistlands_StatueGroup", StringComparison.OrdinalIgnoreCase))
			{
				return "Statue group";
			}
			if (name.StartsWith("Hildir_plainsfortress", StringComparison.OrdinalIgnoreCase))
			{
				return "Sealed Tower";
			}
			if (name.StartsWith("Mistlands_Excavation", StringComparison.OrdinalIgnoreCase))
			{
				return "Dvergr excavation";
			}
			if (name.StartsWith("Mistlands_RoadPost", StringComparison.OrdinalIgnoreCase))
			{
				return "Road post";
			}
			if (name.StartsWith("NorthMemorialPlace", StringComparison.OrdinalIgnoreCase))
			{
				return "North memorial place";
			}
			if (name.StartsWith("StoneHouse1_heath", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone house 1 heath";
			}
			if (name.StartsWith("StoneHouse2_heath", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone house 2 heath";
			}
			if (name.StartsWith("StoneHouse5_heath", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone house 5 heath";
			}
			if (name.StartsWith("AbandonedLogCabin", StringComparison.OrdinalIgnoreCase))
			{
				return "Abandoned log cabin";
			}
			if (name.StartsWith("Mistlands_Harbour", StringComparison.OrdinalIgnoreCase))
			{
				return "Dvergr harbour";
			}
			if (name.StartsWith("Mistlands_Viaduct", StringComparison.OrdinalIgnoreCase))
			{
				return "Viaduct";
			}
			if (name.StartsWith("CharredTowerRuins", StringComparison.OrdinalIgnoreCase))
			{
				return "Charred tower ruins";
			}
			if (name.StartsWith("Mistlands_Statue", StringComparison.OrdinalIgnoreCase))
			{
				return "Statue";
			}
			if (name.StartsWith("StoneTowerRuins", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone tower ruins";
			}
			if (name.StartsWith("CharredFortress", StringComparison.OrdinalIgnoreCase))
			{
				return "Charred Fortress";
			}
			if (name.StartsWith("FrozenShip01_DN", StringComparison.OrdinalIgnoreCase))
			{
				return "Frozen ship 01 dn";
			}
			if (name.StartsWith("FrozenShip02_DN", StringComparison.OrdinalIgnoreCase))
			{
				return "Frozen ship 02 dn";
			}
			if (name.StartsWith("FrozenShip03_DN", StringComparison.OrdinalIgnoreCase))
			{
				return "Frozen ship 03 dn";
			}
			if (name.StartsWith("Greydwarf_camp", StringComparison.OrdinalIgnoreCase))
			{
				return "Greydwarf camp";
			}
			if (name.StartsWith("DrakeLorestone", StringComparison.OrdinalIgnoreCase))
			{
				return "Drake lorestone";
			}
			if (name.StartsWith("PlaceofMystery", StringComparison.OrdinalIgnoreCase))
			{
				return "Place of Mystery";
			}
			if (name.StartsWith("ShipWreck01_DN", StringComparison.OrdinalIgnoreCase))
			{
				return "Ship wreck 01 dn";
			}
			if (name.StartsWith("ShipWreck02_DN", StringComparison.OrdinalIgnoreCase))
			{
				return "Ship wreck 02 dn";
			}
			if (name.StartsWith("MountainGrave", StringComparison.OrdinalIgnoreCase))
			{
				return "Mountain grave";
			}
			if (name.StartsWith("FortressRuins", StringComparison.OrdinalIgnoreCase))
			{
				return "Fortress ruins";
			}
			if (name.StartsWith("MountainWell", StringComparison.OrdinalIgnoreCase))
			{
				return "Mountain well";
			}
			if (name.StartsWith("MountainCave", StringComparison.OrdinalIgnoreCase))
			{
				return "Frost Cave";
			}
			if (name.StartsWith("Hildir_crypt", StringComparison.OrdinalIgnoreCase))
			{
				return "Smouldering Tomb";
			}
			if (name.StartsWith("CharredRuins", StringComparison.OrdinalIgnoreCase))
			{
				return "Charred ruins";
			}
			if (name.StartsWith("AshlandRuins", StringComparison.OrdinalIgnoreCase))
			{
				return "Ashland ruins";
			}
			if (name.StartsWith("NorthVillage", StringComparison.OrdinalIgnoreCase))
			{
				return "North village";
			}
			if (name.StartsWith("StoneCircle", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone circle";
			}
			if (name.StartsWith("WoodVillage", StringComparison.OrdinalIgnoreCase))
			{
				return "Draugr village";
			}
			if (name.StartsWith("SunkenCrypt", StringComparison.OrdinalIgnoreCase))
			{
				return "Crypt";
			}
			if (name.StartsWith("ShipSetting", StringComparison.OrdinalIgnoreCase))
			{
				return "Ship setting";
			}
			if (name.StartsWith("Hildir_cave", StringComparison.OrdinalIgnoreCase))
			{
				return "Howling Cavern";
			}
			if (name.StartsWith("StoneHouse", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone house";
			}
			if (name.StartsWith("GoblinCamp", StringComparison.OrdinalIgnoreCase))
			{
				return "Fuling village";
			}
			if (name.StartsWith("StoneTower", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone tower";
			}
			if (name.StartsWith("StoneHenge", StringComparison.OrdinalIgnoreCase))
			{
				return "Stone henge";
			}
			if (name.StartsWith("CombatRuin", StringComparison.OrdinalIgnoreCase))
			{
				return "Combat ruin";
			}
			if (name.StartsWith("MorgenHole", StringComparison.OrdinalIgnoreCase))
			{
				return "Putrid Hole";
			}
			if (name.StartsWith("LumberCamp", StringComparison.OrdinalIgnoreCase))
			{
				return "Lumber camp";
			}
			if (name.StartsWith("Runestone", StringComparison.OrdinalIgnoreCase))
			{
				return "Runestone";
			}
			if (name.StartsWith("SwampRuin", StringComparison.OrdinalIgnoreCase))
			{
				return "Swamp ruin";
			}
			if (name.StartsWith("WoodHouse", StringComparison.OrdinalIgnoreCase))
			{
				return "Wood house";
			}
			if (name.StartsWith("TrollCave", StringComparison.OrdinalIgnoreCase))
			{
				return "Troll Cave";
			}
			if (name.StartsWith("SwampWell", StringComparison.OrdinalIgnoreCase))
			{
				return "Swamp well";
			}
			if (name.StartsWith("Waymarker", StringComparison.OrdinalIgnoreCase))
			{
				return "Waymarker";
			}
			if (name.StartsWith("ShipWreck", StringComparison.OrdinalIgnoreCase))
			{
				return "Ship wreck";
			}
			if (name.StartsWith("GoblinHut", StringComparison.OrdinalIgnoreCase))
			{
				return "Goblin hut";
			}
			if (name.StartsWith("FireHole", StringComparison.OrdinalIgnoreCase))
			{
				return "Fire hole";
			}
			if (name.StartsWith("WoodFarm", StringComparison.OrdinalIgnoreCase))
			{
				return "Abandoned farm";
			}
			if (name.StartsWith("SwampHut", StringComparison.OrdinalIgnoreCase))
			{
				return "Swamp hut";
			}
			if (name.StartsWith("MorkBorg", StringComparison.OrdinalIgnoreCase))
			{
				return "Morkhalla";
			}
			if (name.StartsWith("BearCave", StringComparison.OrdinalIgnoreCase))
			{
				return "Bear cave";
			}
			if (name.StartsWith("TheHole", StringComparison.OrdinalIgnoreCase))
			{
				return "The hole";
			}
			if (name.StartsWith("Dolmen", StringComparison.OrdinalIgnoreCase))
			{
				return "Dolmen";
			}
			if (name.StartsWith("TarPit", StringComparison.OrdinalIgnoreCase))
			{
				return "Tar pit";
			}
			if (name.StartsWith("DN_hut", StringComparison.OrdinalIgnoreCase))
			{
				return "Dn hut";
			}
			if (name.StartsWith("Grave", StringComparison.OrdinalIgnoreCase))
			{
				return "Grave";
			}
			if (name.StartsWith("Crypt", StringComparison.OrdinalIgnoreCase))
			{
				return "Burial Chambers";
			}
			if (name.StartsWith("Ruin", StringComparison.OrdinalIgnoreCase))
			{
				return "Ruin";
			}
			return null;
		}

		internal static bool IsService(string prefab)
		{
			if (Aio.TryGetValue(prefab ?? "", out var value))
			{
				return value.Service;
			}
			return false;
		}

		internal static float EnterRadius(float actualRadius)
		{
			return Math.Max(5f, Math.Min(18f, actualRadius * 0.5f));
		}

		internal static bool Entered(bool interiorLocation, bool inInterior, bool sameInterior, float horizontalDistanceSquared, float radius, float heightDifference)
		{
			if (!interiorLocation)
			{
				if (!inInterior && Math.Abs(heightDifference) <= 20f)
				{
					return horizontalDistanceSquared <= radius * radius;
				}
				return false;
			}
			return inInterior && sameInterior;
		}

		internal static bool KeepRecord(string kind)
		{
			if (!(kind == "Portal") && !(kind == "Dungeon"))
			{
				return kind == "Landmark";
			}
			return true;
		}

		internal static float Alpha(bool crossed, float faded)
		{
			if (!crossed)
			{
				return 1f;
			}
			return faded;
		}

		internal static bool MatchingSavedPin(string label, string expected, string prefab)
		{
			if (string.IsNullOrWhiteSpace(label))
			{
				return false;
			}
			string a = label.Trim();
			if (string.Equals(a, expected, StringComparison.OrdinalIgnoreCase) || string.Equals(a, prefab, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if ((prefab ?? "").StartsWith("Crypt", StringComparison.OrdinalIgnoreCase))
			{
				if (!string.Equals(a, "Burial Chamber", StringComparison.OrdinalIgnoreCase))
				{
					return string.Equals(a, "Burial Chambers", StringComparison.OrdinalIgnoreCase);
				}
				return true;
			}
			return false;
		}
	}
	internal static class ResourceGrouping
	{
		internal static Dictionary<string, List<Record>> Build(IEnumerable<Record> input)
		{
			Dictionary<string, List<Record>> dictionary = new Dictionary<string, List<Record>>();
			foreach (var item in from r in input
				group r by new
				{
					Kind = r.Kind,
					Name = ((r.Kind == "Ore") ? "" : (Policy.IsTar(r) ? "$tar" : r.Name))
				})
			{
				if (!Policy.Small(item.Key.Kind))
				{
					foreach (Record item2 in item)
					{
						dictionary.Add(item2.Key, new List<Record> { item2 });
					}
					continue;
				}
				float num = ((item.Key.Kind == "Ore" || item.Key.Name == "$tar") ? 32 : 12);
				float num2 = ((item.Key.Kind == "Ore" || item.Key.Name == "$tar") ? 12 : 4);
				Record[] list = item.OrderBy((Record r) => r.X).ThenBy<Record, string>((Record r) => r.Key, StringComparer.Ordinal).ToArray();
				int[] parent = Enumerable.Range(0, list.Length).ToArray();
				for (int num3 = 0; num3 < list.Length; num3++)
				{
					for (int num4 = num3 + 1; num4 < list.Length; num4++)
					{
						float num5 = list[num4].X - list[num3].X;
						if (num5 > num)
						{
							break;
						}
						float num6 = list[num4].Z - list[num3].Z;
						if (!(Math.Abs(list[num4].Y - list[num3].Y) > num2) && !(num5 * num5 + num6 * num6 > num * num))
						{
							int num7 = Root(parent, num3);
							int num8 = Root(parent, num4);
							if (num7 != num8)
							{
								parent[num8] = num7;
							}
						}
					}
				}
				foreach (IGrouping<int, int> item3 in from i in Enumerable.Range(0, list.Length)
					group i by Root(parent, i))
				{
					List<Record> list2 = item3.Select((int i) => list[i]).OrderBy<Record, string>((Record r) => r.Key, StringComparer.Ordinal).ToList();
					dictionary.Add("cluster:" + list2[0].Key, list2);
				}
			}
			return dictionary;
		}

		internal static string Label(Record first, int count)
		{
			if (!(first.Kind == "Ore") && !Policy.IsTar(first))
			{
				return first.Name + ((count > 1) ? (" x" + count) : "");
			}
			if (count <= 1)
			{
				return "";
			}
			return "×" + count;
		}

		private static int Root(int[] parent, int i)
		{
			while (parent[i] != i)
			{
				parent[i] = parent[parent[i]];
				i = parent[i];
			}
			return i;
		}
	}
}