Decompiled source of AutoPOIMarker v2.0.1

AutoPOIMarker.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: AssemblyTitle("Auto POI Marker - Valheim point-of-interest discovery")]
[assembly: AssemblyDescription("Client-side Valheim mod that announces nearby dungeons and marks configurable points of interest on the map.")]
[assembly: AssemblyCompany("Rollstuhltreter")]
[assembly: AssemblyProduct("Auto POI Marker")]
[assembly: AssemblyCopyright("Copyright (c) Rollstuhltreter")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("2.0.1.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;
		}
	}
}
[BepInPlugin("rollstuhltreter.valheim.autopoimarker", "Auto POI Marker", "2.0.1")]
public sealed class AutoPOIMarkerPlugin : BaseUnityPlugin
{
	private sealed class CachedLocation
	{
		internal object ZoneLocation;

		internal string SourceName;

		internal string PrefabName;

		internal Vector3 Position;

		internal bool IsDungeon;

		internal int Biome;
	}

	private sealed class PoiRule
	{
		internal int Biome;

		internal ConfigEntry<bool> Enabled;

		internal string[] NameFragments;

		internal bool Matches(int biome, string sourceName, string prefabName)
		{
			if (Biome != biome)
			{
				return false;
			}
			string searchText = GetSearchText(sourceName, prefabName);
			string[] nameFragments = NameFragments;
			foreach (string value in nameFragments)
			{
				if (searchText.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}
	}

	private sealed class MarkerOverride
	{
		internal string Name;

		internal PinType Icon;
	}

	private sealed class PortalPin
	{
		internal PinData Pin;

		internal bool Created;
	}

	private sealed class PortalDismissal
	{
		internal long World;

		internal Vector3 Position;

		internal string Name;
	}

	[HarmonyPatch(typeof(ResourceRoot), "Awake")]
	private static class ResourceRootAwakePatch
	{
		private static void Postfix(ResourceRoot __instance)
		{
			Instance?.RegisterYggdrasilRoot(__instance);
		}
	}

	[HarmonyPatch(typeof(ZNetScene), "CreateObject", new Type[] { typeof(ZDO) })]
	private static class ZNetSceneCreateObjectPatch
	{
		private static void Postfix(GameObject __result)
		{
			Instance?.RegisterYggdrasilRoot(__result);
			Instance?.RegisterResourceNode(__result);
		}
	}

	[HarmonyPatch(typeof(TeleportWorld), "Awake")]
	private static class TeleportWorldAwakePatch
	{
		private static void Postfix(TeleportWorld __instance)
		{
			Instance?.RegisterPortal(__instance);
		}
	}

	[HarmonyPatch(typeof(TeleportWorld), "SetText")]
	private static class TeleportWorldSetTextPatch
	{
		private static void Postfix(TeleportWorld __instance, string __0)
		{
			Instance?.PortalNameEntered(__instance, __0);
		}
	}

	[HarmonyPatch(typeof(Minimap), "RemovePin", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	private static class MinimapRemovePinAtPositionPatch
	{
		private static void Prefix()
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Instance._removingMapPin = true;
			}
		}

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

	[HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })]
	private static class MinimapRemovePinDataPatch
	{
		private static void Prefix(Minimap __instance, PinData __0)
		{
			Instance?.RememberPortalPinRemoval(__instance, __0);
		}
	}

	[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
	private static class ZDOManHandleDestroyedZDOPatch
	{
		private static void Prefix(ZDOMan __instance, ZDOID __0)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Instance?.RemovePortalMarker(__instance, __0);
		}
	}

	[HarmonyPatch(typeof(Location), "Awake")]
	private static class LocationAwakePatch
	{
		private static void Postfix(Location __instance)
		{
			Instance?.RegisterNetworkLocation(__instance);
		}
	}

	[HarmonyPatch(typeof(LocationProxy), "SpawnLocation")]
	private static class LocationProxySpawnPatch
	{
		private static void Postfix(LocationProxy __instance)
		{
			Instance?.RegisterLocationProxy(__instance);
		}
	}

	[HarmonyPatch(typeof(ZoneSystem), "CreateLocationProxy")]
	private static class CreateLocationProxyPatch
	{
		private static void Postfix(ZoneLocation __0, Vector3 __2)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Instance?.RegisterZoneLocation(__0, __2);
		}
	}

