Decompiled source of HTFMapLoader v0.2.8

BepInEx/plugins/HTFMapLoader.dll

Decompiled 6 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.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("HTFMapLoader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HTFMapLoader")]
[assembly: AssemblyTitle("HTFMapLoader")]
[assembly: AssemblyVersion("1.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 HTFMapLoader
{
	[BepInPlugin("com.howtofish.maploader", "HTF Map Loader", "0.2.8")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		[Serializable]
		public sealed class MapManifest
		{
			public string id;

			public string name;

			public string author;

			public string bundle;

			public string scene;

			public string positionMode;

			public SerializableVector3 position = new SerializableVector3();

			public bool moveScene = true;

			public string radarColor = "";

			public float islandSize = 55f;

			public RuntimeManifest runtime = new RuntimeManifest();

			public WildlifeManifest wildlife = new WildlifeManifest();
		}

		[Serializable]
		public sealed class SerializableVector3
		{
			public float x;

			public float y;

			public float z;

			public Vector3 ToVector3()
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				return new Vector3(x, y, z);
			}
		}

		[Serializable]
		public sealed class RuntimeManifest
		{
			public string playerSpawn = "PlayerSpawnPoint";

			public string boatSpawn = "BoatSpawnPoint";

			public SerializableVector3 defaultPlayerSpawn = new SerializableVector3
			{
				x = 0f,
				y = 6f,
				z = 0f
			};

			public SerializableVector3 defaultBoatSpawn = new SerializableVector3
			{
				x = 0f,
				y = 0.5f,
				z = -25f
			};
		}

		[Serializable]
		public sealed class WildlifeManifest
		{
			public bool seagulls;

			public bool clams;

			public int seagullMax = 3;

			public float seagullDelay = 60f;

			public int clamMax = 3;

			public float clamDelay = 15f;
		}

		private sealed class RegisteredMap
		{
			public MapManifest Manifest;

			public string Folder;

			public string BundlePath;

			public string SceneName;

			public string ScenePath;

			public Vector3 Position;

			public Color RadarColor;

			public byte LogicalIndex;

			public AssetBundle Bundle;

			public object MapDot;

			public override string ToString()
			{
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				return (Manifest?.name ?? Manifest?.id ?? "Map") + " " + $"index={LogicalIndex} scene='{SceneName}' pos={Position}";
			}
		}

		public const string Guid = "com.howtofish.maploader";

		public const string Name = "HTF Map Loader";

		public const string Version = "0.2.8";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<bool> _verbose;

		private ConfigEntry<bool> _repairRuntime;

		private ConfigEntry<bool> _enableMapWildlife;

		private readonly List<RegisteredMap> _maps = new List<RegisteredMap>();

		private readonly Dictionary<byte, RegisteredMap> _mapsByIndex = new Dictionary<byte, RegisteredMap>();

		private bool _scanned;

		private bool _registered;

		private bool _loggedDisabled;

		private bool _verifiedRegisteredTriggers;

		private float _managerFirstSeenTime = -1f;

		private bool _bypassQueuePatch;

		private bool _transitioning;

		private RegisteredMap _loadingMap;

		private RegisteredMap _currentMap;

		private object _radarUi;

		private MethodInfo _radarUpdateDotMethod;

		private float _nextRadarAcquire;

		private int _nativeGroundLayer = -1;

		private PhysicsMaterial _nativeGroundMaterial;

		private string LegacyMapsRoot => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Maps");

		private string PluginsRoot => Paths.PluginPath;

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable HTF Map Loader.");
			_repairRuntime = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RepairMissingRuntimeObjects", true, "Automatically repair common Island/SpawnManager/Level setup when a map is missing it.");
			_enableMapWildlife = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowMapWildlifeOptions", true, "Allow map.json to request optional built-in Seagull and Clam spawners.");
			_verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Enable verbose Map Loader logging.");
			Directory.CreateDirectory(LegacyMapsRoot);
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			PatchQueueRequest();
			PatchNativeIslandSpawnerTrigger();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"HTF Map Loader v0.2.8 loaded.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Enabled={_enabled.Value}, RepairRuntime={_repairRuntime.Value}, WildlifeOptions={_enableMapWildlife.Value}");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Legacy maps directory: " + LegacyMapsRoot));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Thunderstore plugin root: " + PluginsRoot));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Map packs are discovered recursively from BepInEx/plugins/**/Maps/**/map.json.");
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SceneManager.sceneUnloaded -= OnSceneUnloaded;
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			foreach (RegisteredMap map in _maps)
			{
				try
				{
					if ((Object)(object)map.Bundle != (Object)null)
					{
						map.Bundle.Unload(false);
					}
				}
				catch
				{
				}
			}
		}

		private void Update()
		{
			if (!_enabled.Value)
			{
				if (!_loggedDisabled)
				{
					_loggedDisabled = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[GENERAL] HTF Map Loader is disabled by config: [General] Enabled=false.");
				}
				return;
			}
			_loggedDisabled = false;
			if (!_scanned)
			{
				ScanMapFolders();
				_scanned = true;
			}
			if (!_registered && _maps.Count > 0)
			{
				TryRegisterMaps();
			}
			if (_registered && !_verifiedRegisteredTriggers && IsGameplayWorldReady())
			{
				VerifyRegisteredNavigationTriggers();
				_verifiedRegisteredTriggers = true;
			}
			if (_registered && IsGameplayWorldReady())
			{
				UpdateRadar();
			}
		}

		private void ScanMapFolders()
		{
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			_maps.Clear();
			string[] array = DiscoverMapManifests();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[MAPS] Found {array.Length} map.json file(s) across installed plugin packages.");
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			int num = 0;
			string[] array2 = array;
			foreach (string text in array2)
			{
				try
				{
					string text2 = File.ReadAllText(text);
					MapManifest mapManifest = JsonUtility.FromJson<MapManifest>(text2);
					ApplyExplicitVectorOverrides(mapManifest, text2, text);
					if (!ValidateManifest(mapManifest, text))
					{
						continue;
					}
					if (!hashSet.Add(mapManifest.id.Trim()))
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] Duplicate map id '" + mapManifest.id + "'. Skipping " + text + "."));
						continue;
					}
					string directoryName = Path.GetDirectoryName(text);
					string text3 = mapManifest.bundle.Trim();
					string text4 = Path.Combine(directoryName, text3);
					if (!File.Exists(text4))
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] '" + mapManifest.id + "' bundle does not exist: " + text4));
						continue;
					}
					RegisteredMap item = new RegisteredMap
					{
						Manifest = mapManifest,
						Folder = directoryName,
						BundlePath = text4,
						SceneName = ((mapManifest.scene != null) ? mapManifest.scene.Trim() : ""),
						Position = ResolveMapPosition(mapManifest, num),
						RadarColor = ResolveRadarColor(mapManifest, num)
					};
					_maps.Add(item);
					num++;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[MAPS] Discovered '" + (mapManifest.name ?? mapManifest.id) + "' bundle='" + text3 + "'."));
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[MAPS] Failed reading '" + text + "': " + ex.Message));
				}
			}
		}

		private string[] DiscoverMapManifests()
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			AddMapManifestsFromMapsRoot(LegacyMapsRoot, hashSet);
			try
			{
				if (Directory.Exists(PluginsRoot))
				{
					foreach (string item in EnumerateDirectoriesSafe(PluginsRoot, "Maps"))
					{
						AddMapManifestsFromMapsRoot(item, hashSet);
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] Failed scanning plugin packages: " + ex.Message));
			}
			return hashSet.OrderBy<string, string>((string p) => p, StringComparer.OrdinalIgnoreCase).ToArray();
		}

		private void AddMapManifestsFromMapsRoot(string mapsRoot, HashSet<string> results)
		{
			if (string.IsNullOrWhiteSpace(mapsRoot) || results == null || !Directory.Exists(mapsRoot))
			{
				return;
			}
			try
			{
				string[] files = Directory.GetFiles(mapsRoot, "map.json", SearchOption.AllDirectories);
				foreach (string text in files)
				{
					try
					{
						results.Add(Path.GetFullPath(text));
					}
					catch
					{
						results.Add(text);
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] Could not scan '" + mapsRoot + "': " + ex.Message));
			}
		}

		private IEnumerable<string> EnumerateDirectoriesSafe(string root, string wantedName)
		{
			Stack<string> pending = new Stack<string>();
			pending.Push(root);
			while (pending.Count > 0)
			{
				string path = pending.Pop();
				string[] directories;
				try
				{
					directories = Directory.GetDirectories(path);
				}
				catch
				{
					continue;
				}
				string[] array = directories;
				foreach (string text in array)
				{
					string fileName;
					try
					{
						fileName = Path.GetFileName(text.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
					}
					catch
					{
						continue;
					}
					if (string.Equals(fileName, wantedName, StringComparison.OrdinalIgnoreCase))
					{
						yield return text;
					}
					else
					{
						pending.Push(text);
					}
				}
			}
		}

		private void ApplyExplicitVectorOverrides(MapManifest manifest, string json, string manifestPath)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			if (manifest == null || string.IsNullOrWhiteSpace(json))
			{
				return;
			}
			if (TryReadVector3Object(json, "position", out var value))
			{
				manifest.position = value;
			}
			if (manifest.runtime == null)
			{
				manifest.runtime = new RuntimeManifest();
			}
			if (TryReadObjectBody(json, "runtime", out var body))
			{
				if (TryReadVector3Object(body, "defaultPlayerSpawn", out value))
				{
					manifest.runtime.defaultPlayerSpawn = value;
				}
				if (TryReadVector3Object(body, "defaultBoatSpawn", out value))
				{
					manifest.runtime.defaultBoatSpawn = value;
				}
			}
			if (_verbose != null && _verbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[JSON] Parsed vectors from '" + manifestPath + "': " + $"position={manifest.position?.ToVector3()}, " + $"defaultPlayerSpawn={manifest.runtime?.defaultPlayerSpawn?.ToVector3()}, " + $"defaultBoatSpawn={manifest.runtime?.defaultBoatSpawn?.ToVector3()}."));
			}
		}

		private static bool TryReadVector3Object(string json, string propertyName, out SerializableVector3 value)
		{
			value = null;
			if (!TryReadObjectBody(json, propertyName, out var body))
			{
				return false;
			}
			if (!TryReadFloatProperty(body, "x", out var value2) || !TryReadFloatProperty(body, "y", out var value3) || !TryReadFloatProperty(body, "z", out var value4))
			{
				return false;
			}
			value = new SerializableVector3
			{
				x = value2,
				y = value3,
				z = value4
			};
			return true;
		}

		private static bool TryReadObjectBody(string json, string propertyName, out string body)
		{
			body = null;
			if (string.IsNullOrWhiteSpace(json) || string.IsNullOrWhiteSpace(propertyName))
			{
				return false;
			}
			Match match = Regex.Match(json, "\"" + Regex.Escape(propertyName) + "\"\\s*:\\s*\\{", RegexOptions.IgnoreCase);
			if (!match.Success)
			{
				return false;
			}
			int num = json.IndexOf('{', match.Index);
			if (num < 0)
			{
				return false;
			}
			int num2 = 0;
			bool flag = false;
			bool flag2 = false;
			for (int i = num; i < json.Length; i++)
			{
				char c = json[i];
				if (flag)
				{
					if (flag2)
					{
						flag2 = false;
						continue;
					}
					switch (c)
					{
					case '\\':
						flag2 = true;
						break;
					case '"':
						flag = false;
						break;
					}
					continue;
				}
				switch (c)
				{
				case '"':
					flag = true;
					break;
				case '{':
					num2++;
					break;
				case '}':
					num2--;
					if (num2 == 0)
					{
						body = json.Substring(num + 1, i - num - 1);
						return true;
					}
					break;
				}
			}
			return false;
		}

		private static bool TryReadFloatProperty(string objectBody, string propertyName, out float value)
		{
			value = 0f;
			if (string.IsNullOrWhiteSpace(objectBody))
			{
				return false;
			}
			Match match = Regex.Match(objectBody, "\"" + Regex.Escape(propertyName) + "\"\\s*:\\s*([-+]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:[eE][-+]?\\d+)?)", RegexOptions.IgnoreCase);
			if (!match.Success)
			{
				return false;
			}
			return float.TryParse(match.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out value);
		}

		private bool ValidateManifest(MapManifest manifest, string manifestPath)
		{
			if (manifest == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] Invalid JSON manifest: " + manifestPath + "."));
				return false;
			}
			List<string> list = new List<string>();
			if (string.IsNullOrWhiteSpace(manifest.id))
			{
				list.Add("id");
			}
			if (string.IsNullOrWhiteSpace(manifest.name))
			{
				list.Add("name");
			}
			if (string.IsNullOrWhiteSpace(manifest.author))
			{
				list.Add("author");
			}
			if (string.IsNullOrWhiteSpace(manifest.bundle))
			{
				list.Add("bundle");
			}
			if (string.IsNullOrWhiteSpace(manifest.scene))
			{
				list.Add("scene");
			}
			if (string.IsNullOrWhiteSpace(manifest.positionMode))
			{
				list.Add("positionMode");
			}
			if (list.Count > 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] '" + manifestPath + "' is missing required field(s): " + string.Join(", ", list) + ". See MAP_JSON_REFERENCE.md."));
				return false;
			}
			string a = manifest.positionMode.Trim();
			if (!string.Equals(a, "auto", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "manual", StringComparison.OrdinalIgnoreCase))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] '" + manifest.id + "' has invalid positionMode='" + manifest.positionMode + "'. Use 'auto' or 'manual'."));
				return false;
			}
			if (string.Equals(a, "manual", StringComparison.OrdinalIgnoreCase) && manifest.position == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] '" + manifest.id + "' uses manual positioning but has no position object."));
				return false;
			}
			Color val = default(Color);
			if (!string.IsNullOrWhiteSpace(manifest.radarColor) && !ColorUtility.TryParseHtmlString(manifest.radarColor.Trim(), ref val))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] '" + manifest.id + "' has invalid radarColor='" + manifest.radarColor + "'. Use a hex color like #20DFFF."));
				return false;
			}
			if (manifest.runtime == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] '" + manifest.id + "' is missing runtime. Include the runtime object even if you keep the default marker names."));
				return false;
			}
			if (manifest.wildlife == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[MAPS] '" + manifest.id + "' is missing wildlife. Include the wildlife object and set seagulls/clams explicitly."));
				return false;
			}
			return true;
		}

		private Vector3 ResolveMapPosition(MapManifest manifest, int order)
		{
			//IL_006b: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			if (manifest != null && string.Equals(manifest.positionMode, "manual", StringComparison.OrdinalIgnoreCase))
			{
				if (manifest.position == null)
				{
					return Vector3.zero;
				}
				return manifest.position.ToVector3();
			}
			int num = order / 8;
			int num2 = order % 8;
			float num3 = 650f + (float)num * 450f;
			float num4 = MathF.PI / 4f * (float)num2 + MathF.PI / 8f;
			return new Vector3(Mathf.Cos(num4) * num3, 0f, Mathf.Sin(num4) * num3);
		}

		private Color ResolveRadarColor(MapManifest manifest, int order)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			if (manifest != null && !string.IsNullOrWhiteSpace(manifest.radarColor) && ColorUtility.TryParseHtmlString(manifest.radarColor.Trim(), ref result))
			{
				result.a = 1f;
				return result;
			}
			Color[] array = (Color[])(object)new Color[6]
			{
				new Color(0.15f, 0.85f, 1f, 1f),
				new Color(0.75f, 0.35f, 1f, 1f),
				new Color(1f, 0.35f, 0.75f, 1f),
				new Color(0.3f, 1f, 0.65f, 1f),
				new Color(0.45f, 0.65f, 1f, 1f),
				new Color(1f, 0.8f, 0.25f, 1f)
			};
			return array[Math.Abs(order) % array.Length];
		}

		private void TryRegisterMaps()
		{
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			object obj = FindLiveObjectByTypeName("IslandManager");
			if (obj == null)
			{
				return;
			}
			FieldInfo fieldInfo = FindField(obj.GetType(), "_islandInfos");
			Array array = ((fieldInfo != null) ? (fieldInfo.GetValue(obj) as Array) : null);
			if (array == null || array.Length < 5)
			{
				return;
			}
			if (_managerFirstSeenTime < 0f)
			{
				_managerFirstSeenTime = Time.unscaledTime;
			}
			else
			{
				if (Time.unscaledTime - _managerFirstSeenTime < 1.5f)
				{
					return;
				}
				try
				{
					CacheNativeGroundCollision();
					int length = array.Length;
					object value = array.GetValue(Math.Min(4, array.Length - 1));
					if (value == null)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)"[REGISTER] No IslandInfo template available.");
						return;
					}
					Type type = value.GetType();
					FieldInfo fieldInfo2 = FindField(type, "_spawnPosition");
					FieldInfo fieldInfo3 = FindField(type, "_warning");
					object? obj2 = fieldInfo2?.GetValue(value);
					GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null);
					object? obj3 = fieldInfo3?.GetValue(value);
					GameObject sourceWarning = (GameObject)((obj3 is GameObject) ? obj3 : null);
					if (fieldInfo2 == null || fieldInfo3 == null || (Object)(object)val == (Object)null)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)"[REGISTER] Native IslandInfo trigger template is incomplete.");
						return;
					}
					ResolveNonConflictingMapPositions(array, fieldInfo2);
					int length2 = array.Length + _maps.Count;
					Array array2 = Array.CreateInstance(type, length2);
					Array.Copy(array, array2, array.Length);
					for (int i = 0; i < _maps.Count; i++)
					{
						RegisteredMap registeredMap = _maps[i];
						int num = length + i;
						if (num > 255)
						{
							((BaseUnityPlugin)this).Logger.LogError((object)"[REGISTER] Too many maps for byte island indexes.");
							break;
						}
						registeredMap.LogicalIndex = (byte)num;
						object obj4 = CreateIslandInfoForMap(registeredMap, type, val, sourceWarning, fieldInfo2, fieldInfo3);
						if (obj4 != null)
						{
							array2.SetValue(obj4, num);
							_mapsByIndex[registeredMap.LogicalIndex] = registeredMap;
							((BaseUnityPlugin)this).Logger.LogWarning((object)("[REGISTER] " + registeredMap.Manifest.name + " " + $"index={registeredMap.LogicalIndex} " + "scene='" + registeredMap.Manifest.scene + "' " + $"pos={registeredMap.Position} " + "bundle='" + registeredMap.Manifest.bundle + "' radar=" + registeredMap.Manifest.radarColor));
						}
					}
					fieldInfo.SetValue(obj, array2);
					_registered = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)($"[REGISTER] Added {_mapsByIndex.Count} custom map(s). " + $"IslandInfo {array.Length} -> {array2.Length}."));
					ResetRadarReferences();
				}
				catch (Exception arg)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"[REGISTER] Failed: {arg}");
				}
			}
		}

		private void ResolveNonConflictingMapPositions(Array existingInfos, FieldInfo spawnField)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			if (existingInfos != null)
			{
				for (int i = 0; i < existingInfos.Length; i++)
				{
					object value = existingInfos.GetValue(i);
					if (value != null && TryGetIslandInfoPosition(value, spawnField, out var position))
					{
						list.Add(position);
						if (_verbose.Value)
						{
							((BaseUnityPlugin)this).Logger.LogInfo((object)$"[PLACEMENT] Existing island index={i} pos={position}.");
						}
					}
				}
			}
			for (int j = 0; j < _maps.Count; j++)
			{
				RegisteredMap registeredMap = _maps[j];
				Vector3 position2 = registeredMap.Position;
				if (!FindPositionConflict(position2, list, 550f, out var conflictingPosition))
				{
					list.Add(position2);
					continue;
				}
				Vector3 val = FindFreeNavigationPosition(list, j, 550f);
				((BaseUnityPlugin)this).Logger.LogWarning((object)($"[PLACEMENT] '{registeredMap.Manifest.id}' requested {position2}, but that " + $"position conflicts with an existing island at {conflictingPosition}. " + $"Automatically moved navigation/radar position to {val}."));
				registeredMap.Position = val;
				list.Add(val);
			}
		}

		private bool TryGetIslandInfoPosition(object info, FieldInfo fallbackSpawnField, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			if (info == null)
			{
				return false;
			}
			try
			{
				PropertyInfo property = info.GetType().GetProperty("IslandPosition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == typeof(Vector3) && property.CanRead)
				{
					position = (Vector3)property.GetValue(info, null);
					return true;
				}
			}
			catch
			{
			}
			try
			{
				object? obj2 = (fallbackSpawnField ?? FindField(info.GetType(), "_spawnPosition"))?.GetValue(info);
				GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if ((Object)(object)val != (Object)null)
				{
					position = val.transform.position;
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool FindPositionConflict(Vector3 candidate, IEnumerable<Vector3> occupied, float minimumSpacing, out Vector3 conflictingPosition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			conflictingPosition = Vector3.zero;
			Vector2 val2 = default(Vector2);
			foreach (Vector3 item in occupied)
			{
				Vector2 val = new Vector2(candidate.x, candidate.z);
				((Vector2)(ref val2))..ctor(item.x, item.z);
				if (Vector2.Distance(val, val2) < minimumSpacing)
				{
					conflictingPosition = item;
					return true;
				}
			}
			return false;
		}

		private Vector3 FindFreeNavigationPosition(IEnumerable<Vector3> occupied, int mapOrder, float minimumSpacing)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> occupied2 = occupied.ToList();
			Vector3 val = default(Vector3);
			for (int i = 0; i < 64; i++)
			{
				float num = 1250f + (float)i * 450f;
				for (int j = 0; j < 12; j++)
				{
					int num2 = (j + mapOrder * 3) % 12;
					float num3 = MathF.PI / 6f * (float)num2 + MathF.PI / 12f;
					((Vector3)(ref val))..ctor(Mathf.Cos(num3) * num, 0f, Mathf.Sin(num3) * num);
					if (!FindPositionConflict(val, occupied2, minimumSpacing, out var _))
					{
						return val;
					}
				}
			}
			return new Vector3(2500f + (float)mapOrder * 650f, 0f, 2500f);
		}

		private object CreateIslandInfoForMap(RegisteredMap map, Type infoType, GameObject sourceSpawn, GameObject sourceWarning, FieldInfo spawnField, FieldInfo warningField)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = sourceSpawn.transform.parent;
			GameObject val = (GameObject)(((Object)(object)parent != (Object)null) ? ((object)Object.Instantiate<GameObject>(((Component)parent).gameObject)) : ((object)new GameObject("HTFML_Trigger_" + map.Manifest.id)));
			((Object)val).name = "HTFML_IslandPositionHolder_" + map.Manifest.id;
			Transform val2 = FindChildRecursive(val.transform, ((Object)sourceSpawn).name);
			if ((Object)(object)val2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[REGISTER] '" + map.Manifest.id + "': cloned spawn not found."));
				Object.Destroy((Object)(object)val);
				return null;
			}
			Vector3 val3 = map.Position - val2.position;
			Transform transform = val.transform;
			transform.position += val3;
			GameObject gameObject = ((Component)val2).gameObject;
			((Object)gameObject).name = "HTFML_IslandPosition_" + map.Manifest.id;
			GameObject val4 = null;
			if ((Object)(object)sourceWarning != (Object)null)
			{
				Transform val5 = FindChildRecursive(val.transform, ((Object)sourceWarning).name);
				if ((Object)(object)val5 != (Object)null)
				{
					val4 = ((Component)val5).gameObject;
					((Object)val4).name = "HTFML_IslandWarning_" + map.Manifest.id;
				}
			}
			Type type = AccessTools.TypeByName("IslandSpawner");
			Component val6 = ((type != null) ? gameObject.GetComponent(type) : null);
			FieldInfo fieldInfo = (((Object)(object)val6 != (Object)null) ? FindField(((object)val6).GetType(), "_islandIndex") : null);
			if ((Object)(object)val6 == (Object)null || fieldInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[REGISTER] '" + map.Manifest.id + "': IslandSpawner/index missing."));
				Object.Destroy((Object)(object)val);
				return null;
			}
			fieldInfo.SetValue(val6, Convert.ChangeType(map.LogicalIndex, fieldInfo.FieldType));
			object obj = Activator.CreateInstance(infoType, nonPublic: true);
			spawnField.SetValue(obj, gameObject);
			warningField.SetValue(obj, val4);
			val.SetActive(true);
			gameObject.SetActive(true);
			RepairClonedTriggerGeometry(((Object)(object)parent != (Object)null) ? ((Component)parent).gameObject : null, val);
			DumpRegisteredNavigationTrigger(map, val, gameObject, val6);
			return obj;
		}

		private void RepairClonedTriggerGeometry(GameObject sourceHolder, GameObject clonedHolder)
		{
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sourceHolder == (Object)null || (Object)(object)clonedHolder == (Object)null)
			{
				return;
			}
			Collider[] componentsInChildren = sourceHolder.GetComponentsInChildren<Collider>(true);
			Collider[] componentsInChildren2 = clonedHolder.GetComponentsInChildren<Collider>(true);
			int num = Math.Min(componentsInChildren.Length, componentsInChildren2.Length);
			for (int i = 0; i < num; i++)
			{
				Collider val = componentsInChildren[i];
				Collider val2 = componentsInChildren2[i];
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || ((object)val).GetType() != ((object)val2).GetType())
				{
					continue;
				}
				bool enabled = val2.enabled;
				val2.enabled = false;
				SphereCollider val3 = (SphereCollider)(object)((val is SphereCollider) ? val : null);
				if (val3 != null)
				{
					SphereCollider val4 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null);
					if (val4 != null)
					{
						val4.center = val3.center;
						val4.radius = val3.radius;
						goto IL_0148;
					}
				}
				BoxCollider val5 = (BoxCollider)(object)((val is BoxCollider) ? val : null);
				if (val5 != null)
				{
					BoxCollider val6 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null);
					if (val6 != null)
					{
						val6.center = val5.center;
						val6.size = val5.size;
						goto IL_0148;
					}
				}
				CapsuleCollider val7 = (CapsuleCollider)(object)((val is CapsuleCollider) ? val : null);
				if (val7 != null)
				{
					CapsuleCollider val8 = (CapsuleCollider)(object)((val2 is CapsuleCollider) ? val2 : null);
					if (val8 != null)
					{
						val8.center = val7.center;
						val8.radius = val7.radius;
						val8.height = val7.height;
						val8.direction = val7.direction;
					}
				}
				goto IL_0148;
				IL_0148:
				Physics.SyncTransforms();
				val2.enabled = enabled;
			}
			Physics.SyncTransforms();
			((BaseUnityPlugin)this).Logger.LogWarning((object)($"[TRIGGER FIX] Refreshed {num} cloned collider(s) after moving " + $"'{((Object)clonedHolder).name}' to {clonedHolder.transform.position}."));
		}

		private void DumpRegisteredNavigationTrigger(RegisteredMap map, GameObject holder, GameObject spawn, Component spawner)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: 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)
			if (map == null || (Object)(object)holder == (Object)null || (Object)(object)spawn == (Object)null)
			{
				return;
			}
			try
			{
				Collider[] componentsInChildren = holder.GetComponentsInChildren<Collider>(true);
				ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
				string[] obj = new string[12]
				{
					"[TRIGGER DUMP] '",
					map.Manifest.id,
					"' holder='",
					((Object)holder).name,
					"' ",
					$"holderActive={holder.activeInHierarchy} ",
					$"spawn='{((Object)spawn).name}' spawnActive={spawn.activeInHierarchy} ",
					$"spawnPos={spawn.transform.position} ",
					"spawnerEnabled=",
					null,
					null,
					null
				};
				Behaviour val = (Behaviour)(object)((spawner is Behaviour) ? spawner : null);
				obj[9] = ((val != null) ? val.enabled.ToString() : "n/a");
				obj[10] = " ";
				obj[11] = $"colliders={componentsInChildren.Length}.";
				logger.LogWarning((object)string.Concat(obj));
				Collider[] array = componentsInChildren;
				foreach (Collider val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						Rigidbody component = ((Component)val2).GetComponent<Rigidbody>();
						ManualLogSource logger2 = ((BaseUnityPlugin)this).Logger;
						string[] obj2 = new string[10]
						{
							"[TRIGGER DUMP]   collider='",
							((Object)val2).name,
							"' ",
							$"type={((object)val2).GetType().Name} enabled={val2.enabled} ",
							$"isTrigger={val2.isTrigger} active={((Component)val2).gameObject.activeInHierarchy} ",
							$"layer={((Component)val2).gameObject.layer} tag='{SafeTag(((Component)val2).gameObject)}' ",
							null,
							null,
							null,
							null
						};
						Bounds bounds = val2.bounds;
						object arg = ((Bounds)(ref bounds)).center;
						bounds = val2.bounds;
						obj2[6] = $"center={arg} size={((Bounds)(ref bounds)).size} ";
						obj2[7] = "rb=";
						obj2[8] = (((Object)(object)component != (Object)null) ? $"kinematic={component.isKinematic}" : "none");
						obj2[9] = ".";
						logger2.LogWarning((object)string.Concat(obj2));
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[TRIGGER DUMP] Failed for '" + map.Manifest.id + "': " + ex.Message));
			}
		}

		private static string SafeTag(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return "<null>";
			}
			try
			{
				return go.tag;
			}
			catch
			{
				return "<unavailable>";
			}
		}

		private void PatchNativeIslandSpawnerTrigger()
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("IslandSpawner");
				if (type == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[PATCH] IslandSpawner type not found.");
					return;
				}
				int num = 0;
				string[] array = new string[2] { "OnTriggerEnter", "OnTriggerStay" };
				foreach (string text in array)
				{
					MethodInfo method = type.GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Collider) }, null);
					if (!(method == null))
					{
						_harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "NativeIslandSpawnerTriggerPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[PATCH] IslandSpawner." + text + "(Collider) patched."));
					}
				}
				if (num == 0)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[PATCH] No IslandSpawner trigger callbacks were found.");
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"[PATCH] IslandSpawner trigger patch failed: {arg}");
			}
		}

		private static void NativeIslandSpawnerTriggerPostfix(object __instance, Collider other)
		{
			Plugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance._enabled.Value || __instance == null || (Object)(object)other == (Object)null)
			{
				return;
			}
			FieldInfo fieldInfo = FindField(__instance.GetType(), "_islandIndex");
			if (fieldInfo == null)
			{
				return;
			}
			byte b;
			try
			{
				b = Convert.ToByte(fieldInfo.GetValue(__instance));
			}
			catch
			{
				return;
			}
			if (!instance._mapsByIndex.TryGetValue(b, out var value))
			{
				return;
			}
			ManualLogSource logger = ((BaseUnityPlugin)instance).Logger;
			string[] obj2 = new string[5]
			{
				$"[ISLAND SPAWNER HIT] map='{value.Manifest.id}' index={b} ",
				"spawner='",
				null,
				null,
				null
			};
			object obj3 = ((__instance is Component) ? __instance : null);
			object obj4;
			if (obj3 == null)
			{
				obj4 = null;
			}
			else
			{
				GameObject gameObject = ((Component)obj3).gameObject;
				obj4 = ((gameObject != null) ? ((Object)gameObject).name : null);
			}
			obj2[2] = (string)obj4;
			obj2[3] = "' ";
			obj2[4] = $"other='{((Object)other).name}' otherLayer={((Component)other).gameObject.layer}.";
			logger.LogWarning((object)string.Concat(obj2));
			if (instance.IsCustomMapAlreadyActive(value) || instance._transitioning)
			{
				return;
			}
			if (!IsGameplayBoatOrPlayerCollider(other))
			{
				if (instance._verbose.Value)
				{
					((BaseUnityPlugin)instance).Logger.LogInfo((object)("[ISLAND SPAWNER] '" + value.Manifest.id + "' ignored collider '" + ((Object)other).name + "'."));
				}
				return;
			}
			object obj5 = FindLiveObjectByTypeName("IslandManager");
			if (obj5 == null)
			{
				return;
			}
			FieldInfo fieldInfo2 = FindField(obj5.GetType(), "_hasQueuedIsland");
			try
			{
				if (fieldInfo2 != null && fieldInfo2.FieldType == typeof(bool) && (bool)fieldInfo2.GetValue(obj5))
				{
					return;
				}
			}
			catch
			{
			}
			MethodInfo methodInfo = AccessTools.Method(obj5.GetType(), "QueueRequest", new Type[1] { typeof(byte) }, (Type[])null);
			if (methodInfo == null)
			{
				return;
			}
			((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ISLAND SPAWNER] Native trigger reached custom map " + $"'{value.Manifest.id}' index={b} with collider " + $"'{((Object)other).name}'. Forwarding QueueRequest({b})."));
			try
			{
				methodInfo.Invoke(obj5, new object[1] { b });
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ISLAND SPAWNER] QueueRequest repair failed: " + ex.Message));
			}
		}

		private static bool IsGameplayBoatOrPlayerCollider(Collider other)
		{
			Transform val = (((Object)(object)other != (Object)null) ? ((Component)other).transform : null);
			Type type = AccessTools.TypeByName("Boat");
			Type type2 = AccessTools.TypeByName("Player");
			while ((Object)(object)val != (Object)null)
			{
				GameObject gameObject = ((Component)val).gameObject;
				string text = ((Object)gameObject).name ?? "";
				if (string.Equals(text, "MenuBoat", StringComparison.OrdinalIgnoreCase))
				{
					return false;
				}
				if (type != null && (Object)(object)gameObject.GetComponent(type) != (Object)null)
				{
					return true;
				}
				if (type2 != null && (Object)(object)gameObject.GetComponent(type2) != (Object)null)
				{
					return true;
				}
				if (text.IndexOf("HostBoatCol", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("LocalPlayer", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private void PatchQueueRequest()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("IslandManager");
				MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "QueueRequest", new Type[1] { typeof(byte) }, (Type[])null) : null);
				if (methodInfo == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"[PATCH] IslandManager.QueueRequest(byte) not found.");
					return;
				}
				_harmony = new Harmony("com.howtofish.maploader");
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "QueueRequestPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[PATCH] IslandManager.QueueRequest(byte) patched.");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"[PATCH] QueueRequest failed: {arg}");
			}
		}

		private static bool QueueRequestPrefix(object __instance, byte islandId)
		{
			if ((Object)(object)Instance == (Object)null || !Instance._enabled.Value || Instance._bypassQueuePatch)
			{
				return true;
			}
			if (Instance._mapsByIndex.TryGetValue(islandId, out var value))
			{
				if (Instance.IsCustomMapAlreadyActive(value))
				{
					if (Instance._verbose.Value)
					{
						((BaseUnityPlugin)Instance).Logger.LogInfo((object)($"[QUEUE] Ignoring duplicate QueueRequest({islandId}) " + "for already active map '" + value.Manifest.id + "'."));
					}
					return false;
				}
				if (!Instance._transitioning)
				{
					((MonoBehaviour)Instance).StartCoroutine(Instance.TransitionToCustomMap(value));
				}
				return false;
			}
			if (Instance._currentMap != null)
			{
				if (!Instance._transitioning)
				{
					((MonoBehaviour)Instance).StartCoroutine(Instance.LeaveCustomAndQueueNative(__instance, islandId));
				}
				return false;
			}
			return true;
		}

		private bool IsCustomMapAlreadyActive(RegisteredMap target)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (target == null)
			{
				return false;
			}
			if (_currentMap != null && _currentMap == target)
			{
				Scene sceneByName = SceneManager.GetSceneByName(target.SceneName);
				if (((Scene)(ref sceneByName)).IsValid() && ((Scene)(ref sceneByName)).isLoaded)
				{
					return true;
				}
			}
			if (!string.IsNullOrWhiteSpace(target.SceneName))
			{
				Scene sceneByName2 = SceneManager.GetSceneByName(target.SceneName);
				if (((Scene)(ref sceneByName2)).IsValid() && ((Scene)(ref sceneByName2)).isLoaded)
				{
					_currentMap = target;
					return true;
				}
			}
			return false;
		}

		private IEnumerator TransitionToCustomMap(RegisteredMap target)
		{
			if (IsCustomMapAlreadyActive(target))
			{
				yield break;
			}
			_transitioning = true;
			try
			{
				if (_currentMap != null)
				{
					yield return UnloadMapScene(_currentMap);
				}
				if (!EnsureBundleLoaded(target))
				{
					yield break;
				}
				CacheNativeGroundCollision();
				yield return UnloadAllGameplayIslandsExceptGame();
				_loadingMap = target;
				AsyncOperation load = SceneManager.LoadSceneAsync(target.SceneName, (LoadSceneMode)1);
				if (load == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[LOAD] LoadSceneAsync('" + target.SceneName + "') returned null."));
					_loadingMap = null;
					yield break;
				}
				while (!load.isDone)
				{
					yield return null;
				}
				_currentMap = target;
				_loadingMap = null;
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"[LOAD] Custom map active: {target}");
			}
			finally
			{
				_transitioning = false;
			}
		}

		private IEnumerator LeaveCustomAndQueueNative(object islandManager, byte islandId)
		{
			_transitioning = true;
			if (_currentMap != null)
			{
				yield return UnloadMapScene(_currentMap);
			}
			_currentMap = null;
			try
			{
				MethodInfo methodInfo = AccessTools.Method(islandManager.GetType(), "QueueRequest", new Type[1] { typeof(byte) }, (Type[])null);
				if (methodInfo == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"[LOAD] Could not forward native QueueRequest.");
					yield break;
				}
				_bypassQueuePatch = true;
				methodInfo.Invoke(islandManager, new object[1] { islandId });
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[LOAD] Forwarded native QueueRequest({islandId}).");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"[LOAD] Leaving custom map failed: {arg}");
			}
			finally
			{
				_bypassQueuePatch = false;
				_transitioning = false;
			}
		}

		private IEnumerator UnloadAllGameplayIslandsExceptGame()
		{
			List<AsyncOperation> list = new List<AsyncOperation>();
			for (int num = SceneManager.sceneCount - 1; num >= 0; num--)
			{
				Scene sceneAt = SceneManager.GetSceneAt(num);
				if (((Scene)(ref sceneAt)).IsValid() && ((Scene)(ref sceneAt)).isLoaded && !string.Equals(((Scene)(ref sceneAt)).name, "Game", StringComparison.OrdinalIgnoreCase))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[LOAD] Unloading '" + ((Scene)(ref sceneAt)).name + "'."));
					AsyncOperation val = SceneManager.UnloadSceneAsync(sceneAt);
					if (val != null)
					{
						list.Add(val);
					}
				}
			}
			foreach (AsyncOperation op in list)
			{
				while (!op.isDone)
				{
					yield return null;
				}
			}
		}

		private IEnumerator UnloadMapScene(RegisteredMap map)
		{
			if (map == null || string.IsNullOrWhiteSpace(map.SceneName))
			{
				yield break;
			}
			Scene sceneByName = SceneManager.GetSceneByName(map.SceneName);
			if (!((Scene)(ref sceneByName)).IsValid() || !((Scene)(ref sceneByName)).isLoaded)
			{
				yield break;
			}
			AsyncOperation op = SceneManager.UnloadSceneAsync(sceneByName);
			if (op != null)
			{
				while (!op.isDone)
				{
					yield return null;
				}
			}
		}

		private bool EnsureBundleLoaded(RegisteredMap map)
		{
			if ((Object)(object)map.Bundle != (Object)null && !string.IsNullOrWhiteSpace(map.SceneName))
			{
				return true;
			}
			try
			{
				map.Bundle = AssetBundle.LoadFromFile(map.BundlePath);
				if ((Object)(object)map.Bundle == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[BUNDLE] LoadFromFile failed: " + map.BundlePath));
					return false;
				}
				string[] allScenePaths = map.Bundle.GetAllScenePaths();
				if (allScenePaths == null || allScenePaths.Length == 0)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[BUNDLE] '" + map.Manifest.id + "' contains no scenes."));
					return false;
				}
				string requested = map.Manifest.scene ?? "";
				string text = null;
				if (!string.IsNullOrWhiteSpace(requested))
				{
					text = allScenePaths.FirstOrDefault((string p) => string.Equals(Path.GetFileNameWithoutExtension(p), requested, StringComparison.OrdinalIgnoreCase) || string.Equals(p, requested, StringComparison.OrdinalIgnoreCase));
				}
				if (text == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[BUNDLE] '" + map.Manifest.id + "' requested scene '" + requested + "', but that scene was not found in the bundle."));
					((BaseUnityPlugin)this).Logger.LogError((object)("[BUNDLE] Available scenes: " + string.Join(", ", allScenePaths)));
					return false;
				}
				map.ScenePath = text;
				map.SceneName = Path.GetFileNameWithoutExtension(text);
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[BUNDLE] '" + map.Manifest.id + "' -> scene '" + map.SceneName + "'."));
				return true;
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"[BUNDLE] '{map.Manifest.id}' failed: {arg}");
				return false;
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded && (string.Equals(((Scene)(ref scene)).name, "Game", StringComparison.OrdinalIgnoreCase) || string.Equals(((Scene)(ref scene)).name, "DevIsland", StringComparison.OrdinalIgnoreCase) || ((Scene)(ref scene)).name.StartsWith("Island", StringComparison.OrdinalIgnoreCase)))
			{
				ResetRadarReferences();
			}
			RegisteredMap registeredMap = _maps.FirstOrDefault((RegisteredMap m) => !string.IsNullOrWhiteSpace(m.SceneName) && string.Equals(m.SceneName, ((Scene)(ref scene)).name, StringComparison.OrdinalIgnoreCase));
			if (registeredMap != null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[RUNTIME] Preparing custom scene '" + ((Scene)(ref scene)).name + "'."));
				PositionMapScene(registeredMap, scene);
				if (_repairRuntime.Value)
				{
					PrepareMapRuntime(registeredMap, scene);
				}
				if (_enableMapWildlife.Value)
				{
					ApplyOptionalWildlife(registeredMap, scene);
				}
				ResetRadarReferences();
			}
		}

		private void OnSceneUnloaded(Scene scene)
		{
			if (_currentMap != null && string.Equals(_currentMap.SceneName, ((Scene)(ref scene)).name, StringComparison.OrdinalIgnoreCase))
			{
				_currentMap = null;
			}
		}

		private void PositionMapScene(RegisteredMap map, Scene scene)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if (map == null || !map.Manifest.moveScene)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[RUNTIME] '" + map?.Manifest?.id + "' moveScene=false; scene coordinates preserved."));
				return;
			}
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			GameObject val = ((IEnumerable<GameObject>)rootGameObjects).FirstOrDefault((Func<GameObject, bool>)((GameObject r) => (Object)(object)r != (Object)null && string.Equals(((Object)r).name, "IslandHolder", StringComparison.OrdinalIgnoreCase)));
			if ((Object)(object)val != (Object)null)
			{
				Vector3 position = val.transform.position;
				val.transform.position = map.Position;
				((BaseUnityPlugin)this).Logger.LogWarning((object)($"[RUNTIME] '{map.Manifest.id}' IslandHolder moved {position} -> " + $"{val.transform.position} (requested {map.Position})."));
				return;
			}
			GameObject[] array = rootGameObjects;
			foreach (GameObject val2 in array)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Transform transform = val2.transform;
					transform.position += map.Position;
				}
			}
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[RUNTIME] '" + map.Manifest.id + "' has no IslandHolder; moved " + $"{rootGameObjects.Length} root(s) by {map.Position}."));
		}

		private void PrepareMapRuntime(RegisteredMap map, Scene scene)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0041: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = ((IEnumerable<GameObject>)((Scene)(ref scene)).GetRootGameObjects()).FirstOrDefault((Func<GameObject, bool>)((GameObject r) => (Object)(object)r != (Object)null && string.Equals(((Object)r).name, "IslandHolder", StringComparison.OrdinalIgnoreCase)));
			if ((Object)(object)val == (Object)null)
			{
				val = new GameObject("IslandHolder");
				SceneManager.MoveGameObjectToScene(val, scene);
				val.transform.position = (map.Manifest.moveScene ? map.Position : Vector3.zero);
			}
			AdaptLevelPhysics(val.transform);
			EnsureIslandComponent(map, val.transform);
			EnsureSpawnManager(map, val.transform);
		}

		private void EnsureIslandComponent(RegisteredMap map, Transform holder)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("Island");
			if (!(type == null))
			{
				Transform val = FindChildRecursive(holder, "IslandManager");
				GameObject val2;
				if ((Object)(object)val != (Object)null)
				{
					val2 = ((Component)val).gameObject;
				}
				else
				{
					val2 = new GameObject("IslandManager");
					val2.transform.SetParent(holder, false);
				}
				Component val3 = val2.GetComponent(type);
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = val2.AddComponent(type);
				}
				SetFieldIfExists(val3, "_islandSize", map.Manifest.islandSize);
			}
		}

		private void EnsureSpawnManager(RegisteredMap map, Transform holder)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_027d: 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_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: 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)
			Type type = AccessTools.TypeByName("SpawnManager");
			if (!(type == null))
			{
				Transform val = FindChildRecursive(holder, "SpawnManager");
				GameObject val2;
				if ((Object)(object)val != (Object)null)
				{
					val2 = ((Component)val).gameObject;
				}
				else
				{
					val2 = new GameObject("SpawnManager");
					val2.transform.SetParent(holder, false);
				}
				val2.SetActive(false);
				string text = map.Manifest.runtime?.playerSpawn ?? "PlayerSpawnPoint";
				string text2 = map.Manifest.runtime?.boatSpawn ?? "BoatSpawnPoint";
				Transform val3 = FindChildRecursive(holder, text);
				if ((Object)(object)val3 == (Object)null)
				{
					GameObject val4 = new GameObject(text);
					val4.transform.SetParent(val2.transform, false);
					val4.transform.localPosition = (Vector3)(((??)map.Manifest.runtime?.defaultPlayerSpawn?.ToVector3()) ?? new Vector3(0f, 6f, 0f));
					val3 = val4.transform;
				}
				Transform val5 = FindChildRecursive(holder, text2);
				if ((Object)(object)val5 == (Object)null)
				{
					GameObject val6 = new GameObject(text2);
					val6.transform.SetParent(val2.transform, false);
					val6.transform.localPosition = (Vector3)(((??)map.Manifest.runtime?.defaultBoatSpawn?.ToVector3()) ?? new Vector3(0f, 0.5f, -25f));
					val5 = val6.transform;
				}
				Component val7 = val2.GetComponent(type);
				if ((Object)(object)val7 == (Object)null)
				{
					val7 = val2.AddComponent(type);
				}
				SetFieldIfExists(val7, "_testPrint", "HTF Map Loader: " + map.Manifest.id);
				SetFieldIfExists(val7, "_playerSpawnPoint", val3);
				SetFieldIfExists(val7, "_boatSpawnPoint", val5);
				object obj = FindBoatPrefabInMemory();
				if (obj != null)
				{
					SetFieldIfExists(val7, "_boatPrefab", obj);
				}
				val2.SetActive(true);
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[RUNTIME] '{map.Manifest.id}' PlayerSpawn={val3.position}, BoatSpawn={val5.position}.");
			}
		}

		private void ApplyOptionalWildlife(RegisteredMap map, Scene scene)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			WildlifeManifest wildlife = map.Manifest.wildlife;
			if (wildlife != null)
			{
				if (wildlife.seagulls)
				{
					EnsureSeagullSpawner(scene, Mathf.Clamp(wildlife.seagullMax, 1, 20), Mathf.Max(1f, wildlife.seagullDelay));
				}
				if (wildlife.clams)
				{
					EnsureClamSpawner(scene, Mathf.Clamp(wildlife.clamMax, 1, 20), Mathf.Max(1f, wildlife.clamDelay));
				}
			}
		}

		private void EnsureSeagullSpawner(Scene scene, int maxCount, float delay)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = FindIslandHolder(scene);
			if ((Object)(object)val == (Object)null || (Object)(object)FindChildRecursive(val.transform, "SeagullSpawner") != (Object)null)
			{
				return;
			}
			Type type = AccessTools.TypeByName("ItemSpawner");
			Type type2 = AccessTools.TypeByName("Bird");
			if (!(type == null) && !(type2 == null))
			{
				Object val2 = FindNamedComponentPrefab(type2, "Seagull");
				if (val2 == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[WILDLIFE] Seagull prefab not available in memory.");
					return;
				}
				Transform orCreateChild = GetOrCreateChild(val.transform, "CreatureSpawners");
				GameObject val3 = new GameObject("SeagullSpawner");
				val3.transform.SetParent(orCreateChild, false);
				val3.transform.localPosition = new Vector3(0f, 20f, 0f);
				val3.SetActive(false);
				BoxCollider val4 = val3.AddComponent<BoxCollider>();
				((Collider)val4).isTrigger = true;
				val4.size = new Vector3(70f, 12f, 70f);
				Component spawner = val3.AddComponent(type);
				ConfigureItemSpawner(spawner, val4, val2, deadCreature: false, spawnInAir: true, maxCount, delay, 1);
				val3.SetActive(true);
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[WILDLIFE] SeagullSpawner added max={maxCount}, delay={delay:0.#}.");
			}
		}

		private void EnsureClamSpawner(Scene scene, int maxCount, float delay)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = FindIslandHolder(scene);
			if ((Object)(object)val == (Object)null || (Object)(object)FindChildRecursive(val.transform, "ClamSpawner") != (Object)null)
			{
				return;
			}
			Type type = AccessTools.TypeByName("ItemSpawner");
			Type type2 = AccessTools.TypeByName("Creature");
			if (!(type == null) && !(type2 == null))
			{
				Object val2 = FindNamedComponentPrefab(type2, "Clam");
				if (val2 == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[WILDLIFE] Clam prefab not available in memory.");
					return;
				}
				Transform orCreateChild = GetOrCreateChild(val.transform, "CreatureSpawners");
				GameObject val3 = new GameObject("ClamSpawner");
				val3.transform.SetParent(orCreateChild, false);
				val3.transform.localPosition = new Vector3(0f, 1.5f, 0f);
				val3.SetActive(false);
				BoxCollider val4 = val3.AddComponent<BoxCollider>();
				((Collider)val4).isTrigger = true;
				val4.center = new Vector3(0f, -1.25f, 0f);
				val4.size = new Vector3(28f, 3f, 28f);
				Component spawner = val3.AddComponent(type);
				ConfigureItemSpawner(spawner, val4, val2, deadCreature: true, spawnInAir: false, maxCount, delay, 2);
				val3.SetActive(true);
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[WILDLIFE] ClamSpawner added max={maxCount}, delay={delay:0.#}.");
			}
		}

		private void ConfigureItemSpawner(Component spawner, BoxCollider box, Object prefab, bool deadCreature, bool spawnInAir, int max, float delay, int count)
		{
			SetFieldIfExists(spawner, "_isActive", true);
			SetFieldIfExists(spawner, "_itemToSpawn", prefab);
			SetFieldIfExists(spawner, "_spawnsDeadCreature", deadCreature);
			SetFieldIfExists(spawner, "_startFrequencyForRadio", 98);
			SetFieldIfExists(spawner, "_useRandomRotation", true);
			SetFieldIfExists(spawner, "_maxItemsSpawned", max);
			SetFieldIfExists(spawner, "_spawnInstant", true);
			SetFieldIfExists(spawner, "_onlySpawnOnce", false);
			SetFieldIfExists(spawner, "_spawnInAir", spawnInAir);
			SetFieldIfExists(spawner, "_spawnDelay", delay);
			SetFieldIfExists(spawner, "_spawnCount", count);
			SetFieldIfExists(spawner, "_spawnBox", box);
			SetFieldIfExists(spawner, "_hasSpawned", false);
			FieldInfo fieldInfo = FindField(((object)spawner).GetType(), "_itemsSpawned");
			if (fieldInfo != null)
			{
				try
				{
					fieldInfo.SetValue(spawner, Activator.CreateInstance(fieldInfo.FieldType));
				}
				catch
				{
				}
			}
		}

		private void VerifyRegisteredNavigationTriggers()
		{
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			Type type = AccessTools.TypeByName("IslandSpawner");
			if (type == null)
			{
				return;
			}
			Object[] source = Resources.FindObjectsOfTypeAll(type);
			foreach (RegisteredMap map in _mapsByIndex.Values)
			{
				Component val = source.OfType<Component>().FirstOrDefault((Func<Component, bool>)delegate(Component c)
				{
					if ((Object)(object)c == (Object)null || (Object)(object)c.gameObject == (Object)null)
					{
						return false;
					}
					FieldInfo fieldInfo = FindField(((object)c).GetType(), "_islandIndex");
					if (fieldInfo == null)
					{
						return false;
					}
					try
					{
						return Convert.ToByte(fieldInfo.GetValue(c)) == map.LogicalIndex;
					}
					catch
					{
						return false;
					}
				});
				if ((Object)(object)val == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)($"[TRIGGER VERIFY] '{map.Manifest.id}' index={map.LogicalIndex}: " + "NO live IslandSpawner found."));
					continue;
				}
				Transform parent = val.gameObject.transform.parent;
				Collider[] array = ((parent != null) ? ((Component)parent).GetComponentsInChildren<Collider>(true) : null) ?? Array.Empty<Collider>();
				((BaseUnityPlugin)this).Logger.LogWarning((object)($"[TRIGGER VERIFY] '{map.Manifest.id}' index={map.LogicalIndex}: " + $"spawner='{((Object)val.gameObject).name}' active={val.gameObject.activeInHierarchy} " + $"pos={val.transform.position} colliders={array.Length}."));
			}
		}

		private bool IsGameplayWorldReady()
		{
			//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)
			bool flag = false;
			bool flag2 = false;
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene scene = SceneManager.GetSceneAt(i);
				if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
				{
					if (string.Equals(((Scene)(ref scene)).name, "Game", StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
					}
					else if (((Scene)(ref scene)).name.StartsWith("Island", StringComparison.OrdinalIgnoreCase) || string.Equals(((Scene)(ref scene)).name, "DevIsland", StringComparison.OrdinalIgnoreCase) || _maps.Any((RegisteredMap m) => !string.IsNullOrWhiteSpace(m.SceneName) && string.Equals(m.SceneName, ((Scene)(ref scene)).name, StringComparison.OrdinalIgnoreCase)))
					{
						flag2 = true;
					}
				}
			}
			if (!flag || !flag2)
			{
				return false;
			}
			object obj = FindLiveObjectByTypeName("IslandManager");
			if (obj == null)
			{
				return false;
			}
			Array infos = FindField(obj.GetType(), "_islandInfos")?.GetValue(obj) as Array;
			if (infos != null)
			{
				return _mapsByIndex.Keys.All((byte index) => index < infos.Length);
			}
			return false;
		}

		private void UpdateRadar()
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			if (_mapsByIndex.Count == 0)
			{
				return;
			}
			if (_radarUi == null || _maps.Any((RegisteredMap m) => _mapsByIndex.ContainsKey(m.LogicalIndex) && m.MapDot == null))
			{
				EnsureRadarDots();
			}
			if (_radarUi == null)
			{
				return;
			}
			if (!IsNativeRadarCurrentlyVisible())
			{
				foreach (RegisteredMap map in _maps)
				{
					SetMapDotVisualActive(map.MapDot, active: false);
				}
				return;
			}
			foreach (RegisteredMap map2 in _maps)
			{
				if (map2.MapDot == null)
				{
					continue;
				}
				try
				{
					if (_radarUpdateDotMethod == null)
					{
						Type type = map2.MapDot.GetType();
						_radarUpdateDotMethod = _radarUi.GetType().GetMethod("UpdateDot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
						{
							type,
							typeof(Vector3)
						}, null);
					}
					_radarUpdateDotMethod?.Invoke(_radarUi, new object[2] { map2.MapDot, map2.Position });
					SetMapDotVisualActive(map2.MapDot, active: true);
					ApplyMapDotColor(map2);
				}
				catch
				{
					ResetRadarReferences();
					break;
				}
			}
		}

		private void EnsureRadarDots()
		{
			if (Time.unscaledTime < _nextRadarAcquire)
			{
				return;
			}
			_nextRadarAcquire = Time.unscaledTime + 1f;
			object obj = FindLiveObjectByTypeName("RadarUI");
			if (obj == null)
			{
				return;
			}
			FieldInfo fieldInfo = FindField(obj.GetType(), "_islandDots");
			if (!(fieldInfo?.GetValue(obj) is Array array))
			{
				return;
			}
			Type elementType = array.GetType().GetElementType();
			if (elementType == null)
			{
				return;
			}
			int val = (from m in _maps
				where _mapsByIndex.ContainsKey(m.LogicalIndex)
				select m.LogicalIndex + 1).DefaultIfEmpty(array.Length).Max();
			Array array2 = Array.CreateInstance(elementType, Math.Max(array.Length, val));
			Array.Copy(array, array2, array.Length);
			object obj2 = null;
			for (int num = 0; num < array.Length; num++)
			{
				object value = array.GetValue(num);
				if (value != null)
				{
					obj2 = value;
					break;
				}
			}
			if (obj2 == null)
			{
				return;
			}
			foreach (RegisteredMap map in _maps)
			{
				int logicalIndex = map.LogicalIndex;
				object obj3 = ((logicalIndex < array.Length) ? array.GetValue(logicalIndex) : null);
				if (obj3 != null && map.MapDot == null && IsOurMapDot(obj3, map.Manifest.id))
				{
					map.MapDot = obj3;
				}
				if (map.MapDot == null)
				{
					map.MapDot = CloneMapDot(obj2, "HTFML_Radar_" + map.Manifest.id);
				}
				if (map.MapDot != null)
				{
					array2.SetValue(map.MapDot, logicalIndex);
					ApplyMapDotColor(map);
				}
			}
			fieldInfo.SetValue(obj, array2);
			_radarUi = obj;
			_radarUpdateDotMethod = null;
			((BaseUnityPlugin)this).Logger.LogWarning((object)($"[RADAR] MapDot array {array.Length} -> {array2.Length}. " + "Custom=" + string.Join(", ", _mapsByIndex.Values.Select((RegisteredMap m) => $"{m.Manifest.id}@{m.LogicalIndex}:{m.Position}"))));
		}

		private bool IsOurMapDot(object mapDot, string mapId)
		{
			if (mapDot == null)
			{
				return false;
			}
			try
			{
				object? obj = FindField(mapDot.GetType(), "_dot")?.GetValue(mapDot);
				Component val = (Component)((obj is Component) ? obj : null);
				return (Object)(object)val != (Object)null && (Object)(object)val.gameObject != (Object)null && string.Equals(((Object)val.gameObject).name, "HTFML_Radar_" + mapId, StringComparison.OrdinalIgnoreCase);
			}
			catch
			{
				return false;
			}
		}

		private object CloneMapDot(object template, string name)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			object obj = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(template, null);
			if (obj == null)
			{
				return null;
			}
			FieldInfo fieldInfo = FindField(obj.GetType(), "_dot");
			object? obj2 = fieldInfo?.GetValue(template);
			Component val = (Component)((obj2 is Component) ? obj2 : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.transform.parent == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val.gameObject);
			((Object)val2).name = name;
			val2.transform.SetParent(val.transform.parent, false);
			val2.transform.localPosition = val.transform.localPosition;
			val2.transform.localRotation = val.transform.localRotation;
			val2.transform.localScale = val.transform.localScale;
			Component component = val2.GetComponent(fieldInfo.FieldType);
			if ((Object)(object)component == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			fieldInfo.SetValue(obj, component);
			val2.SetActive(val.gameObject.activeInHierarchy);
			return obj;
		}

		private bool IsNativeRadarCurrentlyVisible()
		{
			if (_radarUi == null)
			{
				return false;
			}
			if (!(FindField(_radarUi.GetType(), "_islandDots")?.GetValue(_radarUi) is Array array))
			{
				return false;
			}
			int num = Math.Min(5, array.Length);
			for (int i = 0; i < num; i++)
			{
				object value = array.GetValue(i);
				object? obj = ((value != null) ? FindField(value.GetType(), "_dot") : null)?.GetValue(value);
				Component val = (Component)((obj is Component) ? obj : null);
				if ((Object)(object)val != (Object)null && val.gameObject.activeInHierarchy)
				{
					return true;
				}
			}
			return false;
		}

		private void ApplyMapDotColor(RegisteredMap map)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (map == null || map.MapDot == null)
			{
				return;
			}
			object? obj = FindField(map.MapDot.GetType(), "_dot")?.GetValue(map.MapDot);
			Component val = (Component)((obj is Component) ? obj : null);
			PropertyInfo propertyInfo = ((object)val)?.GetType().GetProperty("color", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(propertyInfo != null) || !propertyInfo.CanWrite || !(propertyInfo.PropertyType == typeof(Color)))
			{
				return;
			}
			try
			{
				propertyInfo.SetValue(val, map.RadarColor, null);
			}
			catch
			{
			}
		}

		private void SetMapDotVisualActive(object mapDot, bool active)
		{
			if (mapDot != null)
			{
				object? obj = FindField(mapDot.GetType(), "_dot")?.GetValue(mapDot);
				Component val = (Component)((obj is Component) ? obj : null);
				if ((Object)(object)val != (Object)null && val.gameObject.activeSelf != active)
				{
					val.gameObject.SetActive(active);
				}
			}
		}

		private void ResetRadarReferences()
		{
			_radarUi = null;
			_radarUpdateDotMethod = null;
			_nextRadarAcquire = Time.unscaledTime + 0.75f;
			foreach (RegisteredMap map in _maps)
			{
				map.MapDot = null;
			}
		}

		private void CacheNativeGroundCollision()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			Collider val = null;
			float num = -1f;
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene sceneAt = SceneManager.GetSceneAt(i);
				if (!((Scene)(ref sceneAt)).IsValid() || !((Scene)(ref sceneAt)).isLoaded || (!((Scene)(ref sceneAt)).name.StartsWith("Island", StringComparison.OrdinalIgnoreCase) && !string.Equals(((Scene)(ref sceneAt)).name, "DevIsland", StringComparison.OrdinalIgnoreCase)))
				{
					continue;
				}
				GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects();
				for (int j = 0; j < rootGameObjects.Length; j++)
				{
					Collider[] componentsInChildren = rootGameObjects[j].GetComponentsInChildren<Collider>(true);
					foreach (Collider val2 in componentsInChildren)
					{
						if (!((Object)(object)val2 == (Object)null) && val2.enabled && !val2.isTrigger)
						{
							Bounds bounds = val2.bounds;
							Vector3 size = ((Bounds)(ref bounds)).size;
							float num2 = size.x * size.z;
							if (num2 > num)
							{
								num = num2;
								val = val2;
							}
						}
					}
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				_nativeGroundLayer = ((Component)val).gameObject.layer;
				_nativeGroundMaterial = val.sharedMaterial;
			}
		}

		private void AdaptLevelPhysics(Transform holder)
		{
			if ((Object)(object)holder == (Object)null)
			{
				return;
			}
			int num = LayerMask.NameToLayer("Level");
			if (num < 0)
			{
				num = ((_nativeGroundLayer >= 0) ? _nativeGroundLayer : 8);
			}
			Collider[] componentsInChildren = ((Component)holder).GetComponentsInChildren<Collider>(true);
			int num2 = 0;
			Collider[] array = componentsInChildren;
			foreach (Collider val in array)
			{
				if ((Object)(object)val == (Object)null || val.isTrigger)
				{
					continue;
				}
				Rigidbody component = ((Component)val).gameObject.GetComponent<Rigidbody>();
				if (!((Object)(object)component != (Object)null) || component.isKinematic)
				{
					((Component)val).gameObject.layer = num;
					TrySetLevelTag(((Component)val).gameObject);
					val.enabled = true;
					if ((Object)(object)_nativeGroundMaterial != (Object)null && (Object)(object)val.sharedMaterial == (Object)null)
					{
						val.sharedMaterial = _nativeGroundMaterial;
					}
					num2++;
				}
			}
			if (_verbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[PHYSICS] Adapted {num2} static collider(s) to Level.");
			}
		}

		private bool TrySetLevelTag(GameObject go)
		{
			try
			{
				if (!go.CompareTag("Level"))
				{
					go.tag = "Level";
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private object FindBoatPrefabInMemory()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Type type = AccessTools.TypeByName("Boat");
			if (type == null)
			{
				return null;
			}
			Object[] array = Resources.FindObjectsOfTypeAll(type);
			Object[] array2 = array;
			foreach (Object val in array2)
			{
				Component val2 = (Component)(object)((val is Component) ? val : null);
				if (!((Object)(object)val2 == (Object)null))
				{
					Scene scene = val2.gameObject.scene;
					if (!((Scene)(ref scene)).IsValid() || ((Scene)(ref scene)).buildIndex < 0)
					{
						return val;
					}
				}
			}
			return ((IEnumerable<Object>)array).FirstOrDefault((Func<Object, bool>)((Object o) => o != (Object)null));
		}

		private Object FindNamedComponentPrefab(Type componentType, string wantedName)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			Object[] array = Resources.FindObjectsOfTypeAll(componentType);
			Object val = null;
			Object[] array2 = array;
			foreach (Object obj in array2)
			{
				Component val2 = (Component)(object)((obj is Component) ? obj : null);
				if (!((Object)(object)val2 == (Object)null) && (((Object)val2.gameObject).name ?? "").IndexOf(wantedName, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Scene scene = val2.gameObject.scene;
					if (!((Scene)(ref scene)).IsValid() || ((Scene)(ref scene)).buildIndex < 0)
					{
						return (Object)(object)val2;
					}
					if (val == (Object)null)
					{
						val = (Object)(object)val2;
					}
				}
			}
			return val;
		}

		private GameObject FindIslandHolder(Scene scene)
		{
			if (!((Scene)(ref scene)).IsValid() || !((Scene)(ref scene)).isLoaded)
			{
				return null;
			}
			return ((IEnumerable<GameObject>)((Scene)(ref scene)).GetRootGameObjects()).FirstOrDefault((Func<GameObject, bool>)((GameObject r) => (Object)(object)r != (Object)null && string.Equals(((Object)r).name, "IslandHolder", StringComparison.OrdinalIgnoreCase)));
		}

		private Transform GetOrCreateChild(Transform parent, string name)
		{
			//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)
			Transform val = FindChildRecursive(parent, name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			GameObject val2 = new GameObject(name);
			val2.transform.SetParent(parent, false);
			return val2.transform;
		}

		private static object FindLiveObjectByTypeName(string typeName)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			Type type = AccessTools.TypeByName(typeName);
			if (type == null)
			{
				return null;
			}
			Object[] array = Resources.FindObjectsOfTypeAll(type);
			Object[] array2 = array;
			foreach (Object obj in array2)
			{
				Component val = (Component)(object)((obj is Component) ? obj : null);
				if (!((Object)(object)val == (Object)null))
				{
					Scene scene = val.gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
					{
						return val;
					}
				}
			}
			return ((IEnumerable<Object>)array).FirstOrDefault((Func<Object, bool>)((Object o) => o != (Object)null));
		}

		private static FieldInfo FindField(Type type, string name)
		{
			Type type2 = type;
			while (type2 != null)
			{
				FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field;
				}
				type2 = type2.BaseType;
			}
			return null;
		}

		private static Transform FindChildRecursive(Transform root, string name)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			if (string.Equals(((Object)root).name, name, StringComparison.Ordinal))
			{
				return root;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform val = FindChildRecursive(root.GetChild(i), name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static bool SetFieldIfExists(object target, string fieldName, object value)
		{
			if (target == null)
			{
				return false;
			}
			FieldInfo fieldInfo = FindField(target.GetType(), fieldName);
			if (fieldInfo == null)
			{
				return false;
			}
			try
			{
				object value2 = value;
				if (value != null && !fieldInfo.FieldType.IsInstanceOfType(value))
				{
					value2 = ((!fieldInfo.FieldType.IsEnum) ? Convert.ChangeType(value, fieldInfo.FieldType) : Enum.ToObject(fieldInfo.FieldType, value));
				}
				fieldInfo.SetValue(target, value2);
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
}