	[HarmonyPatch(typeof(ZoneSystem), "SpawnLocation")]
	private static class SpawnLocationPatch
	{
		private static void Postfix(ZoneLocation __0, Vector3 __2)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Instance?.RegisterZoneLocation(__0, __2);
		}
	}

	public const string PluginGuid = "rollstuhltreter.valheim.autopoimarker";

	public const string PluginName = "Auto POI Marker";

	public const string PluginVersion = "2.0.1";

	internal static ConfigEntry<bool> Enable;

	internal static ConfigEntry<float> DetectionRadius;

	internal static ConfigEntry<bool> MarkYggdrasilRoots;

	internal static ConfigEntry<bool> MarkCopperDeposits;

	internal static ConfigEntry<bool> MarkSilverVeins;

	internal static ConfigEntry<bool> MarkFlametalOreVeins;

	internal static ConfigEntry<bool> MarkTraders;

	internal static ConfigEntry<bool> MarkBosses;

	internal static ConfigEntry<bool> MarkPortals;

	internal static ConfigEntry<string> AdditionalPoiNames;

	internal static ConfigEntry<string> MarkerOverrides;

	internal static ConfigEntry<bool> ShowNotification;

	internal static ConfigEntry<bool> MarkOnMap;

	internal static ConfigEntry<bool> EnableDebugLogging;

	private static readonly BindingFlags InstanceNonPublic = BindingFlags.Instance | BindingFlags.NonPublic;

	private static readonly BindingFlags InstanceAny = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly FieldInfo LocationField = FindNestedField("LocationInstance", "m_location");

	private static readonly FieldInfo PositionField = FindNestedField("LocationInstance", "m_position");

	private static readonly FieldInfo NameField = typeof(ZoneLocation).GetField("m_name", InstanceAny);

	private static readonly FieldInfo PrefabNameField = typeof(ZoneLocation).GetField("m_prefabName", InstanceAny);

	private static readonly FieldInfo BiomeField = typeof(ZoneLocation).GetField("m_biome", InstanceAny);

	private static readonly FieldInfo LocationBiomeField = typeof(Location).GetField("m_biome", InstanceAny);

	private static readonly FieldInfo LocationProxyInstanceField = typeof(LocationProxy).GetField("m_instance", InstanceAny);

	private static readonly MethodInfo HaveSimilarPinMethod = typeof(Minimap).GetMethod("HaveSimilarPin", InstanceNonPublic);

	private static readonly FieldInfo MinimapPinsField = typeof(Minimap).GetField("m_pins", InstanceNonPublic);

	private const float LocationCellSize = 128f;

	private const float RescanDistance = 16f;

	private const float FlametalOreExtraRadius = 50f;

	private const int IndexEntriesPerFrame = 50;

	private static readonly string[] TraderLocations = new string[3] { "Vendor_BlackForest", "Hildir_camp", "BogWitch_Camp" };

	private static readonly string[] BossLocations = new string[9] { "Eikthyrnir", "GDKing", "Bonemass", "Dragonqueen", "GoblinKing", "Mistlands_DvergrBossEntrance", "FaderLocation", "DN_Bossroom", "FimbulLocation" };

	private static readonly string[] ResourceLocationNames = new string[4] { "LeviathanLava", "Mistlands_Giant", "TarPit", "DrakeNest" };

	private readonly HashSet<string> _announcedLocations = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private readonly HashSet<string> _markedLocations = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private readonly HashSet<ResourceRoot> _knownYggdrasilRoots = new HashSet<ResourceRoot>();

	private readonly HashSet<GameObject> _knownResourceNodes = new HashSet<GameObject>();

	private readonly HashSet<TeleportWorld> _knownPortals = new HashSet<TeleportWorld>();

	private readonly Dictionary<ZDOID, PortalPin> _portalPins = new Dictionary<ZDOID, PortalPin>();

	private readonly List<PortalDismissal> _portalDismissals = new List<PortalDismissal>();

	private readonly List<PoiRule> _poiRules = new List<PoiRule>();

	private readonly List<MarkerOverride> _markerOverrides = new List<MarkerOverride>();

	private readonly HashSet<string> _cachedLocationKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private readonly List<CachedLocation> _pendingNetworkLocations = new List<CachedLocation>();

	private Dictionary<Vector2Int, List<CachedLocation>> _locationBuckets;

	private ZoneSystem _indexedZoneSystem;

	private LocationInstance[] _locationSnapshot;

	private int _locationSnapshotIndex;

	private bool _locationIndexReady;

	private bool _loadedMineRocksIndexed;

	private bool _loadedPortalsIndexed;

	private bool _hasLastScanPosition;

	private bool _scanRequested;

	private Vector3 _lastScanPosition;

	private Harmony _harmony;

	private int _indexedLocationCount;

	private int _networkLocationCount;

	private int _rootRegistrationCount;

	private string _markerOverridesText;

	private float _nextPortalScan;

	private Minimap _portalMinimap;

	private string _portalDismissalsPath;

	private bool _removingMapPin;

	private static AutoPOIMarkerPlugin Instance;

	private void Awake()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		Instance = this;
		_harmony = new Harmony("rollstuhltreter.valheim.autopoimarker");
		_harmony.PatchAll();
		Enable = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable", true, "Enable nearby dungeon and point-of-interest discovery.");
		DetectionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DetectionRadius", 50f, "World-space radius in meters used to discover a location.");
		ConfigurePoiSettings();
		ShowNotification = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowNotification", true, "Show a large centered notification when a configured location is discovered.");
		MarkOnMap = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "MarkOnMap", true, "Add the discovered location to the map.");
		MarkPortals = ((BaseUnityPlugin)this).Config.Bind<bool>("Portals", "MarkPortals", true, "Mark nearby named portals with Valheim's portal icon. Existing portal pins are left unchanged.");
		MarkerOverrides = ((BaseUnityPlugin)this).Config.Bind<string>("Display", "MarkerOverrides", string.Empty, "Optional prefab-name overrides, separated by commas. 1 = dot, 2 = hammer, 3 = campfire. Example: rock4_copper \"1\", SunkenCrypt4 \"2\"");
		EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLogging", false, "Write detailed local POI discovery diagnostics to BepInEx/LogOutput.log. Disable this after testing.");
		_portalDismissalsPath = Path.Combine(Paths.ConfigPath, "rollstuhltreter.valheim.autopoimarker.dismissed-portals.dat");
		LoadPortalDismissals();
		DebugLog("Plugin initialized. Waiting for a world and player.");
	}

	private void ConfigurePoiSettings()
	{
		AddPoiRule("Black Forest", (Biome)8, "MarkBurialChambers", "Mark Burial Chambers.", "Crypt2", "Crypt3", "Crypt4", "Burial");
		AddPoiRule("Black Forest", (Biome)8, "MarkTrollCaves", "Mark Troll Caves.", "TrollCave");
		MarkCopperDeposits = ((BaseUnityPlugin)this).Config.Bind<bool>("Black Forest", "MarkCopperDeposits", true, "Mark nearby Copper Deposits.");
		AddPoiRule("Swamp", (Biome)2, "MarkSunkenCrypts", "Mark Sunken Crypts.", "SunkenCrypt");
		AddPoiRule("Swamp", (Biome)2, "MarkFireGeysers", "Mark Fire Geysers and Surtling spawns.", "FireHole", "Surtling");
		AddPoiRule("Mountains", (Biome)4, "MarkFrostCaves", "Mark Frost Caves.", "FrostCave", "MountainCave");
		MarkSilverVeins = ((BaseUnityPlugin)this).Config.Bind<bool>("Mountains", "MarkSilverVeins", true, "Mark nearby Silver Veins.");
		AddPoiRule("Mountains", (Biome)4, "MarkDragonNests", "Mark Dragon Nests.", "DrakeNest");
		AddPoiRule("Plains", (Biome)16, "MarkFulingVillages", "Mark Fuling Villages.", "GoblinCamp");
		AddPoiRule("Plains", (Biome)16, "MarkTarPits", "Mark Tar Pits.", "TarPit");
		AddPoiRule("Plains", (Biome)16, "MarkFulingOutpostsAndTowers", "Mark Fuling Outposts and Stone Towers.", "GoblinOutpost", "StoneTower");
		MarkYggdrasilRoots = ((BaseUnityPlugin)this).Config.Bind<bool>("Mistlands", "MarkYggdrasilRoots", true, "Mark nearby Yggdrasil Roots.");
		AddPoiRule("Mistlands", (Biome)512, "MarkInfestedMines", "Mark Infested Mines.", "InfestedMine");
		AddPoiRule("Mistlands", (Biome)512, "MarkDvergrOutposts", "Mark Dvergr Outposts and Towers.", "Mistlands_GuardTower", "DvergrTower", "DvergrCamp");
		AddPoiRule("Mistlands", (Biome)512, "MarkExcavationSites", "Mark Excavation Sites.", "Mistlands_Excavation");
		AddPoiRule("Mistlands", (Biome)512, "MarkHarbours", "Mark Dvergr Harbours.", "Mistlands_Harbour");
		AddPoiRule("Mistlands", (Biome)512, "MarkGiantRemains", "Mark Giant Remains containing Soft Tissue.", "Mistlands_Giant1", "Mistlands_Giant2");
		AddPoiRule("Ashlands", (Biome)32, "MarkCharredFortresses", "Mark Charred Fortresses.", "CharredFortress");
		AddPoiRule("Ashlands", (Biome)32, "MarkPutridHoles", "Mark Putrid Holes.", "MorgenHole", "PutridHole");
		MarkFlametalOreVeins = ((BaseUnityPlugin)this).Config.Bind<bool>("Ashlands", "MarkFlametalOreVeins", true, "Mark nearby Flametal Ore Veins.");
		AddPoiRule("Deep North", (Biome)64, "MarkAbandonedVillages", "Mark Abandoned Villages.", "NorthVillage");
		AddPoiRule("Deep North", (Biome)64, "MarkWindingTunnels", "Mark Winding Tunnels.", "TheHole");
		AddPoiRule("Deep North", (Biome)64, "MarkMorkhallaGates", "Mark Gates of Morkhalla.", "MorkBorg");
		AddPoiRule("Deep North", (Biome)64, "MarkJotunInvasions", "Mark Jotun Invasions when available.", "Jotun");
		MarkTraders = ((BaseUnityPlugin)this).Config.Bind<bool>("Traders and Bosses", "MarkTraders", false, "Mark trader camps in any biome.");
		MarkBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("Traders and Bosses", "MarkBosses", false, "Mark boss altars and entrances in any biome.");
		AdditionalPoiNames = ((BaseUnityPlugin)this).Config.Bind<string>("Additional POIs", "AdditionalPoiNames", string.Empty, "Additional POI name fragments to mark, separated by commas.");
	}

	private void AddPoiRule(string section, Biome biome, string key, string description, params string[] nameFragments)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Expected I4, but got Unknown
		_poiRules.Add(new PoiRule
		{
			Biome = (int)biome,
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>(section, key, true, description),
			NameFragments = nameFragments
		});
	}

	private void OnDestroy()
	{
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}

	private void DebugLog(string message)
	{
		if (EnableDebugLogging != null && EnableDebugLogging.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[POI Debug] " + message));
		}
	}

	private void Update()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		if (Enable == null || !Enable.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null)
		{
			return;
		}
		bool num = BuildLocationIndexStep(instance);
		ScanKnownPortals();
		if (num)
		{
			IndexLoadedMineRocks();
			Vector3 position = ((Component)localPlayer).transform.position;
			if (_scanRequested || !_hasLastScanPosition || !(HorizontalDistanceSquared(position, _lastScanPosition) < 256f))
			{
				_lastScanPosition = position;
				_hasLastScanPosition = true;
				_scanRequested = false;
				float num2 = SanitizeRadius(DetectionRadius.Value);
				float radiusSquared = num2 * num2;
				ScanNearbyLocations(position, num2, radiusSquared);
				ScanKnownYggdrasilRoots(position, radiusSquared);
				ScanKnownResourceNodes(position, radiusSquared);
			}
		}
	}

	private bool BuildLocationIndexStep(ZoneSystem zoneSystem)
	{
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_indexedZoneSystem != (Object)(object)zoneSystem || _locationBuckets == null)
		{
			_indexedZoneSystem = zoneSystem;
			_locationBuckets = new Dictionary<Vector2Int, List<CachedLocation>>();
			_cachedLocationKeys.Clear();
			_indexedLocationCount = 0;
			foreach (CachedLocation pendingNetworkLocation in _pendingNetworkLocations)
			{
				AddCachedLocation(pendingNetworkLocation);
			}
			_pendingNetworkLocations.Clear();
			_locationSnapshot = null;
			_locationSnapshotIndex = 0;
			_locationIndexReady = false;
			_loadedMineRocksIndexed = false;
			_loadedPortalsIndexed = false;
			_knownPortals.Clear();
			_portalPins.Clear();
			_portalMinimap = null;
			_nextPortalScan = 0f;
			_hasLastScanPosition = false;
			_scanRequested = true;
		}
		if (_locationIndexReady)
		{
			return true;
		}
		if (!zoneSystem.LocationsGenerated)
		{
			return true;
		}
		if (_locationSnapshot == null)
		{
			Dictionary<Vector2s, LocationInstance>.ValueCollection locationList = zoneSystem.GetLocationList();
			if (locationList == null)
			{
				DebugLog("World location list is unavailable. Continuing with server-loaded locations.");
				return true;
			}
			_locationSnapshot = (LocationInstance[])(object)new LocationInstance[locationList.Count];
			locationList.CopyTo(_locationSnapshot, 0);
			_locationSnapshotIndex = 0;
			DebugLog("Starting location index build.");
		}
		for (int i = 0; i < 50; i++)
		{
			if (_locationSnapshotIndex >= _locationSnapshot.Length)
			{
				break;
			}
			AddLocationToIndex(_locationSnapshot[_locationSnapshotIndex]);
			_locationSnapshotIndex++;
		}
		if (_locationSnapshotIndex < _locationSnapshot.Length)
		{
			return false;
		}
		_locationSnapshot = null;
		_locationIndexReady = true;
		DebugLog(string.Format(CultureInfo.InvariantCulture, "Location index ready. locations={0}, cells={1}, networkLocations={2}, roots={3}.", _indexedLocationCount, _locationBuckets.Count, _networkLocationCount, _rootRegistrationCount));
		return true;
	}

	private void AddLocationToIndex(LocationInstance instance)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: 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)
		object obj = ((LocationField == null) ? null : LocationField.GetValue(instance));
		if (obj != null && ((PositionField == null) ? null : PositionField.GetValue(instance)) is Vector3 position)
		{
			string text = ReadString(obj, NameField);
			string text2 = ReadString(obj, PrefabNameField);
			string text3 = (string.IsNullOrWhiteSpace(text) ? text2 : text);
			if (!string.IsNullOrWhiteSpace(text3) && !IsExcludedLocation(text3, text2))
			{
				CachedLocation location = new CachedLocation
				{
					ZoneLocation = obj,
					SourceName = text3,
					PrefabName = text2,
					Position = position,
					IsDungeon = IsDungeon(text3, text2),
					Biome = ReadBiome(obj)
				};
				AddCachedLocation(location);
			}
		}
	}

	private void AddCachedLocation(CachedLocation location)
	{
		//IL_001b: 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_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		if (IsExcludedLocation(location.SourceName, location.PrefabName))
		{
			return;
		}
		string item = BuildLocationKey(location.SourceName, location.Position);
		if (_cachedLocationKeys.Add(item))
		{
			Vector2Int locationCell = GetLocationCell(location.Position);
			if (!_locationBuckets.TryGetValue(locationCell, out var value))
			{
				value = new List<CachedLocation>();
				_locationBuckets.Add(locationCell, value);
			}
			value.Add(location);
			_indexedLocationCount++;
		}
	}

	private void ScanNearbyLocations(Vector3 playerPosition, float radius, float radiusSquared)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0289: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		float num = (MarkFlametalOreVeins.Value ? (radius + 50f) : radius);
		int num2 = Mathf.CeilToInt(num / 128f);
		Vector2Int locationCell = GetLocationCell(playerPosition);
		int num3 = 0;
		int num4 = 0;
		int num5 = 0;
		int num6 = 0;
		for (int i = ((Vector2Int)(ref locationCell)).x - num2; i <= ((Vector2Int)(ref locationCell)).x + num2; i++)
		{
			for (int j = ((Vector2Int)(ref locationCell)).y - num2; j <= ((Vector2Int)(ref locationCell)).y + num2; j++)
			{
				if (!_locationBuckets.TryGetValue(new Vector2Int(i, j), out var value))
				{
					continue;
				}
				foreach (CachedLocation item2 in value)
				{
					num3++;
					float num7 = playerPosition.x - item2.Position.x;
					float num8 = playerPosition.z - item2.Position.z;
					float num9 = ((IsFlametalLocation(item2) && MarkFlametalOreVeins.Value) ? (num * num) : radiusSquared);
					if (num7 * num7 + num8 * num8 > num9)
					{
						continue;
					}
					num4++;
					if (!ShouldTrack(item2, out var builtIn))
					{
						continue;
					}
					num5++;
					string item = BuildLocationKey(item2.SourceName, item2.Position);
					bool num10 = !ShowNotification.Value || _announcedLocations.Contains(item);
					bool flag = !MarkOnMap.Value || _markedLocations.Contains(item);
					if (!(num10 && flag))
					{
						string displayName = GetDisplayName(item2.SourceName, item2.PrefabName);
						if (MarkOnMap.Value && !_markedLocations.Contains(item) && (Object)(object)Minimap.instance != (Object)null)
						{
							PinType defaultIcon = (PinType)((!builtIn) ? 2 : ((int)GetDefaultLocationIcon(item2)));
							PinType icon = ResolveMarkerIcon(item2.SourceName, item2.PrefabName, displayName, defaultIcon);
							AddMapMarker(item2.Position, displayName, icon);
							_markedLocations.Add(item);
							num6++;
						}
						if (ShowNotification.Value && !_announcedLocations.Contains(item) && (Object)(object)MessageHud.instance != (Object)null)
						{
							MessageHud.instance.ShowMessage((MessageType)2, displayName + " found!", 0, (Sprite)null, false, false);
							_announcedLocations.Add(item);
						}
					}
				}
			}
		}
		DebugLog(string.Format(CultureInfo.InvariantCulture, "Scan at ({0:0}, {1:0}): candidates={2}, nearby={3}, accepted={4}, pinsAdded={5}.", playerPosition.x, playerPosition.z, num3, num4, num5, num6));
	}

	private void ScanKnownYggdrasilRoots(Vector3 playerPosition, float radiusSquared)
	{
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: 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_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		if (MarkYggdrasilRoots == null || !MarkYggdrasilRoots.Value)
		{
			return;
		}
		_knownYggdrasilRoots.RemoveWhere((ResourceRoot root) => (Object)(object)root == (Object)null);
		int num = 0;
		int num2 = 0;
		foreach (ResourceRoot knownYggdrasilRoot in _knownYggdrasilRoots)
		{
			if ((Object)(object)knownYggdrasilRoot == (Object)null || (Object)(object)((Component)knownYggdrasilRoot).gameObject == (Object)null || ((Object)((Component)knownYggdrasilRoot).gameObject).name.IndexOf("YggdrasilRoot", StringComparison.OrdinalIgnoreCase) < 0)
			{
				continue;
			}
			Vector3 position = ((Component)knownYggdrasilRoot).transform.position;
			float num3 = playerPosition.x - position.x;
			float num4 = playerPosition.z - position.z;
			if (!(num3 * num3 + num4 * num4 > radiusSquared))
			{
				num++;
				string item = BuildLocationKey("YggdrasilRoot", position);
				if (MarkOnMap.Value && !_markedLocations.Contains(item) && (Object)(object)Minimap.instance != (Object)null)
				{
					PinType icon = ResolveMarkerIcon(((Object)((Component)knownYggdrasilRoot).gameObject).name, "YggdrasilRoot", "Ancient Root", (PinType)3);
					AddMapMarker(position, "Ancient Root", icon);
					_markedLocations.Add(item);
					num2++;
				}
				if (ShowNotification.Value && !_announcedLocations.Contains(item) && (Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)2, "Ancient Root found!", 0, (Sprite)null, false, false);
					_announcedLocations.Add(item);
				}
			}
		}
		DebugLog(string.Format(CultureInfo.InvariantCulture, "Root scan: registered={0}, nearby={1}, pinsAdded={2}.", _knownYggdrasilRoots.Count, num, num2));
	}

	private void RegisterYggdrasilRoot(ResourceRoot root)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)root != (Object)null && ((Object)((Component)root).gameObject).name.IndexOf("YggdrasilRoot", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			if (_knownYggdrasilRoots.Add(root))
			{
				_rootRegistrationCount++;
				DebugLog(string.Format(CultureInfo.InvariantCulture, "Registered Ancient Root at ({0:0}, {1:0}).", ((Component)root).transform.position.x, ((Component)root).transform.position.z));
			}
			RequestScan();
		}
	}

	private void RegisterYggdrasilRoot(GameObject gameObject)
	{
		if (!((Object)(object)gameObject == (Object)null))
		{
			RegisterYggdrasilRoot(gameObject.GetComponentInChildren<ResourceRoot>(true));
		}
	}

	private void RegisterPortal(TeleportWorld portal)
	{
		if ((Object)(object)portal != (Object)null && _knownPortals.Add(portal))
		{
			_nextPortalScan = 0f;
		}
	}

	private void LoadPortalDismissals()
	{
		//IL_009b: 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)
		if (!File.Exists(_portalDismissalsPath))
		{
			return;
		}
		try
		{
			string[] array = File.ReadAllLines(_portalDismissalsPath);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' }, 4);
				if (array2.Length == 4 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
				{
					try
					{
						_portalDismissals.Add(new PortalDismissal
						{
							World = result,
							Position = new Vector3(result2, 0f, result3),
							Name = Encoding.UTF8.GetString(Convert.FromBase64String(array2[3]))
						});
					}
					catch (FormatException)
					{
					}
				}
			}
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not read dismissed portal pins: " + ex2.Message));
		}
	}

	private void SavePortalDismissals()
	{
		string[] array = new string[_portalDismissals.Count];
		for (int i = 0; i < _portalDismissals.Count; i++)
		{
			PortalDismissal portalDismissal = _portalDismissals[i];
			array[i] = string.Join("|", portalDismissal.World.ToString(CultureInfo.InvariantCulture), portalDismissal.Position.x.ToString("R", CultureInfo.InvariantCulture), portalDismissal.Position.z.ToString("R", CultureInfo.InvariantCulture), Convert.ToBase64String(Encoding.UTF8.GetBytes(portalDismissal.Name)));
		}
		try
		{
			File.WriteAllLines(_portalDismissalsPath, array, Encoding.UTF8);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not save dismissed portal pins: " + ex.Message));
		}
	}

	private static long CurrentWorldId()
	{
		if (!((Object)(object)ZNet.instance == (Object)null))
		{
			return ZNet.instance.GetWorldUID();
		}
		return 0L;
	}

	private bool IsPortalDismissed(long world, Vector3 position, string name)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		foreach (PortalDismissal portalDismissal in _portalDismissals)
		{
			if (portalDismissal.World == world && string.Equals(portalDismissal.Name, name, StringComparison.Ordinal) && HorizontalDistanceSquared(portalDismissal.Position, position) <= 2.25f)
			{
				return true;
			}
		}
		return false;
	}

	private void ClearPortalDismissals(long world, Vector3 position, string currentName, bool mismatchedOnly)
	{
		//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)
		float maxDistanceSquared = (mismatchedOnly ? 0.25f : 2.25f);
		if (_portalDismissals.RemoveAll((PortalDismissal dismissal) => dismissal.World == world && HorizontalDistanceSquared(dismissal.Position, position) <= maxDistanceSquared && (!mismatchedOnly || !string.Equals(dismissal.Name, currentName, StringComparison.Ordinal))) > 0)
		{
			SavePortalDismissals();
		}
	}

	private void RememberPortalPinRemoval(Minimap minimap, PinData pin)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Invalid comparison between Unknown and I4
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		if (_removingMapPin && pin != null && pin.m_save && (int)pin.m_type == 6 && !string.IsNullOrWhiteSpace(pin.m_name) && !((Object)(object)minimap != (Object)(object)Minimap.instance) && !((Object)(object)Player.m_localPlayer == (Object)null))
		{
			long num = CurrentWorldId();
			if (num != 0L && !IsPortalDismissed(num, pin.m_pos, pin.m_name))
			{
				_portalDismissals.Add(new PortalDismissal
				{
					World = num,
					Position = pin.m_pos,
					Name = pin.m_name
				});
				SavePortalDismissals();
			}
		}
	}

	private void PortalNameEntered(TeleportWorld portal, string name)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)portal == (Object)null) && !string.IsNullOrWhiteSpace(name))
		{
			long num = CurrentWorldId();
			if (num != 0L)
			{
				ClearPortalDismissals(num, ((Component)portal).transform.position, null, mismatchedOnly: false);
			}
			_nextPortalScan = 0f;
		}
	}

	private void ScanKnownPortals()
	{
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_0256: Unknown result type (might be due to invalid IL or missing references)
		if (MarkPortals == null || !MarkPortals.Value || MarkOnMap == null || !MarkOnMap.Value)
		{
			return;
		}
		Minimap instance = Minimap.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		if ((Object)(object)_portalMinimap != (Object)(object)instance)
		{
			_portalMinimap = instance;
			_portalPins.Clear();
			_loadedPortalsIndexed = false;
			_nextPortalScan = 0f;
		}
		if (!_loadedPortalsIndexed)
		{
			TeleportWorld[] array = Object.FindObjectsByType<TeleportWorld>((FindObjectsSortMode)0);
			foreach (TeleportWorld item in array)
			{
				_knownPortals.Add(item);
			}
			_loadedPortalsIndexed = true;
		}
		if (Time.unscaledTime < _nextPortalScan)
		{
			return;
		}
		_nextPortalScan = Time.unscaledTime + 2f;
		_knownPortals.RemoveWhere((TeleportWorld portal) => (Object)(object)portal == (Object)null);
		List<PinData> list = MinimapPinsField?.GetValue(instance) as List<PinData>;
		foreach (TeleportWorld knownPortal in _knownPortals)
		{
			ZNetView component = ((Component)knownPortal).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component == (Object)null) ? null : component.GetZDO());
			if (val == null)
			{
				continue;
			}
			ZDOID uid = val.m_uid;
			string text = val.GetString(ZDOVars.s_tag, string.Empty);
			Vector3 position = ((Component)knownPortal).transform.position;
			long num = CurrentWorldId();
			if (string.IsNullOrWhiteSpace(text))
			{
				if (num != 0L)
				{
					ClearPortalDismissals(num, position, null, mismatchedOnly: false);
				}
				if (_portalPins.TryGetValue(uid, out var value))
				{
					if (value.Created && (list == null || list.Contains(value.Pin)))
					{
						instance.RemovePin(value.Pin);
					}
					_portalPins.Remove(uid);
				}
				continue;
			}
			if (num != 0L)
			{
				ClearPortalDismissals(num, position, text, mismatchedOnly: true);
				if (IsPortalDismissed(num, position, text))
				{
					_portalPins.Remove(uid);
					continue;
				}
			}
			if (_portalPins.TryGetValue(uid, out var value2))
			{
				if (list == null || list.Contains(value2.Pin))
				{
					if (value2.Created)
					{
						value2.Pin.m_name = text;
					}
					continue;
				}
				_portalPins.Remove(uid);
			}
			PinData val2 = FindPortalPin(list, position, text);
			if (val2 != null)
			{
				if (string.Equals(val2.m_name, text, StringComparison.Ordinal))
				{
					_portalPins[uid] = new PortalPin
					{
						Pin = val2
					};
				}
			}
			else
			{
				PinData pin = instance.AddPin(position, (PinType)6, text, true, false, 0L, default(PlatformUserID));
				_portalPins[uid] = new PortalPin
				{
					Pin = pin,
					Created = true
				};
			}
		}
	}

	private void RemovePortalMarker(ZDOMan manager, ZDOID id)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		PortalPin value;
		bool flag = _portalPins.TryGetValue(id, out value);
		ZDO val = null;
		if (!flag)
		{
			val = manager.GetZDO(id);
			if (val == null || (Object)(object)Game.instance == (Object)null || !Game.instance.PortalPrefabHash.Contains(val.GetPrefab()))
			{
				return;
			}
		}
		long num = CurrentWorldId();
		if (num != 0L)
		{
			ClearPortalDismissals(num, flag ? value.Pin.m_pos : val.GetPosition(), null, mismatchedOnly: false);
		}
		Minimap instance = Minimap.instance;
		if ((Object)(object)instance == (Object)null)
		{
			_portalPins.Remove(id);
			return;
		}
		List<PinData> list = MinimapPinsField?.GetValue(instance) as List<PinData>;
		if (flag)
		{
			if (list == null || list.Contains(value.Pin))
			{
				instance.RemovePin(value.Pin);
			}
			_portalPins.Remove(id);
			return;
		}
		string text = val.GetString(ZDOVars.s_tag, string.Empty);
		if (!string.IsNullOrWhiteSpace(text))
		{
			PinData val2 = FindPortalPin(list, val.GetPosition(), text);
			if (val2 != null && string.Equals(val2.m_name, text, StringComparison.Ordinal))
			{
				instance.RemovePin(val2);
			}
		}
	}

	private static PinData FindPortalPin(List<PinData> pins, Vector3 position, string name)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Invalid comparison between Unknown and I4
		//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)
		if (pins == null)
		{
			return null;
		}
		PinData val = null;
		float num = 9f;
		int num2 = 1;
		foreach (PinData pin in pins)
		{
			if (pin.m_save && (int)pin.m_type == 6)
			{
				float num3 = HorizontalDistanceSquared(pin.m_pos, position);
				int num4 = ((!string.Equals(pin.m_name, name, StringComparison.Ordinal)) ? 1 : 0);
				if (num3 <= 9f && (val == null || num4 < num2 || (num4 == num2 && num3 < num)))
				{
					val = pin;
					num = num3;
					num2 = num4;
				}
			}
		}
		return val;
	}

	private void ScanKnownResourceNodes(Vector3 playerPosition, float radiusSquared)
	{
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		_knownResourceNodes.RemoveWhere((GameObject node) => (Object)(object)node == (Object)null);
		foreach (GameObject knownResourceNode in _knownResourceNodes)
		{
			string resourceNodeDisplayName = GetResourceNodeDisplayName(knownResourceNode);
			if (string.IsNullOrEmpty(resourceNodeDisplayName))
			{
				continue;
			}
			Vector3 position = knownResourceNode.transform.position;
			float num = playerPosition.x - position.x;
			float num2 = playerPosition.z - position.z;
			if (!(num * num + num2 * num2 > radiusSquared))
			{
				string item = BuildLocationKey(resourceNodeDisplayName, position);
				if (MarkOnMap.Value && !_markedLocations.Contains(item) && (Object)(object)Minimap.instance != (Object)null)
				{
					PinType icon = ResolveMarkerIcon(((Object)knownResourceNode).name, string.Empty, resourceNodeDisplayName, (PinType)3);
					AddMapMarker(position, resourceNodeDisplayName, icon);
					_markedLocations.Add(item);
				}
				if (ShowNotification.Value && !_announcedLocations.Contains(item) && (Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)2, resourceNodeDisplayName + " found!", 0, (Sprite)null, false, false);
					_announcedLocations.Add(item);
				}
			}
		}
	}

	private void RegisterResourceNode(GameObject gameObject)
	{
		if ((Object)(object)gameObject == (Object)null)
		{
			return;
		}
		Transform[] componentsInChildren = ((Component)gameObject.transform.root).GetComponentsInChildren<Transform>(true);
		foreach (Transform val in componentsInChildren)
		{
			if (IsKnownResourceNode(((Component)val).gameObject) && _knownResourceNodes.Add(((Component)val).gameObject))
			{
				RequestScan();
			}
		}
	}

	private void IndexLoadedMineRocks()
	{
		if (!_loadedMineRocksIndexed)
		{
			MineRock[] array = Object.FindObjectsByType<MineRock>((FindObjectsSortMode)0);
			foreach (MineRock val in array)
			{
				RegisterResourceNode(((Component)val).gameObject);
			}
			MineRock5[] array2 = Object.FindObjectsByType<MineRock5>((FindObjectsSortMode)0);
			foreach (MineRock5 val2 in array2)
			{
				RegisterResourceNode(((Component)val2).gameObject);
			}
			_loadedMineRocksIndexed = true;
		}
	}

	private static string GetResourceNodeDisplayName(GameObject gameObject)
	{
		if ((Object)(object)gameObject == (Object)null)
		{
			return null;
		}
		string name = ((Object)gameObject).name;
		if (MarkCopperDeposits != null && MarkCopperDeposits.Value && IsCopperDeposit(name))
		{
			return "Copper Deposit";
		}
		if (MarkSilverVeins != null && MarkSilverVeins.Value && name.IndexOf("SilverVein", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "Silver Vein";
		}
		return null;
	}

	private static bool IsKnownResourceNode(GameObject gameObject)
	{
		if ((Object)(object)gameObject == (Object)null)
		{
			return false;
		}
		string name = ((Object)gameObject).name;
		if (!IsCopperDeposit(name))
		{
			return name.IndexOf("SilverVein", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return true;
	}

	private static bool IsCopperDeposit(string name)
	{
		if (!name.StartsWith("rock4_copper", StringComparison.OrdinalIgnoreCase) && !name.StartsWith("MineRock_Copper", StringComparison.OrdinalIgnoreCase))
		{
			return name.StartsWith("CopperDeposit", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	private static int ResolveLocationBiome(string sourceName, string prefabName, int biome)
	{
		if (biome != 0)
		{
			return biome;
		}
		string text = sourceName + " " + prefabName;
		if (text.IndexOf("MorgenHole", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("CharredFortress", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return 32;
		}
		return biome;
	}

	private void RegisterNetworkLocation(Location location)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)location == (Object)null) && !((Object)(object)((Component)location).gameObject == (Object)null))
		{
			RegisterLoadedLocation(((Object)((Component)location).gameObject).name, ((Object)((Component)location).gameObject).name, ((Component)location).transform.position, ReadBiome(location, LocationBiomeField));
		}
	}

	private void RegisterZoneLocation(ZoneLocation zoneLocation, Vector3 position)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (zoneLocation != null)
		{
			string sourceName = ReadString(zoneLocation, NameField);
			string prefabName = ReadString(zoneLocation, PrefabNameField);
			RegisterLoadedLocation(sourceName, prefabName, position, ReadBiome(zoneLocation));
		}
	}

	private void RegisterLocationProxy(LocationProxy proxy)
	{
		if (!((Object)(object)proxy == (Object)null) && !(LocationProxyInstanceField == null))
		{
			object? value = LocationProxyInstanceField.GetValue(proxy);
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				DebugLog("Location proxy spawned without an instantiated location object.");
			}
			else
			{
				RegisterNetworkLocation(val.GetComponentInChildren<Location>(true));
			}
		}
	}

	private void RegisterLoadedLocation(string sourceName, string prefabName, Vector3 position, int biome)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		if (IsExcludedLocation(sourceName, prefabName))
		{
			return;
		}
		if (string.IsNullOrWhiteSpace(sourceName))
		{
			sourceName = prefabName;
		}
		if (!string.IsNullOrWhiteSpace(sourceName))
		{
			biome = ResolveLocationBiome(sourceName, prefabName, biome);
			CachedLocation cachedLocation = new CachedLocation
			{
				SourceName = sourceName,
				PrefabName = prefabName,
				Position = position,
				IsDungeon = IsDungeon(sourceName, prefabName),
				Biome = biome
			};
			_networkLocationCount++;
			DebugLog(string.Format(CultureInfo.InvariantCulture, "Registered server location '{0}' / '{1}' at ({2:0}, {3:0}), biome={4}, dungeon={5}, accepted={6}.", sourceName, prefabName, position.x, position.z, biome, cachedLocation.IsDungeon, ShouldTrack(cachedLocation)));
			if (_locationBuckets == null)
			{
				_pendingNetworkLocations.Add(cachedLocation);
				RequestScan();
			}
			else
			{
				AddCachedLocation(cachedLocation);
				RequestScan();
			}
		}
	}

	private void RequestScan()
	{
		_scanRequested = true;
	}

	private static Vector2Int GetLocationCell(Vector3 position)
	{
		//IL_0000: 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_0022: Unknown result type (might be due to invalid IL or missing references)
		return new Vector2Int(Mathf.FloorToInt(position.x / 128f), Mathf.FloorToInt(position.z / 128f));
	}

	private static float HorizontalDistanceSquared(Vector3 first, Vector3 second)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		float num = first.x - second.x;
		float num2 = first.z - second.z;
		return num * num + num2 * num2;
	}

	private static void AddMapMarker(Vector3 position, string shortName, PinType icon)
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: 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)
		Minimap instance = Minimap.instance;
		if (!(HaveSimilarPinMethod != null) || !(bool)HaveSimilarPinMethod.Invoke(instance, new object[4] { position, icon, shortName, true }))
		{
			instance.AddPin(position, icon, shortName, true, false, 0L, default(PlatformUserID));
		}
	}

	private bool ShouldTrack(CachedLocation location)
	{
		bool builtIn;
		return ShouldTrack(location, out builtIn);
	}

	private bool ShouldTrack(CachedLocation location, out bool builtIn)
	{
		builtIn = true;
		if (IsExcludedLocation(location.SourceName, location.PrefabName))
		{
			return false;
		}
		if (MarkFlametalOreVeins != null && MarkFlametalOreVeins.Value && IsFlametalLocation(location))
		{
			return true;
		}
		string searchText = GetSearchText(location.SourceName, location.PrefabName);
		if (MarkTraders != null && MarkTraders.Value && MatchesLocation(searchText, TraderLocations))
		{
			return true;
		}
		if (MarkBosses != null && MarkBosses.Value && MatchesLocation(searchText, BossLocations))
		{
			return true;
		}
		foreach (PoiRule poiRule in _poiRules)
		{
			if (poiRule.Enabled.Value && poiRule.Matches(location.Biome, location.SourceName, location.PrefabName))
			{
				return true;
			}
		}
		builtIn = false;
		return MatchesAdditionalPoiFilter(location);
	}

	private static PinType GetDefaultLocationIcon(CachedLocation location)
	{
		string searchText = GetSearchText(location.SourceName, location.PrefabName);
		if (searchText.IndexOf("FireHole", StringComparison.OrdinalIgnoreCase) < 0 && searchText.IndexOf("Surtling", StringComparison.OrdinalIgnoreCase) < 0)
		{
			string[] resourceLocationNames = ResourceLocationNames;
			foreach (string value in resourceLocationNames)
			{
				if (searchText.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return (PinType)3;
				}
			}
			return (PinType)2;
		}
		return (PinType)0;
	}

	private PinType ResolveMarkerIcon(string sourceName, string prefabName, string displayName, PinType defaultIcon)
	{
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		string text = MarkerOverrides?.Value ?? string.Empty;
		if (!string.Equals(text, _markerOverridesText, StringComparison.Ordinal))
		{
			_markerOverridesText = text;
			_markerOverrides.Clear();
			string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				Match match = Regex.Match(array[i], "^\\s*(?<name>.+?)(?:\\s+|=|:)\\s*\"?(?<icon>[123])\"?\\s*$");
				if (match.Success)
				{
					string text2 = NormalizeMarkerName(match.Groups["name"].Value);
					if (text2.Length != 0)
					{
						char c = match.Groups["icon"].Value[0];
						_markerOverrides.Add(new MarkerOverride
						{
							Name = text2,
							Icon = (PinType)(c switch
							{
								'2' => 2, 
								'1' => 3, 
								_ => 0, 
							})
						});
					}
				}
			}
		}
		PinType result = defaultIcon;
		int num = 0;
		string prefabName2 = NormalizeMarkerName(sourceName);
		string prefabName3 = NormalizeMarkerName(prefabName);
		foreach (MarkerOverride markerOverride in _markerOverrides)
		{
			if (markerOverride.Name.Length >= num && (MatchesMarkerPrefab(markerOverride.Name, prefabName2) || MatchesMarkerPrefab(markerOverride.Name, prefabName3)))
			{
				result = markerOverride.Icon;
				num = markerOverride.Name.Length;
			}
		}
		if (num > 0)
		{
			return result;
		}
		string b = NormalizeMarkerName(displayName);
		foreach (MarkerOverride markerOverride2 in _markerOverrides)
		{
			if (string.Equals(markerOverride2.Name, b, StringComparison.OrdinalIgnoreCase))
			{
				result = markerOverride2.Icon;
			}
		}
		return result;
	}

	private static string NormalizeMarkerName(string name)
	{
		if (string.IsNullOrWhiteSpace(name))
		{
			return string.Empty;
		}
		name = name.Trim().Trim(new char[1] { '"' }).Trim();
		int num = Math.Max(name.LastIndexOf('/'), name.LastIndexOf('\\'));
		if (num >= 0)
		{
			name = name.Substring(num + 1);
		}
		if (name.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase))
		{
			name = name.Substring(0, name.Length - "(Clone)".Length).TrimEnd(Array.Empty<char>());
		}
		return name;
	}

	private static bool MatchesMarkerPrefab(string configuredName, string prefabName)
	{
		if (string.Equals(configuredName, prefabName, StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		if (configuredName.Length == 0 || prefabName.Length <= configuredName.Length || char.IsDigit(configuredName[configuredName.Length - 1]) || !prefabName.StartsWith(configuredName, StringComparison.OrdinalIgnoreCase))
		{
			return false;
		}
		for (int i = configuredName.Length; i < prefabName.Length; i++)
		{
			if (!char.IsDigit(prefabName[i]))
			{
				return false;
			}
		}
		return true;
	}

	private static bool IsFlametalLocation(CachedLocation location)
	{
		if (!location.SourceName.StartsWith("LeviathanLava", StringComparison.OrdinalIgnoreCase))
		{
			return location.PrefabName.StartsWith("LeviathanLava", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	private static bool MatchesLocation(string name, string[] locations)
	{
		foreach (string value in locations)
		{
			if (name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
		}
		return false;
	}

	private bool MatchesAdditionalPoiFilter(CachedLocation location)
	{
		if (AdditionalPoiNames == null || string.IsNullOrWhiteSpace(AdditionalPoiNames.Value))
		{
			return false;
		}
		string searchText = GetSearchText(location.SourceName, location.PrefabName);
		string[] array = AdditionalPoiNames.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
		foreach (string text in array)
		{
			if (searchText.IndexOf(text.Trim(), StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
		}
		return false;
	}

	private static string GetSearchText(string sourceName, string prefabName)
	{
		string text = sourceName + " " + prefabName;
		if (!IsInfestedMineEntrance(sourceName, prefabName))
		{
			return text;
		}
		return text + " InfestedMine";
	}

	private static bool IsDungeon(string name, string prefabName)
	{
		string text = (name + " " + prefabName).ToLowerInvariant();
		string[] array = new string[14]
		{
			"crypt", "cave", "dungeon", "mine", "catacomb", "tomb", "burial", "sunken", "infested", "morgenhole",
			"thedarkesthole", "thehole", "dvergrtownentrance", "hildir_plainsfortress"
		};
		foreach (string value in array)
		{
			if (text.Contains(value))
			{
				return true;
			}
		}
		return false;
	}

	private static bool IsInfestedMineEntrance(string sourceName, string prefabName)
	{
		string text = sourceName + " " + prefabName;
		if (text.IndexOf("DvergrTownEntrance", StringComparison.OrdinalIgnoreCase) < 0)
		{
			return text.IndexOf("InfestedMine", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return true;
	}

	private static string GetDisplayName(string sourceName, string prefabName)
	{
		string text = sourceName + " " + prefabName;
		if (sourceName.StartsWith("LeviathanLava", StringComparison.OrdinalIgnoreCase) || prefabName.StartsWith("LeviathanLava", StringComparison.OrdinalIgnoreCase))
		{
			return "Flametal Ore Vein";
		}
		if (text.IndexOf("Mistlands_GuardTower", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "Guard Tower";
		}
		if (text.IndexOf("Mistlands_Giant1", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Mistlands_Giant2", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "Giant Remains";
		}
		if (text.IndexOf("Vendor_BlackForest", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "Haldor";
		}
		if (text.IndexOf("Hildir_camp", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "Hildir";
		}
		if (text.IndexOf("BogWitch_Camp", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "Bog Witch";
		}
		if (IsInfestedMineEntrance(sourceName, prefabName))
		{
			return "Infested Mine";
		}
		if (text.IndexOf("MorgenHole", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("PutridHole", StringComparison.OrdinalIgnoreCase) < 0)
		{
			return MakeShortName(sourceName);
		}
		return "Putrid Hole";
	}

	private static bool IsExcludedLocation(string sourceName, string prefabName)
	{
		string text = sourceName + " " + prefabName;
		if (text.IndexOf("InfestedTree", StringComparison.OrdinalIgnoreCase) < 0)
		{
			return text.IndexOf("Infested Tree", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return true;
	}

	private static string MakeShortName(string rawName)
	{
		string text = rawName;
		int num = Math.Max(text.LastIndexOf('/'), text.LastIndexOf('\\'));
		if (num >= 0 && num + 1 < text.Length)
		{
			text = text.Substring(num + 1);
		}
		text = Regex.Replace(text, "\\s*\\(Clone\\)\\s*$", string.Empty, RegexOptions.IgnoreCase);
		text = Regex.Replace(text, "\\d+", string.Empty);
		text = Regex.Replace(text, "(?<!^)([A-Z])", " $1");
		text = Regex.Replace(text, "[_-]+", " ");
		text = Regex.Replace(text, "\\s+", " ").Trim();
		if (text.Length > 28)
		{
			text = text.Substring(0, 28).TrimEnd(Array.Empty<char>());
		}
		if (!string.IsNullOrWhiteSpace(text))
		{
			return text;
		}
		return "Unknown location";
	}

	private static string BuildLocationKey(string name, Vector3 position)
	{
		//IL_0010: 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)
		return string.Format(CultureInfo.InvariantCulture, "{0}|{1:0}|{2:0}", MakeShortName(name), position.x, position.z);
	}

	private static int ReadBiome(object zoneLocation)
	{
		return ReadBiome(zoneLocation, BiomeField);
	}

	private static int ReadBiome(object instance, FieldInfo field)
	{
		if (instance == null || field == null)
		{
			return 0;
		}
		object value = field.GetValue(instance);
		if (value != null)
		{
			return Convert.ToInt32(value, CultureInfo.InvariantCulture);
		}
		return 0;
	}

	private static string ReadString(object instance, FieldInfo field)
	{
		object obj;
		if (!(field == null))
		{
			obj = field.GetValue(instance) as string;
			if (obj == null)
			{
				return string.Empty;
			}
		}
		else
		{
			obj = string.Empty;
		}
		return (string)obj;
	}

	private static FieldInfo FindNestedField(string nestedTypeName, string fieldName)
	{
		Type nestedType = typeof(ZoneSystem).GetNestedType(nestedTypeName, BindingFlags.Public | BindingFlags.NonPublic);
		if (!(nestedType == null))
		{
			return nestedType.GetField(fieldName, InstanceAny);
		}
		return null;
	}

	private static float SanitizeRadius(float value)
	{
		if (float.IsNaN(value) || float.IsInfinity(value))
		{
			return 100f;
		}
		return Mathf.Clamp(value, 1f, 1000f);
	}
}