Decompiled source of CustomIslandsLoader v1.6.1

HTFMapLoader.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExtraIslands;
using FishNet.Object;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[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;
		}
	}
}
internal static class HoverGuard
{
	private static readonly HashSet<string> _told = new HashSet<string>();

	internal static bool HasIt(object instance, string field)
	{
		try
		{
			Object val = (Object)((instance is Object) ? instance : null);
			if (val == (Object)null)
			{
				return true;
			}
			FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), field);
			if (fieldInfo == null)
			{
				return true;
			}
			object? value = fieldInfo.GetValue(instance);
			if ((Object)((value is Object) ? value : null) != (Object)null)
			{
				return true;
			}
			if (_told.Add(val.name + "." + field))
			{
				MapLoaderPlugin.Log.LogWarning((object)("'" + val.name + "' has no " + field.TrimStart(new char[1] { '_' }) + " assigned, and the game reads it without checking - which throws and stops EVERY interaction near it, NPCs included. Skipped so the rest of the island keeps working. Fix the map by assigning it, or delete the stand."));
			}
			return false;
		}
		catch
		{
			return true;
		}
	}
}
[HarmonyPatch]
internal static class BaitStandsWithNoBait
{
	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("BaitPurchasable");
		if (!(type == null))
		{
			return AccessTools.Method(type, "OnStartHover", (Type[])null, (Type[])null);
		}
		return null;
	}

	private static bool Prepare()
	{
		return TargetMethod() != null;
	}

	private static bool Prefix(object __instance)
	{
		return HoverGuard.HasIt(__instance, "_bait");
	}
}
[HarmonyPatch]
internal static class AttachmentStandsWithNoAttachment
{
	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("AttachmentPurchasable");
		if (!(type == null))
		{
			return AccessTools.Method(type, "OnStartHover", (Type[])null, (Type[])null);
		}
		return null;
	}

	private static bool Prepare()
	{
		return TargetMethod() != null;
	}

	private static bool Prefix(object __instance)
	{
		return HoverGuard.HasIt(__instance, "_info");
	}
}
[BepInPlugin("yoxi.htf.maploader", "HTF Map Loader", "1.6.1")]
public class MapLoaderPlugin : BaseUnityPlugin
{
	[Serializable]
	private class MapInfo
	{
		public string name;

		public string author;

		public int replacesIsland = -1;

		public int casinoFromIsland = -1;

		public string sky = "";

		public int format = 1;

		public int gameplayFromIsland = -1;

		public RelinkEntry[] relinks;

		public RelinkNpc[] npcs;

		public RelinkMaterial[] materials;
	}

	private static class ArrivedUnderOwnSteam
	{
		internal static bool InsideTheRing;

		internal static float At = -999f;

		internal static bool ConsumeRecent()
		{
			bool result = Time.time - At < 30f;
			At = -999f;
			return result;
		}
	}

	[HarmonyPatch]
	private static class WatchTheRing
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("IslandSpawner");
			if (!(type == null))
			{
				return AccessTools.Method(type, "OnTriggerEnter", (Type[])null, (Type[])null);
			}
			return null;
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Prefix()
		{
			ArrivedUnderOwnSteam.InsideTheRing = true;
		}

		private static void Finalizer()
		{
			ArrivedUnderOwnSteam.InsideTheRing = false;
		}
	}

	[HarmonyPatch]
	private static class WatchWhoAsksForAnIsland
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("OnlineIslandManager");
			if (!(type == null))
			{
				return AccessTools.Method(type, "SpawnIsland", (Type[])null, (Type[])null);
			}
			return null;
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Prefix()
		{
			if (ArrivedUnderOwnSteam.InsideTheRing)
			{
				ArrivedUnderOwnSteam.At = Time.time;
			}
		}
	}

	private struct Placement
	{
		public Vector3 pos;

		public Quaternion rot;
	}

	private static class CasinoTrace
	{
		[HarmonyPatch(typeof(SlotMachine), "OnTriggerStay")]
		private static class Stay
		{
			private static void Prefix(Collider other)
			{
				if (Time.time - _lastStay < 2f)
				{
					return;
				}
				_lastStay = Time.time;
				try
				{
					Item val = ItemManager.Get(other);
					string text = (((Object)(object)val == (Object)null) ? "not an item" : (((Object)val).name + " holder=" + (((Object)(object)val.Holder != (Object)null) ? "held" : "free") + " creature=" + ((!((Object)(object)val.Creature != (Object)null)) ? "none" : (val.Creature.IsDead ? "dead" : "alive")) + " quest=" + val.IsQuestItem));
					Log.LogInfo((object)("Slot machine trigger: " + ((Object)other).name + " (layer " + ((Component)other).gameObject.layer + ") - " + text + "; rolling=" + SlotMachine.IsRolling + "; server=" + ((Object)(object)Server.Instance != (Object)null && ((NetworkBehaviour)Server.Instance).IsServerInitialized)));
				}
				catch (Exception ex)
				{
					Log.LogInfo((object)("Slot machine trigger: " + ((Object)other).name + " (" + ex.Message + ")"));
				}
			}
		}

		[HarmonyPatch(typeof(SlotMachineManager), "RollRandom")]
		private static class RollRandom
		{
			private static void Prefix()
			{
				Item[] availableItems = SlotMachine.AvailableItems;
				Log.LogInfo((object)("Slot machine: roll requested. Prizes " + ((availableItems == null) ? "NONE" : availableItems.Length.ToString()) + ", manager " + (SlotMachineManager_Instance() ? "ready" : "MISSING or not server")));
			}
		}

		[HarmonyPatch(typeof(SlotMachine), "Roll")]
		private static class Roll
		{
			private static void Prefix(byte[] itemIDs, byte rolled)
			{
				Log.LogInfo((object)("Slot machine: rolling " + ((itemIDs != null) ? itemIDs.Length : 0) + " item(s), result index " + rolled + "."));
			}
		}

		[HarmonyPatch(typeof(BetButton), "Interact")]
		private static class Bet
		{
			private static void Prefix(BetButton __instance)
			{
				Log.LogInfo((object)("Roulette: " + ((Object)__instance).name + " pressed. Betting=" + CasinoManager.IsBetting + " placed=" + CasinoManager.HasPlacedBet + " worth=" + (((Object)(object)CasinoManager.Instance != (Object)null) ? CasinoManager.Instance.TotalWorth.ToString() : "?")));
			}
		}

		[HarmonyPatch(typeof(CasinoManager), "SetBetItems")]
		private static class BetItems
		{
			private static void Prefix(List<Item> allItems)
			{
				Log.LogInfo((object)("Roulette: " + (allItems?.Count ?? 0) + " item(s) in the betting box."));
			}
		}

		[HarmonyPatch(typeof(CasinoManager), "ServerStartBet")]
		private static class StartBet
		{
			private static void Prefix()
			{
				Log.LogInfo((object)"Roulette: server starting the bet.");
			}
		}

		[HarmonyPatch(typeof(LocalCasino), "ServerStartRoulette")]
		private static class StartRoulette
		{
			private static void Prefix()
			{
				Log.LogInfo((object)"Roulette: wheel spinning.");
			}
		}

		private static float _lastStay = -10f;

		private static bool SlotMachineManager_Instance()
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(SlotMachineManager), "_instance");
			SlotMachineManager val = (SlotMachineManager)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val != (Object)null)
			{
				return ((NetworkBehaviour)val).IsServerInitialized;
			}
			return false;
		}
	}

	private static class MoneyTrace
	{
		[HarmonyPatch(typeof(MoneyManager), "SellItem")]
		private static class Sell
		{
			private static void Postfix(Item item)
			{
				try
				{
					Log.LogInfo((object)("Money [" + Side() + "] " + DateTime.Now.ToString("HH:mm:ss.fff") + ": sold " + (((Object)(object)item != (Object)null) ? ((Object)item).name : "?") + " for " + (((Object)(object)item != (Object)null) ? item.TotalWorth : 0) + ", wallet now " + MoneyManager.Money + ", last holder " + (((Object)(object)item != (Object)null && (Object)(object)item.LastHolder != (Object)null) ? ((Object)item.LastHolder).name : "none")));
				}
				catch (Exception ex)
				{
					Log.LogInfo((object)("Money: sale (" + ex.Message + ")"));
				}
			}
		}

		[HarmonyPatch(typeof(MoneyManager), "OnChangeMoney")]
		private static class Change
		{
			private static void Postfix(int prev, int next, bool asServer)
			{
				string text = "?";
				string text2 = "?";
				try
				{
					FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerUI), "_instance");
					text = ((fieldInfo != null && (Object)/*isinst with value type is only supported in some contexts*/ != (Object)null) ? "ok" : "MISSING");
					text2 = (((Object)(object)Player.LocalPlayer != (Object)null) ? "ok" : "MISSING");
				}
				catch (Exception)
				{
				}
				Log.LogInfo((object)("Money [" + Side() + "] " + DateTime.Now.ToString("HH:mm:ss.fff") + ": change " + prev + " -> " + next + (asServer ? " (server side)" : " (client side)") + ", money UI " + text + ", local player " + text2 + ", wallet now " + MoneyManager.Money));
			}

			private static Exception Finalizer(Exception __exception)
			{
				if (__exception != null)
				{
					Log.LogError((object)("Money: the change callback threw, so the money UI did not update: " + __exception));
				}
				return __exception;
			}
		}

		[HarmonyPatch(typeof(MoneyUI), "SetMoney")]
		private static class Ui
		{
			private static Exception Finalizer(Exception __exception)
			{
				if (__exception != null)
				{
					Log.LogError((object)("Money: the money UI itself threw while updating: " + __exception));
				}
				return __exception;
			}
		}

		private static string Side()
		{
			try
			{
				bool flag = (Object)(object)Server.Instance != (Object)null && ((NetworkBehaviour)Server.Instance).IsServerInitialized;
				bool flag2 = (Object)(object)Server.Instance != (Object)null && ((NetworkBehaviour)Server.Instance).IsClientInitialized;
				return (flag && flag2) ? "host" : (flag ? "server" : (flag2 ? "client" : "offline"));
			}
			catch (Exception)
			{
				return "?";
			}
		}
	}

	[HarmonyPatch]
	private static class SkipBorrowedSingletons
	{
		public static readonly Dictionary<Type, List<MethodInfo>> Guarded = new Dictionary<Type, List<MethodInfo>>();

		private static readonly string[] Names = new string[4] { "Awake", "OnEnable", "Start", "OnDisable" };

		private static IEnumerable<MethodBase> TargetMethods()
		{
			List<MethodBase> list = new List<MethodBase>();
			Type[] types;
			try
			{
				types = typeof(Island).Assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				types = ex.Types;
			}
			Type[] array = types;
			foreach (Type type in array)
			{
				if (type == null || !typeof(MonoBehaviour).IsAssignableFrom(type))
				{
					continue;
				}
				string[] names = Names;
				foreach (string name in names)
				{
					MethodInfo method;
					try
					{
						method = type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					}
					catch (Exception)
					{
						continue;
					}
					if (method == null || method.IsAbstract)
					{
						continue;
					}
					bool flag = false;
					try
					{
						foreach (KeyValuePair<OpCode, object> item in PatchProcessor.ReadMethodBody((MethodBase)method))
						{
							FieldInfo fieldInfo = item.Value as FieldInfo;
							if (item.Key == OpCodes.Stsfld && fieldInfo != null && fieldInfo.IsStatic && fieldInfo.FieldType.IsAssignableFrom(type))
							{
								flag = true;
								break;
							}
							MethodInfo methodInfo = item.Value as MethodInfo;
							if ((item.Key == OpCodes.Call || item.Key == OpCodes.Callvirt) && methodInfo != null && methodInfo.Name == "SetSingleInstance")
							{
								flag = true;
								break;
							}
						}
					}
					catch (Exception)
					{
					}
					if (flag)
					{
						if (!Guarded.TryGetValue(type, out var value))
						{
							value = (Guarded[type] = new List<MethodInfo>());
						}
						value.Add(method);
						list.Add(method);
					}
				}
			}
			List<string> list3 = new List<string>();
			foreach (KeyValuePair<Type, List<MethodInfo>> item2 in Guarded)
			{
				list3.Add(item2.Key.Name);
			}
			list3.Sort();
			Log.LogInfo((object)("Guarding " + list.Count + " singleton wake-up(s) on " + Guarded.Count + " class(es) against borrowed islands: " + string.Join(", ", list3.ToArray()) + "."));
			return list;
		}

		private static bool Prefix(MonoBehaviour __instance)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (Borrowing.Count == 0 || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			HashSet<string> borrowing = Borrowing;
			Scene scene = ((Component)__instance).gameObject.scene;
			return !borrowing.Contains(((Scene)(ref scene)).path);
		}
	}

	private class HomeValues
	{
		private Vector3 _player;

		private Vector3 _boat;

		private Vector3 _island;

		private float _playerRot;

		private float _size;

		private Quaternion _boatRot;

		private Island _cur;

		public static HomeValues Remember()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			return new HomeValues
			{
				_player = SpawnManager.PlayerSpawnPos,
				_playerRot = SpawnManager.PlayerSpawnRot,
				_boat = SpawnManager.BoatSpawnPos,
				_boatRot = SpawnManager.BoatSpawnRot,
				_island = Island.IslandPos,
				_size = Island.IslandSize,
				_cur = Island.CurIsland
			};
		}

		public void PutBack(Scene ours)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: 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_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: 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_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: 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_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: 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_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 playerSpawnPos = SpawnManager.PlayerSpawnPos;
			Vector3 islandPos = Island.IslandPos;
			SpawnManager val = null;
			Island val2 = null;
			GameObject[] rootGameObjects = ((Scene)(ref ours)).GetRootGameObjects();
			foreach (GameObject val3 in rootGameObjects)
			{
				if (!((Object)(object)val3 == (Object)null))
				{
					if ((Object)(object)val == (Object)null)
					{
						val = val3.GetComponentInChildren<SpawnManager>(true);
					}
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = val3.GetComponentInChildren<Island>(true);
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				object? value = AccessTools.Field(typeof(SpawnManager), "_playerSpawnPoint").GetValue(val);
				Transform val4 = (Transform)((value is Transform) ? value : null);
				object? value2 = AccessTools.Field(typeof(SpawnManager), "_boatSpawnPoint").GetValue(val);
				Transform val5 = (Transform)((value2 is Transform) ? value2 : null);
				if ((Object)(object)val4 != (Object)null)
				{
					_player = val4.position;
					_playerRot = val4.eulerAngles.y;
				}
				if ((Object)(object)val5 != (Object)null)
				{
					_boat = val5.position;
					_boatRot = val5.rotation;
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				_island = ((Component)val2).transform.position;
				FieldInfo fieldInfo = AccessTools.Field(typeof(Island), "_islandSize");
				if (fieldInfo != null)
				{
					_size = (float)fieldInfo.GetValue(val2);
				}
				_cur = val2;
			}
			SpawnManager.PlayerSpawnPos = _player;
			SpawnManager.PlayerSpawnRot = _playerRot;
			SpawnManager.BoatSpawnPos = _boat;
			SpawnManager.BoatSpawnRot = _boatRot;
			Island.IslandPos = _island;
			Island.IslandSize = _size;
			if ((Object)(object)_cur != (Object)null)
			{
				Island.CurIsland = _cur;
			}
			RestoreTheSingletons(ours);
			ResendTheDecorations(ours);
			Vector3 val6 = playerSpawnPos - _player;
			bool flag = ((Vector3)(ref val6)).sqrMagnitude > 1f;
			val6 = islandPos - _island;
			bool flag2 = ((Vector3)(ref val6)).sqrMagnitude > 1f;
			if (flag || flag2)
			{
				Log.LogInfo((object)("Borrowing from the game's islands had moved " + (flag ? ("the spawn point to " + ((Vector3)(ref playerSpawnPos)).ToString("0")) : "") + ((flag && flag2) ? " and " : "") + (flag2 ? ("the island's home to " + ((Vector3)(ref islandPos)).ToString("0")) : "") + ". Put back to the map's own: spawn " + ((Vector3)(ref _player)).ToString("0") + ", island " + ((Vector3)(ref _island)).ToString("0") + "."));
			}
		}
	}

	public const string Id = "yoxi.htf.maploader";

	internal static ManualLogSource Log;

	private static ConfigEntry<int> _slot;

	private static ConfigEntry<bool> _verbose;

	private static readonly ConfigEntry<bool>[] _useCustom = new ConfigEntry<bool>[5];

	private static ConfigEntry<float> _dayMinutes;

	private static ConfigEntry<KeyCode> _timeBackKey;

	private static ConfigEntry<KeyCode> _timeForwardKey;

	private static ConfigEntry<float> _timeScrubSeconds;

	private static ConfigEntry<bool> _importGameplay;

	private static ConfigEntry<int> _casinoFrom;

	private static ConfigEntry<bool> _terrainShader;

	private static ConfigEntry<bool> _paintItPink;

	private static ConfigEntry<bool> _standOnGround;

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

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

	private static readonly Dictionary<string, string> SkyOfScene = new Dictionary<string, string>();

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

	private static readonly List<AssetBundle> Held = new List<AssetBundle>();

	private static readonly Dictionary<string, MapInfo> InfoOfScene = new Dictionary<string, MapInfo>();

	private static readonly string[] Gameplay = new string[8] { "NPCs", "ShopItems", "SlotMachine", "CasinoHolder", "GrillHolder", "CreatureSpawners", "IslandManager", "ExtraColliders" };

	private static readonly List<GameObject> Imported = new List<GameObject>();

	private static readonly Dictionary<string, Placement> MapPlacement = new Dictionary<string, Placement>();

	private static readonly List<KeyValuePair<float, string>> _skipped = new List<KeyValuePair<float, string>>();

	public static readonly HashSet<string> Borrowing = new HashSet<string>();

	private static readonly string[] TakeWhole = new string[3] { "CasinoHolder", "SlotMachine", "GrillHolder" };

	private static readonly Dictionary<string, string> Anchors = new Dictionary<string, string> { { "CasinoHolder", "Wheel" } };

	private const float MovedOnPurpose = 6f;

	private static readonly Dictionary<string, string> TableRoots = new Dictionary<string, string> { { "CasinoHolder", "RouletteTable" } };

	private static bool _dumped;

	private const int IslandScenes = 6;

	private static readonly string[] NoCollision = new string[19]
	{
		"leaf", "leafs", "grass", "fern", "plant", "windy", "coconut", "poof", "smoke", "nightsky",
		"stars", "moonglow", "moonface", "galaxydust", "cloud", "sun", "shade", "aurora", "moonphase"
	};

	public static string MapsFolder => Path.Combine(Paths.PluginPath, "HTFMaps");

	private void Awake()
	{
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		_slot = ((BaseUnityPlugin)this).Config.Bind<int>("Maps", "ReplaceIsland", 2, "MAPMAKERS ONLY: the island a json-less test bundle stands in for, 0 to 4. Finished maps declare their island in their own .json, and that always wins - a custom island can only replace the island it was built for.");
		_importGameplay = ((BaseUnityPlugin)this).Config.Bind<bool>("Maps", "ImportGameplay", true, "Take the NPCs, shops and slot machines from the island your map replaces and put the real, working ones into your map. Turn this off for a map that is meant to be empty.");
		_casinoFrom = ((BaseUnityPlugin)this).Config.Bind<int>("Maps", "CasinoFromIsland", 3, "Put a working roulette table on your map by borrowing it from an island that has one. Only islands 3 and 4 (the fourth and fifth) have a casino. Set to -1 to leave it alone.\nPlace a prop named RouletteTable in your map to say where it should stand.");
		_terrainShader = ((BaseUnityPlugin)this).Config.Bind<bool>("Maps", "TerrainUsesGameShader", true, "Draw sculpted ground with the game's own land shader, so raised and carved areas match the island around them instead of looking like plain flat colour. Turn off if your terrain comes out grey.");
		_paintItPink = ((BaseUnityPlugin)this).Config.Bind<bool>("Maps", "HighlightSculptedGround", false, "Paint the map's own sculpted ground bright magenta, so it is obvious at a glance which ground is yours and which is something else. A diagnostic - turn it off again once you have looked.");
		_standOnGround = ((BaseUnityPlugin)this).Config.Bind<bool>("Maps", "StandGameplayOnTheGround", false, "Let the ground decide the height of imported NPCs and shops, keeping the left-and-right placement the map asked for. A map whose land has been reshaped leaves them at the old island's heights, hanging in the air.");
		_dayMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Sky", "MinutesPerDay", 20f, "For maps built with the day + night cycle: how many real minutes one full day (sunrise to sunrise) lasts.");
		_timeBackKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Sky", "TimeBackKey", (KeyCode)276, "Hold to roll time backwards on a day + night cycle map. Set to None to disable.");
		_timeForwardKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Sky", "TimeForwardKey", (KeyCode)275, "Hold to run time forwards on a day + night cycle map. Set to None to disable.");
		_timeScrubSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sky", "TimeScrubSeconds", 8f, "Holding a time key crosses one whole day in this many real seconds.");
		_verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Maps", "Verbose", false, "Log every island load, for working out why a map did not appear.");
		for (int i = 0; i < 5; i++)
		{
			_useCustom[i] = ((BaseUnityPlugin)this).Config.Bind<bool>("Maps", "UseCustomIsland" + (i + 1), true, "Load the custom map installed for island " + (i + 1) + ". false = the original island, with the map files kept installed for later.");
		}
		LoadBundles();
		SceneManager.sceneLoaded += OnSceneLoaded;
		try
		{
			Harmony val = new Harmony("yoxi.htf.maploader");
			int num = 0;
			int num2 = 0;
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				if (IsTrace(type) && (_verbose == null || !_verbose.Value))
				{
					continue;
				}
				try
				{
					List<MethodInfo> list = val.CreateClassProcessor(type).Patch();
					if (list != null && list.Count > 0)
					{
						num++;
					}
				}
				catch (Exception ex)
				{
					num2++;
					Log.LogError((object)("Patch class " + type.Name + " failed and was skipped: " + ex.Message));
				}
			}
			Log.LogInfo((object)("Patched IslandManager. " + num + " patch class(es) applied" + ((num2 > 0) ? (", " + num2 + " FAILED - see above.") : ".")));
			try
			{
				ExtraIslandsHost.Init(((BaseUnityPlugin)this).Config, Log);
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Could not start the extra-island support: " + ex2));
			}
			if (AccessTools.TypeByName("IslandSpawner") != null && AccessTools.TypeByName("OnlineIslandManager") != null)
			{
				Log.LogInfo((object)"Watching the island trigger rings, so sailing up to an island will not move your boat.");
			}
			else
			{
				Log.LogWarning((object)"Could not find IslandSpawner or OnlineIslandManager, so sailing up to an island may move your boat onto its spawn point. Every other way of arriving still works.");
			}
		}
		catch (Exception ex3)
		{
			Log.LogError((object)("Could not patch IslandManager - no custom map will load. " + ex3));
		}
	}

	private static MapInfo SidecarFor(string bundlePath)
	{
		string path = Path.ChangeExtension(bundlePath, ".json");
		if (!File.Exists(path))
		{
			return null;
		}
		try
		{
			string text = File.ReadAllText(path);
			MapInfo mapInfo = JsonUtility.FromJson<MapInfo>(text);
			if (mapInfo != null && mapInfo.format >= 2)
			{
				RelinkPaperwork relinkPaperwork = new RelinkPaperwork
				{
					format = mapInfo.format,
					gameplayFromIsland = mapInfo.gameplayFromIsland,
					relinks = mapInfo.relinks,
					npcs = mapInfo.npcs,
					materials = mapInfo.materials
				};
				Relink.Fill(relinkPaperwork, text);
				mapInfo.relinks = relinkPaperwork.relinks;
				mapInfo.npcs = relinkPaperwork.npcs;
				mapInfo.materials = relinkPaperwork.materials;
				mapInfo.gameplayFromIsland = relinkPaperwork.gameplayFromIsland;
			}
			return mapInfo;
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)(Path.GetFileName(path) + " could not be read (" + ex.Message + "); using the config defaults instead."));
			return null;
		}
	}

	private void LoadBundles()
	{
		Directory.CreateDirectory(MapsFolder);
		string[] array = Directory.GetDirectories(Paths.PluginPath, "HTFMaps", SearchOption.AllDirectories).SelectMany((string dir) => Directory.GetFiles(dir, "*.bundle")).Concat(from f in Directory.GetFiles(Paths.PluginPath, "*.bundle", SearchOption.AllDirectories)
			where File.Exists(Path.ChangeExtension(f, ".json"))
			select f)
			.Distinct()
			.ToArray();
		if (array.Length == 0)
		{
			Log.LogInfo((object)("No maps in " + MapsFolder + ". Drop a .bundle in there."));
			return;
		}
		string[] array2 = array;
		foreach (string text in array2)
		{
			AssetBundle val;
			try
			{
				val = AssetBundle.LoadFromFile(text);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not read " + Path.GetFileName(text) + ": " + ex.Message));
				continue;
			}
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)(Path.GetFileName(text) + " is not an asset bundle, or was built for a different Unity version. The game is 6000.4.4f1."));
				continue;
			}
			string[] allScenePaths = val.GetAllScenePaths();
			if (allScenePaths == null || allScenePaths.Length == 0)
			{
				Log.LogError((object)(Path.GetFileName(text) + " has no scene in it. A map bundle must be built FROM A SCENE, not from assets."));
				val.Unload(false);
				continue;
			}
			Held.Add(val);
			MapInfo mapInfo = SidecarFor(text);
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
			int num2 = ((mapInfo != null && mapInfo.replacesIsland >= 0) ? Mathf.Clamp(mapInfo.replacesIsland, 0, 4) : Mathf.Clamp(_slot.Value, 0, 4));
			if (Replacements.ContainsKey(num2))
			{
				Log.LogWarning((object)("Island " + num2 + " is already taken by another map. Set \"" + fileNameWithoutExtension + " replaces island\" to a free one, or remove a bundle from " + MapsFolder + "."));
			}
			Replacements[num2] = allScenePaths[0];
			SlotOfScene[allScenePaths[0]] = num2;
			if (mapInfo != null)
			{
				InfoOfScene[allScenePaths[0]] = mapInfo;
			}
			if (mapInfo != null && mapInfo.format >= 2)
			{
				Log.LogInfo((object)("   paperwork: format " + mapInfo.format + ", " + ((mapInfo.relinks != null) ? mapInfo.relinks.Length : 0) + " reference(s), " + ((mapInfo.npcs != null) ? mapInfo.npcs.Length : 0) + " NPC(s)" + ((mapInfo.gameplayFromIsland >= 0) ? (", casino/slots/grill from island " + mapInfo.gameplayFromIsland) : "") + " - loaded without borrowing."));
			}
			if (mapInfo != null && mapInfo.casinoFromIsland >= 0)
			{
				CasinoOfScene[allScenePaths[0]] = mapInfo.casinoFromIsland;
			}
			if (mapInfo != null && !string.IsNullOrEmpty(mapInfo.sky))
			{
				SkyOfScene[allScenePaths[0]] = mapInfo.sky;
			}
			if (mapInfo != null && (!string.IsNullOrEmpty(mapInfo.name) || !string.IsNullOrEmpty(mapInfo.author)))
			{
				Log.LogInfo((object)("   \"" + (string.IsNullOrEmpty(mapInfo.name) ? fileNameWithoutExtension : mapInfo.name) + "\"" + (string.IsNullOrEmpty(mapInfo.author) ? "" : (" by " + mapInfo.author))));
			}
			Log.LogInfo((object)("Loaded " + Path.GetFileName(text) + " -> " + Path.GetFileNameWithoutExtension(allScenePaths[0]) + ", replacing island " + num2 + "."));
			if (allScenePaths.Length > 1)
			{
				Log.LogWarning((object)(Path.GetFileName(text) + " holds " + allScenePaths.Length + " scenes; using the first."));
			}
		}
		if (Replacements.Count > 0)
		{
			Log.LogInfo((object)("---- " + Replacements.Count + " custom map(s) ready: " + string.Join(", ", SlotOfScene.Select((KeyValuePair<string, int> kv) => "island " + kv.Value + " <- " + Path.GetFileNameWithoutExtension(kv.Key)).ToArray()) + " ----"));
			Log.LogWarning((object)"CO-OP NOTE: every player in the lobby needs the SAME maps installed on the SAME islands - a player without the map will see the original island and stand in different scenery than the rest of the crew.");
		}
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: 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_0098: Unknown result type (might be due to invalid IL or missing references)
		if ((((Scene)(ref scene)).buildIndex >= 1 && ((Scene)(ref scene)).buildIndex <= 6) || IsOurs(scene))
		{
			((MonoBehaviour)this).StartCoroutine(GroundReport(scene));
		}
		bool flag = ArrivedUnderOwnSteam.ConsumeRecent();
		if (IsOurs(scene))
		{
			WakeAdditionalLights();
			Log.LogInfo((object)("Arriving at '" + ((Scene)(ref scene)).name + "': " + (flag ? "you sailed here, so nothing gets moved." : "you were brought here, so the map's own spawn points are used for you and the boat.")));
			((MonoBehaviour)this).StartCoroutine(SetUp(scene, !flag));
		}
		else if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).buildIndex < 0)
		{
			WakeAdditionalLights();
			try
			{
				Wire(scene);
				Log.LogInfo((object)("Wired the spawn points on '" + ((Scene)(ref scene)).name + "', an island this mod did not load. A spawn point is honoured whoever put it there."));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not wire the spawn points on '" + ((Scene)(ref scene)).name + "': " + ex.Message));
			}
		}
	}

	private static void WakeAdditionalLights()
	{
		try
		{
			RenderPipelineAsset currentRenderPipeline = GraphicsSettings.currentRenderPipeline;
			if ((Object)(object)currentRenderPipeline == (Object)null)
			{
				return;
			}
			Type type = ((object)currentRenderPipeline).GetType();
			FieldInfo field = type.GetField("m_AdditionalLightsRenderingMode", BindingFlags.Instance | BindingFlags.NonPublic);
			if (!(field == null))
			{
				if (Convert.ToInt32(field.GetValue(currentRenderPipeline)) != 1)
				{
					field.SetValue(currentRenderPipeline, Enum.ToObject(field.FieldType, 1));
					Log.LogInfo((object)"Additional lights set to per-pixel so map lights (torches...) can shine.");
				}
				FieldInfo field2 = type.GetField("m_AdditionalLightsPerObjectLimit", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field2 != null && Convert.ToInt32(field2.GetValue(currentRenderPipeline)) < 8)
				{
					field2.SetValue(currentRenderPipeline, 8);
				}
			}
		}
		catch (Exception)
		{
		}
	}

	private IEnumerator SetUp(Scene scene, bool placeEveryone)
	{
		//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)
		if (!((Scene)(ref scene)).IsValid() || !((Scene)(ref scene)).isLoaded || string.IsNullOrEmpty(((Scene)(ref scene)).path))
		{
			Log.LogInfo((object)("'" + ((Scene)(ref scene)).name + "' is already being unloaded - nothing to set up; the next load of it takes over."));
			yield break;
		}
		HomeValues home = HomeValues.Remember();
		if ((InfoOfScene.TryGetValue(((Scene)(ref scene)).path ?? "", out var value) || InfoOfScene.TryGetValue(FirstKeyFor(scene), out value)) && value != null && value.format >= 2)
		{
			yield return SetUpFromPaperwork(scene, value, home, placeEveryone);
			yield break;
		}
		if (_importGameplay != null && _importGameplay.Value && (SlotOfScene.TryGetValue(((Scene)(ref scene)).path ?? "", out var value2) || SlotOfScene.TryGetValue(FirstKeyFor(scene), out value2)))
		{
			if (BringsItsOwnGameplay(scene))
			{
				Log.LogInfo((object)("This map carries its own working NPCs and shops, so nothing was borrowed from island " + value2 + ". They are the mapmaker's own."));
			}
			else
			{
				yield return ImportGameplay(scene, value2);
			}
		}
		int num = ((_casinoFrom != null) ? _casinoFrom.Value : (-1));
		if (CasinoOfScene.TryGetValue(((Scene)(ref scene)).path ?? "", out var value3))
		{
			num = value3;
		}
		if (num >= 0)
		{
			yield return ImportCasino(scene, num);
		}
		yield return FetchRequestedGoods(scene);
		yield return FillFromTheGamesOwnIsland(scene);
		if (!((Scene)(ref scene)).IsValid() || !((Scene)(ref scene)).isLoaded)
		{
			Log.LogInfo((object)(((Scene)(ref scene)).name + " was unloaded while the game's islands were being borrowed from; the next load of it does the work."));
			if (Borrowing.Count > 0)
			{
				Borrowing.Clear();
			}
			yield break;
		}
		try
		{
			home.PutBack(scene);
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not put the map's own spawn and island values back: " + ex.Message));
		}
		try
		{
			ReviveTheCasinoAndSlots(scene);
		}
		catch (Exception ex2)
		{
			Log.LogWarning((object)("Could not revive the casino and slots: " + ex2.Message));
		}
		try
		{
			if (SwapInGameMaterials(scene) > 0)
			{
				Hooks.RecolourTheNpcs(scene, ((Scene)(ref scene)).name);
			}
		}
		catch (Exception ex3)
		{
			Log.LogWarning((object)("Late material swap failed: " + ex3.Message));
		}
		((MonoBehaviour)this).StartCoroutine(CasinoReport(scene));
		((MonoBehaviour)this).StartCoroutine(LightReport(scene));
		if (Borrowing.Count > 0)
		{
			Log.LogWarning((object)("Borrowing finished with " + Borrowing.Count + " island(s) still marked as borrowed - cleared, or the game's own islands would never wake."));
			Borrowing.Clear();
		}
		try
		{
			Wire(scene);
		}
		catch (Exception ex4)
		{
			Log.LogError((object)("Could not wire up " + ((Scene)(ref scene)).name + ": " + ex4));
		}
		((MonoBehaviour)this).StartCoroutine(PutTheBoatWhereTheMapAsked(placeEveryone));
		((MonoBehaviour)this).StartCoroutine(PutThePlayerWhereTheMapAsked(placeEveryone));
	}

	private IEnumerator SetUpFromPaperwork(Scene scene, MapInfo info, HomeValues home, bool placeEveryone)
	{
		//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)
		try
		{
			Relink.Npcs(scene, info.npcs);
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not place the game's NPCs: " + ex));
		}
		try
		{
			Relink.Fields(scene, info.relinks);
		}
		catch (Exception ex2)
		{
			Log.LogError((object)("Could not hand the map the game's assets: " + ex2));
		}
		if (info.gameplayFromIsland >= 0 && HasAnyOf(scene, TakeWhole))
		{
			yield return TakeGameplayGroups(scene, info.gameplayFromIsland);
		}
		if (!((Scene)(ref scene)).IsValid() || !((Scene)(ref scene)).isLoaded)
		{
			Log.LogInfo((object)(((Scene)(ref scene)).name + " was unloaded while the game's casino/slots/grill were being fetched; the next load of it does the work."));
			yield break;
		}
		try
		{
			home.PutBack(scene);
		}
		catch (Exception ex3)
		{
			Log.LogWarning((object)("Could not put the map's own spawn and island values back: " + ex3.Message));
		}
		try
		{
			ReviveTheCasinoAndSlots(scene);
		}
		catch (Exception ex4)
		{
			Log.LogWarning((object)("Could not revive the casino and slots: " + ex4.Message));
		}
		try
		{
			if (SwapInGameMaterials(scene) > 0)
			{
				Hooks.RecolourTheNpcs(scene, ((Scene)(ref scene)).name);
			}
		}
		catch (Exception ex5)
		{
			Log.LogWarning((object)("Material swap failed: " + ex5.Message));
		}
		try
		{
			Relink.Shaders(scene, info.materials);
		}
		catch (Exception ex6)
		{
			Log.LogWarning((object)("Could not restore the map's shaders by name: " + ex6.Message));
		}
		try
		{
			RegisterTheNpcsProperly(scene);
		}
		catch (Exception ex7)
		{
			Log.LogWarning((object)("Could not register the map's NPCs: " + ex7.Message));
		}
		((MonoBehaviour)this).StartCoroutine(RegisterAgainOnceTheServerIsUp(scene));
		((MonoBehaviour)this).StartCoroutine(CasinoReport(scene));
		((MonoBehaviour)this).StartCoroutine(LightReport(scene));
		if (Borrowing.Count > 0)
		{
			Borrowing.Clear();
		}
		try
		{
			Wire(scene);
		}
		catch (Exception ex8)
		{
			Log.LogError((object)("Could not wire up " + ((Scene)(ref scene)).name + ": " + ex8));
		}
		((MonoBehaviour)this).StartCoroutine(PutTheBoatWhereTheMapAsked(placeEveryone));
		((MonoBehaviour)this).StartCoroutine(PutThePlayerWhereTheMapAsked(placeEveryone));
	}

	private static bool HasAnyOf(Scene scene, string[] names)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		Transform val = FindIn(scene, "IslandHolder");
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		foreach (string text in names)
		{
			Transform val2 = val.Find(text);
			if ((Object)(object)val2 != (Object)null && !WasImported(val2))
			{
				return true;
			}
		}
		return false;
	}

	private IEnumerator TakeGameplayGroups(Scene ours, int island)
	{
		//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)
		string path = SceneUtility.GetScenePathByBuildIndex(island + 1);
		AsyncOperation op = BorrowIsland(island + 1);
		if (op == null && !string.IsNullOrEmpty(path))
		{
			op = BorrowIslandByPath(path);
		}
		if (op == null)
		{
			Log.LogWarning((object)("Could not open island " + island + " for the casino, slot machine or grill; the map's own copies stay."));
			yield break;
		}
		while (!op.isDone)
		{
			yield return null;
		}
		Scene src = SceneManager.GetSceneByBuildIndex(island + 1);
		if (!((Scene)(ref src)).IsValid() && !string.IsNullOrEmpty(path))
		{
			src = SceneManager.GetSceneByPath(path);
		}
		if (!((Scene)(ref src)).IsValid())
		{
			yield break;
		}
		MapPlacement.Clear();
		try
		{
			ReplaceWithTheGamesOwn(src, ours, island);
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not take the game's casino/slots/grill: " + ex.Message));
		}
		foreach (object item in CloseTheBorrowedIsland(src, ours))
		{
			yield return item;
		}
	}

	private IEnumerator ImportCasino(Scene ours, int fromIsland)
	{
		//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)
		if ((Object)(object)FindIn(ours, "CasinoHolder") != (Object)null)
		{
			yield break;
		}
		Transform mine = FindIn(ours, "RouletteTable");
		if ((Object)(object)mine == (Object)null)
		{
			if (_verbose != null && _verbose.Value)
			{
				Log.LogInfo((object)"No RouletteTable in this map, so no casino to place.");
			}
			yield break;
		}
		Transform val = FindUnder(mine, "Wheel");
		Transform val2 = (((Object)(object)val != (Object)null) ? val : mine);
		Vector3 targetPos = val2.position;
		Quaternion targetRot = val2.rotation;
		int buildIndex = fromIsland + 1;
		AsyncOperation op = BorrowIsland(buildIndex);
		if (op == null)
		{
			Log.LogError((object)("Could not open island " + fromIsland + "."));
			yield break;
		}
		while (!op.isDone)
		{
			yield return null;
		}
		Scene sceneByBuildIndex = SceneManager.GetSceneByBuildIndex(buildIndex);
		if (!((Scene)(ref sceneByBuildIndex)).IsValid())
		{
			Log.LogError((object)("Island " + fromIsland + " did not load."));
			yield break;
		}
		Transform val3 = FindIn(sceneByBuildIndex, "CasinoHolder");
		Transform val4 = FindNpc(sceneByBuildIndex, "Roulette");
		if ((Object)(object)val3 == (Object)null)
		{
			Log.LogWarning((object)("Island " + fromIsland + " has no CasinoHolder. Only the fourth and fifth islands do - set CasinoFromIsland to 3 or 4."));
		}
		else
		{
			val3.SetParent((Transform)null, true);
			SceneManager.MoveGameObjectToScene(((Component)val3).gameObject, ours);
			Transform val5 = FindUnder(val3, "Wheel");
			Transform val6 = (((Object)(object)val5 != (Object)null) ? val5 : val3);
			Quaternion val7 = Quaternion.Inverse(val3.rotation) * val6.rotation;
			val3.rotation = targetRot * Quaternion.Inverse(val7);
			val3.position += targetPos - val6.position;
			Transform val8 = FindIn(ours, "IslandHolder");
			if ((Object)(object)val8 != (Object)null)
			{
				val3.SetParent(val8, true);
			}
			Imported.Add(((Component)val3).gameObject);
			WakeTheMoved(((Component)val3).gameObject);
			MeshRenderer[] componentsInChildren = ((Component)val3).GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val9 in componentsInChildren)
			{
				MeshFilter component = ((Component)val9).GetComponent<MeshFilter>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null) && ((Object)component.sharedMesh).name.StartsWith("Combined"))
				{
					((Renderer)val9).enabled = false;
				}
			}
			int num = 0;
			Renderer[] componentsInChildren2 = ((Component)mine).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val10 in componentsInChildren2)
			{
				if (!((Object)(object)val10 == (Object)null) && val10.enabled && !IsPartOfTable(((Component)val10).transform, mine))
				{
					val10.enabled = false;
					num++;
				}
			}
			if ((Object)(object)val4 != (Object)null)
			{
				Vector3 val11 = val4.position - val6.position;
				val4.SetParent((Transform)null, true);
				SceneManager.MoveGameObjectToScene(((Component)val4).gameObject, ours);
				val4.position = targetPos + val11;
				Transform val12 = FindIn(ours, "NPCs");
				if ((Object)(object)val12 != (Object)null)
				{
					val4.SetParent(val12, true);
				}
			}
			Log.LogInfo((object)("Casino from island " + fromIsland + " lined up on your table at " + ((Vector3)(ref targetPos)).ToString("0.00") + ", " + num + " duplicate piece(s) hidden" + (((Object)(object)val4 != (Object)null) ? ", croupier included." : ".")));
		}
		foreach (object item in CloseTheBorrowedIsland(sceneByBuildIndex, ours))
		{
			yield return item;
		}
	}

	private static List<Transform> FindAllIn(Scene scene, string name)
	{
		List<Transform> list = new List<Transform>();
		GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
		for (int i = 0; i < rootGameObjects.Length; i++)
		{
			Transform[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)((Component)val).gameObject).name == name)
				{
					list.Add(val);
				}
			}
		}
		return list;
	}

	private static Transform FindTableTop(Scene scene)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		Transform val = FindIn(scene, "IslandHolder");
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		Transform val2 = val.Find("Meshes");
		if ((Object)(object)val2 == (Object)null)
		{
			return null;
		}
		foreach (Transform item in val2)
		{
			Transform val3 = item;
			if (((Object)((Component)val3).gameObject).name == "Table")
			{
				return val3;
			}
		}
		return null;
	}

	private static bool IsPartOfTable(Transform t, Transform root)
	{
		Transform val = t;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root.parent)
		{
			if (((Object)((Component)val).gameObject).name == "Table")
			{
				return true;
			}
			val = val.parent;
		}
		return false;
	}

	private static Transform FindNpc(Scene scene, string contains)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		Transform val = FindIn(scene, "NPCs");
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		foreach (Transform item in val)
		{
			Transform val2 = item;
			if (((Object)((Component)val2).gameObject).name.IndexOf(contains, StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return val2;
			}
		}
		return null;
	}

	private static Transform FindUnder(Transform root, string name)
	{
		Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
		foreach (Transform val in componentsInChildren)
		{
			if (((Object)((Component)val).gameObject).name == name)
			{
				return val;
			}
		}
		return null;
	}

	private static string FirstKeyFor(Scene scene)
	{
		foreach (KeyValuePair<string, int> item in SlotOfScene)
		{
			if (Path.GetFileNameWithoutExtension(item.Key) == ((Scene)(ref scene)).name)
			{
				return item.Key;
			}
		}
		return "";
	}

	private IEnumerator ImportGameplay(Scene ours, int slot)
	{
		//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)
		int removed = StripDeadGameplay(ours);
		int buildIndex = slot + 1;
		AsyncOperation op = BorrowIsland(buildIndex);
		if (op == null)
		{
			Log.LogError((object)("Could not load island " + slot + " to borrow its gameplay from."));
			yield break;
		}
		while (!op.isDone)
		{
			yield return null;
		}
		Scene sceneByBuildIndex = SceneManager.GetSceneByBuildIndex(buildIndex);
		if (!((Scene)(ref sceneByBuildIndex)).IsValid())
		{
			Log.LogError((object)("Island " + slot + " did not load."));
			yield break;
		}
		int moved = 0;
		int placed = 0;
		List<Transform> list = new List<Transform>();
		GameObject[] rootGameObjects = ((Scene)(ref sceneByBuildIndex)).GetRootGameObjects();
		foreach (GameObject val in rootGameObjects)
		{
			if (((Object)val).name != "IslandHolder")
			{
				if (Wanted(((Object)val).name))
				{
					list.Add(val.transform);
				}
				continue;
			}
			foreach (Transform item in val.transform)
			{
				Transform val2 = item;
				if (Wanted(((Object)val2).name))
				{
					list.Add(val2);
				}
			}
		}
		Transform val3 = FindIn(ours, "IslandHolder");
		foreach (Transform item2 in list)
		{
			if ((Object)(object)item2 == (Object)null)
			{
				continue;
			}
			if (!((Scene)(ref ours)).IsValid() || !((Scene)(ref ours)).isLoaded)
			{
				Log.LogInfo((object)("'" + ((Scene)(ref ours)).name + "' is being unloaded already - the borrowed island is closed and the next load takes over."));
				foreach (object item3 in CloseTheBorrowedIsland(sceneByBuildIndex, ours))
				{
					yield return item3;
				}
				yield break;
			}
			item2.SetParent((Transform)null, true);
			SceneManager.MoveGameObjectToScene(((Component)item2).gameObject, ours);
			if ((Object)(object)val3 != (Object)null)
			{
				item2.SetParent(val3, true);
			}
			placed += PlaceLikeTheMapAsked(item2);
			Imported.Add(((Component)item2).gameObject);
			WakeTheMoved(((Component)item2).gameObject);
			moved++;
		}
		foreach (object item4 in CloseTheBorrowedIsland(sceneByBuildIndex, ours))
		{
			yield return item4;
		}
		RegisterTheNpcsProperly(ours);
		((MonoBehaviour)this).StartCoroutine(RegisterAgainOnceTheServerIsUp(ours));
		Log.LogInfo((object)("Borrowed " + moved + " gameplay group(s) from island " + slot + ((removed > 0) ? (", after removing " + removed + " dead copies from the map") : "") + ". " + ((placed > 0) ? (placed + " object(s) moved to where the map put them.") : "The map had none of its own, so they stand where the island had them.")));
	}

	private static bool Wanted(string name)
	{
		string[] gameplay = Gameplay;
		foreach (string text in gameplay)
		{
			if (name == text)
			{
				return true;
			}
		}
		return false;
	}

	private static bool BringsItsOwnGameplay(Scene scene)
	{
		if (!((Scene)(ref scene)).IsValid())
		{
			return false;
		}
		GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
		foreach (GameObject val in rootGameObjects)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && ((object)val2).GetType().Name == "NPC")
				{
					return true;
				}
			}
		}
		return false;
	}

	private static int StripDeadGameplay(Scene scene)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Expected O, but got Unknown
		MapPlacement.Clear();
		Imported.Clear();
		List<GameObject> list = new List<GameObject>();
		GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
		foreach (GameObject val in rootGameObjects)
		{
			if (Wanted(((Object)val).name))
			{
				list.Add(val);
				continue;
			}
			foreach (Transform item in val.transform)
			{
				Transform val2 = item;
				if (Wanted(((Object)val2).name))
				{
					list.Add(((Component)val2).gameObject);
				}
			}
		}
		int num = 0;
		foreach (GameObject item2 in list)
		{
			if (!((Object)(object)item2 == (Object)null))
			{
				RememberTree(((Object)item2).name, item2.transform);
				Object.Destroy((Object)(object)item2);
				num++;
			}
		}
		return num;
	}

	private static void RememberTree(string key, Transform t)
	{
		RememberTree(key, t, 0);
	}

	private static void RememberTree(string key, Transform t, int depth)
	{
		//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_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Expected O, but got Unknown
		if ((Object)(object)t == (Object)null)
		{
			return;
		}
		Placement value = new Placement
		{
			pos = t.position,
			rot = t.rotation
		};
		if (!MapPlacement.ContainsKey(key))
		{
			MapPlacement[key] = value;
		}
		if (depth > 0 && IsRigged(t))
		{
			return;
		}
		foreach (Transform item in t)
		{
			Transform val = item;
			RememberTree(key + "/" + ((Object)val).name, val, depth + 1);
		}
	}

	private static bool IsRigged(Transform t)
	{
		if (!((Object)(object)((Component)t).GetComponent<SkinnedMeshRenderer>() != (Object)null))
		{
			return (Object)(object)((Component)t).GetComponentInChildren<SkinnedMeshRenderer>(true) != (Object)null;
		}
		return true;
	}

	private static int PlaceLikeTheMapAsked(Transform group)
	{
		//IL_003d: 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_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Expected O, but got Unknown
		if ((Object)(object)group == (Object)null)
		{
			return 0;
		}
		if (!IsAContainer(((Object)group).name))
		{
			return MoveWholeThing(((Object)group).name, group);
		}
		int num = 0;
		if (MapPlacement.TryGetValue(((Object)group).name, out var value))
		{
			group.position = value.pos;
			group.rotation = value.rot;
			num++;
		}
		List<Transform> list = new List<Transform>();
		foreach (Transform item2 in group)
		{
			Transform item = item2;
			list.Add(item);
		}
		foreach (Transform item3 in list)
		{
			if ((Object)(object)item3 != (Object)null)
			{
				num += MoveWholeThing(((Object)group).name + "/" + ((Object)item3).name, item3);
			}
		}
		return num;
	}

	private static bool IsAContainer(string name)
	{
		if (!(name == "ShopItems") && !(name == "NPCs"))
		{
			return name == "CreatureSpawners";
		}
		return true;
	}

	private static int MoveWholeThing(string key, Transform t)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: 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_0066: 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)
		//IL_00a5: 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)
		if ((Object)(object)t == (Object)null)
		{
			return 0;
		}
		Vector3 shift = Vector3.zero;
		float furthest = -1f;
		bool rootItself = false;
		BiggestMove(key, t, ref shift, ref furthest, ref rootItself, key, 0);
		if (furthest < 0f)
		{
			return 0;
		}
		if (rootItself && MapPlacement.TryGetValue(key, out var value))
		{
			t.rotation = value.rot;
		}
		if (((Vector3)(ref shift)).sqrMagnitude > 1E-08f)
		{
			t.position += shift;
		}
		if (_verbose != null && _verbose.Value)
		{
			ManualLogSource log = Log;
			string[] obj = new string[5] { "   placed ", key, " at ", null, null };
			Vector3 position = t.position;
			obj[3] = ((Vector3)(ref position)).ToString("0.00");
			obj[4] = (rootItself ? "" : "  (following a part inside it)");
			log.LogInfo((object)string.Concat(obj));
		}
		return 1;
	}

	private static void BiggestMove(string key, Transform t, ref Vector3 shift, ref float furthest, ref bool rootItself, string rootKey, int depth)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Expected O, but got Unknown
		if ((Object)(object)t == (Object)null)
		{
			return;
		}
		if (MapPlacement.TryGetValue(key, out var value))
		{
			Vector3 val = value.pos - t.position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (sqrMagnitude > furthest)
			{
				furthest = sqrMagnitude;
				shift = val;
				rootItself = key == rootKey;
			}
		}
		if (depth > 0 && IsRigged(t))
		{
			return;
		}
		foreach (Transform item in t)
		{
			Transform val2 = item;
			BiggestMove(key + "/" + ((Object)val2).name, val2, ref shift, ref furthest, ref rootItself, rootKey, depth + 1);
		}
	}

	private static void StandThemOnTheGround()
	{
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected O, but got Unknown
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: 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_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: 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_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		if (_standOnGround != null && !_standOnGround.Value)
		{
			return;
		}
		int num = LayerMask.NameToLayer("Level");
		if (num < 0)
		{
			num = 8;
		}
		int num2 = 1 << num;
		int num3 = 0;
		foreach (GameObject item in Imported)
		{
			if ((Object)(object)item == (Object)null)
			{
				continue;
			}
			foreach (Transform item2 in item.transform)
			{
				Transform val = item2;
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				RaycastHit[] array = Physics.RaycastAll(val.position + Vector3.up * 4f, Vector3.down, 40f, num2, (QueryTriggerInteraction)1);
				float num4 = float.NegativeInfinity;
				string text = "nothing";
				RaycastHit[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					RaycastHit val2 = array2[i];
					if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(val) && !(((Component)((RaycastHit)(ref val2)).collider).gameObject.scene != ((Component)val).gameObject.scene) && !(((RaycastHit)(ref val2)).point.y > val.position.y + 0.5f) && ((RaycastHit)(ref val2)).point.y > num4)
					{
						num4 = ((RaycastHit)(ref val2)).point.y;
						text = ((Object)((Component)((RaycastHit)(ref val2)).collider).gameObject).name;
					}
				}
				if (float.IsNegativeInfinity(num4))
				{
					Log.LogInfo((object)("   " + ((Object)val).name + " has no ground under it at all - left where the map put it."));
					continue;
				}
				float num5 = val.position.y - num4;
				if (!(num5 < 0.3f))
				{
					Vector3 position = val.position;
					position.y = num4;
					val.position = position;
					num3++;
					Log.LogInfo((object)("   dropped " + ((Object)val).name + " " + num5.ToString("0.0") + " m onto " + text));
				}
			}
		}
		if (num3 > 0)
		{
			Log.LogInfo((object)("Stood " + num3 + " thing(s) back on the ground - the map had them at the old island's heights."));
		}
	}

	private static void FloatIt(Transform marker)
	{
		//IL_000b: 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)
		if (SeaLevel(out var y) && !(marker.position.y >= y - 0.05f))
		{
			Log.LogWarning((object)("Boat spawn is " + (y - marker.position.y).ToString("0.00") + " m below the sea surface (y " + y.ToString("0.0") + "). The boat will spawn there exactly, submerged, and float up. Move BoatSpawnPoint to y " + y.ToString("0.0") + " in the editor."));
		}
	}

	private static bool SeaLevel(out float y)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: 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_0080: 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_0097: 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_00be: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
		y = 0f;
		Renderer val = null;
		Bounds bounds2;
		for (int i = 0; i < SceneManager.sceneCount; i++)
		{
			Scene sceneAt = SceneManager.GetSceneAt(i);
			if (!((Scene)(ref sceneAt)).isLoaded)
			{
				continue;
			}
			GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects();
			for (int j = 0; j < rootGameObjects.Length; j++)
			{
				Renderer[] componentsInChildren = rootGameObjects[j].GetComponentsInChildren<Renderer>(false);
				foreach (Renderer val2 in componentsInChildren)
				{
					if ((Object)(object)val2 == (Object)null || !val2.enabled || !((Object)((Component)val2).gameObject).name.StartsWith("Water"))
					{
						continue;
					}
					Bounds bounds = val2.bounds;
					if (((Bounds)(ref bounds)).size.x < 100f || ((Bounds)(ref bounds)).size.y > 1f)
					{
						continue;
					}
					if (!((Object)(object)val == (Object)null))
					{
						float x = ((Bounds)(ref bounds)).size.x;
						bounds2 = val.bounds;
						if (!(x > ((Bounds)(ref bounds2)).size.x))
						{
							continue;
						}
					}
					val = val2;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		bounds2 = val.bounds;
		y = ((Bounds)(ref bounds2)).center.y;
		return true;
	}

	private static void Skipped(MeshFilter mf, string why)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		Renderer component = ((Component)mf).GetComponent<Renderer>();
		Vector3 val;
		if (!((Object)(object)component != (Object)null))
		{
			val = Vector3.zero;
		}
		else
		{
			Bounds bounds = component.bounds;
			val = ((Bounds)(ref bounds)).size;
		}
		Vector3 val2 = val;
		float num = Mathf.Max(val2.x, Mathf.Max(val2.y, val2.z));
		if (!(num < 1.5f))
		{
			_skipped.Add(new KeyValuePair<float, string>(num, ((Object)((Component)mf).gameObject).name + "  (" + num.ToString("0.0") + " m)  - " + why));
		}
	}

	private static void ReportSolidity(Scene scene)
	{
		//IL_0048: 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_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		List<KeyValuePair<float, string>> list = new List<KeyValuePair<float, string>>();
		GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
		for (int i = 0; i < rootGameObjects.Length; i++)
		{
			Renderer[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<Renderer>(false);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || !val.enabled)
				{
					continue;
				}
				Bounds bounds = val.bounds;
				Vector3 size = ((Bounds)(ref bounds)).size;
				float num = Mathf.Max(size.x, Mathf.Max(size.y, size.z));
				if (num < 2f || num > 100f)
				{
					continue;
				}
				string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
				if (text.StartsWith("palm") || text.StartsWith("rock") || text.StartsWith("coconut") || text.StartsWith("fire") || text.StartsWith("smoke"))
				{
					continue;
				}
				GameObject gameObject = ((Component)val).gameObject;
				Collider component = gameObject.GetComponent<Collider>();
				string text2;
				if ((Object)(object)component == (Object)null)
				{
					text2 = "NO COLLIDER";
				}
				else if (!component.enabled)
				{
					text2 = "collider DISABLED";
				}
				else
				{
					MeshCollider val2 = (MeshCollider)(object)((component is MeshCollider) ? component : null);
					text2 = (((Object)(object)val2 == (Object)null) ? ((object)component).GetType().Name : (((Object)(object)val2.sharedMesh == (Object)null) ? "MeshCollider with NO MESH" : (val2.sharedMesh.isReadable ? "MeshCollider ok" : "MeshCollider, mesh NOT READABLE")));
				}
				string text3 = "";
				if ((Object)(object)component != (Object)null && component.enabled)
				{
					bounds = val.bounds;
					Vector3 center = ((Bounds)(ref bounds)).center;
					bounds = component.bounds;
					float num2 = Vector3.Distance(center, ((Bounds)(ref bounds)).center);
					if (num2 > 0.5f)
					{
						text3 = "   *** COLLIDER IS " + num2.ToString("0.0") + " m FROM THE MESH ***";
					}
				}
				list.Add(new KeyValuePair<float, string>(num, ((Object)gameObject).name + "  (" + num.ToString("0.0") + " m)  layer " + gameObject.layer + " " + LayerMask.LayerToName(gameObject.layer) + "  - " + text2 + text3));
			}
		}
		list.Sort((KeyValuePair<float, string> a, KeyValuePair<float, string> b) => b.Key.CompareTo(a.Key));
		Log.LogInfo((object)"SOLIDITY, biggest first:");
		for (int num3 = 0; num3 < list.Count && num3 < 30; num3++)
		{
			Log.LogInfo((object)("   " + list[num3].Value));
		}
	}

	private static void RegisterTheNpcsProperly(Scene ours)
	{
		//IL_0348: Unknown result type (might be due to invalid IL or missing references)
		//IL_039e: Unknown result type (might be due to invalid IL or missing references)
		Type type = AccessTools.TypeByName("NPC");
		Type type2 = AccessTools.TypeByName("NPCManager");
		if (type == null || type2 == null)
		{
			return;
		}
		FieldInfo fieldInfo = AccessTools.Field(type2, "_idToNpc");
		MethodInfo methodInfo = AccessTools.Method(type2, "AddNpc", (Type[])null, (Type[])null);
		if (fieldInfo == null || methodInfo == null || !(fieldInfo.GetValue(null) is IDictionary dictionary))
		{
			return;
		}
		List<object> list = new List<object>();
		foreach (DictionaryEntry item in dictionary)
		{
			object? value = item.Value;
			if ((Object)((value is Object) ? value : null) == (Object)null)
			{
				list.Add(item.Key);
			}
		}
		foreach (object item2 in list)
		{
			dictionary.Remove(item2);
		}
		int num = 0;
		GameObject[] rootGameObjects = ((Scene)(ref ours)).GetRootGameObjects();
		for (int i = 0; i < rootGameObjects.Length; i++)
		{
			Component[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren(type, true);
			foreach (Component val in componentsInChildren)
			{
				int count = dictionary.Count;
				methodInfo.Invoke(null, new object[1] { val });
				if (dictionary.Count > count)
				{
					num++;
				}
			}
		}
		Log.LogInfo((object)("TALK PATH: Server.Instance=" + ((AccessTools.TypeByName("Server") == null) ? "?" : ((AccessTools.Property(AccessTools.TypeByName("Server"), "Instance") == null) ? "?" : (((Object)/*isinst with value type is only supported in some contexts*/ == (Object)null) ? "MISSING" : "ok"))) + "   NPCManager.Instance=" + (((Object)/*isinst with value type is only supported in some contexts*/ == (Object)null) ? "MISSING" : "ok") + "   register holds " + dictionary.Count + " NPC(s)"));
		FieldInfo fieldInfo2 = AccessTools.Field(type, "_id");
		FieldInfo fieldInfo3 = AccessTools.Field(type, "_quests");
		rootGameObjects = ((Scene)(ref ours)).GetRootGameObjects();
		for (int i = 0; i < rootGameObjects.Length; i++)
		{
			Component[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren(type, true);
			foreach (Component val2 in componentsInChildren)
			{
				object obj = ((fieldInfo2 != null) ? fieldInfo2.GetValue(val2) : null);
				object obj2 = ((obj != null && dictionary.Contains(obj)) ? dictionary[obj] : null);
				ICollection collection = ((fieldInfo3 != null) ? (fieldInfo3.GetValue(val2) as ICollection) : null);
				Log.LogInfo((object)("   " + ((Object)val2).name + "  id=" + obj?.ToString() + "  registered=" + ((obj2 == null) ? "NO" : ((obj2 == val2) ? "yes, this one" : ("SOMEONE ELSE (" + ((Object)(Component)obj2).name + ")"))) + "  quests=" + ((collection == null) ? "null" : collection.Count.ToString()) + "  enabled=" + ((Behaviour)val2).enabled + "  active=" + val2.gameObject.activeInHierarchy));
			}
		}
		if (list.Count > 0 || num > 0)
		{
			Log.LogInfo((object)("NPC register: cleared " + list.Count + " dead entr(ies) and put " + num + " of the map's NPCs in. Without this they show their name but will not talk."));
		}
	}

	private IEnumerator RegisterAgainOnceTheServerIsUp(Scene ours)
	{
		//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)
		Type type = AccessTools.TypeByName("NPCManager");
		if (type == null)
		{
			yield break;
		}
		FieldInfo instanceField = AccessTools.Field(type, "Instance");
		MethodInfo isServer = AccessTools.PropertyGetter(type, "IsServerInitialized");
		if (instanceField == null || isServer == null)
		{
			yield break;
		}
		bool registeredHere = false;
		for (float waited = 0f; waited < 20f; waited += 0.5f)
		{
			object? value = instanceField.GetValue(null);
			Object val = (Object)((value is Object) ? value : null);
			if (val != (Object)null)
			{
				bool flag = false;
				try
				{
					flag = (bool)isServer.Invoke(val, null);
				}
				catch
				{
				}
				if (flag)
				{
					RegisterTheNpcsProperly(ours);
					ReArmTheTalkEvent(ours);
					Log.LogInfo((object)"Registered the map's NPCs again now the server is up - that is what gives them their quest index, and without it they will not talk.");
					yield break;
				}
				if (!registeredHere && waited >= 0.5f)
				{
					registeredHere = true;
					RegisterTheNpcsProperly(ours);
					ReArmTheTalkEvent(ours);
					Log.LogInfo((object)"Not the server: the map's NPCs registered on this side, so sales and speech from the host find them here.");
				}
			}
			yield return (object)new WaitForSeconds(0.5f);
		}
		if (!registeredHere)
		{
			Log.LogWarning((object)"NPCManager never appeared, so the NPCs may not talk.");
		}
	}

	private static void ReArmTheTalkEvent(Scene ours)
	{
		Type type = AccessTools.TypeByName("NPC");
		Type type2 = AccessTools.TypeByName("Interactable");
		if (type == null || type2 == null)
		{
			return;
		}
		FieldInfo fieldInfo = AccessTools.Field(type2, "OnInteract");
		MethodInfo methodInfo = AccessTools.Method(type, "Awake", (Type[])null, (Type[])null);
		FieldInfo fieldInfo2 = AccessTools.Field(type, "_characterInteractable");
		if (fieldInfo == null || methodInfo == null)
		{
			return;
		}
		int num = 0;
		int num2 = 0;
		GameObject[] rootGameObjects = ((Scene)(ref ours)).GetRootGameObjects();
		for (int i = 0; i < rootGameObjects.Length; i++)
		{
			Component[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren(type, true);
			foreach (Component val in componentsInChildren)
			{
				Component val2 = (Component)((fieldInfo2 != null) ? /*isinst with value type is only supported in some contexts*/: null);
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = val.GetComponentInChildren(type2, true);
				}
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				if (((fieldInfo.GetValue(val2) is Delegate obj && obj.GetInvocationList().Length != 0) ? 1 : 0) > (false ? 1 : 0))
				{
					num2++;
					continue;
				}
				try
				{
					methodInfo.Invoke(val, null);
					num++;
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("Could not re-arm " + ((Object)val).name + ": " + ex.Message));
				}
			}
		}
		Log.LogInfo((object)("Talk event: " + num2 + " NPC(s) already wired, " + num + " re-armed. Nothing subscribed to the event is the difference between an NPC that shows a prompt and one that answers it."));
	}

	private static AsyncOperation BorrowIsland(int buildIndex)
	{
		string scenePathByBuildIndex = SceneUtility.GetScenePathByBuildIndex(buildIndex);
		if (!string.IsNullOrEmpty(scenePathByBuildIndex))
		{
			Borrowing.Add(scenePathByBuildIndex);
		}
		return SceneManager.LoadSceneAsync(buildIndex, (LoadSceneMode)1);
	}

	private static AsyncOperation BorrowIslandByPath(string path)
	{
		if (!string.IsNullOrEmpty(path))
		{
			Borrowing.Add(path);
		}
		return SceneManager.LoadSceneAsync(path, (LoadSceneMode)1);
	}

	private static void WakeTheMoved(GameObject moved)
	{
		if ((Object)(object)moved == (Object)null)
		{
			return;
		}
		int num = 0;
		MonoBehaviour[] componentsInChildren = moved.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null || !SkipBorrowedSingletons.Guarded.TryGetValue(((object)val).GetType(), out var value))
			{
				continue;
			}
			string[] array = new string[3] { "Awake", "OnEnable", "Start" };
			foreach (string text in array)
			{
				foreach (MethodInfo item in value)
				{
					if (item.Name == text)
					{
						try
						{
							item.Invoke(val, null);
							num++;
						}
						catch (Exception ex)
						{
							Log.LogWarning((object)(((object)val).GetType().Name + "." + text + " on the borrowed " + ((Object)((Component)val).gameObject).name + " threw: " + (ex.InnerException ?? ex).Message));
						}
					}
				}
			}
		}
		if (num > 0)
		{
			Log.LogInfo((object)(((Object)moved).name + " woken by hand after being lifted out of the borrowed island (" + num + " call(s))."));
		}
	}

	private IEnumerator FillFromTheGamesOwnIsland(Scene ours)
	{
		//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)
		if (!SlotOfScene.TryGetValue(((Scene)(ref ours)).path, out var slot) && !SlotOfScene.TryGetValue(FirstKeyFor(ours), out slot))
		{
			yield break;
		}
		string path = SceneUtility.GetScenePathByBuildIndex(slot + 1);
		AsyncOperation op = BorrowIsland(slot + 1);
		if (op == null && !string.IsNullOrEmpty(path))
		{
			Log.LogInfo((object)("Island " + slot + " would not open by build index; trying its path " + path + "."));
			op = BorrowIslandByPath(path);
		}
		if (op == null)
		{
			Log.LogWarning((object)("Could not open the game's island " + slot + " to read its data, so the map's lost references stay lost."));
			yield break;
		}
		while (!op.isDone)
		{
			yield return null;
		}
		Scene src = SceneManager.GetSceneByBuildIndex(slot + 1);
		if (!((Scene)(ref src)).IsValid() && !string.IsNullOrEmpty(path))
		{
			src = SceneManager.GetSceneByPath(path);
		}
		if (!((Scene)(ref src)).IsValid())
		{
			Log.LogWarning((object)("The game's island " + slot + " opened but could not be found afterwards, so the map's lost references stay lost."));
			yield break;
		}
		int filled = 0;
		int objects = 0;
		List<string> examples = new List<string>();
		try
		{
			Dictionary<string, GameObject> dictionary = new Dictionary<string, GameObject>();
			GameObject[] rootGameObjects = ((Scene)(ref src)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					string key = PathOf(val2);
					if (!dictionary.ContainsKey(key))
					{
						dictionary[key] = ((Component)val2).gameObject;
					}
				}
			}
			rootGameObjects = ((Scene)(ref ours)).GetRootGameObjects();
			foreach (GameObject val3 in rootGameObjects)
			{
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				MonoBehaviour[] componentsInChildren2 = val3.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val4 in componentsInChildren2)
				{
					if ((Object)(object)val4 == (Object)null)
					{
						continue;
					}
					Type type = ((object)val4).GetType();
					if (type.Assembly.GetName().Name != "Assembly-CSharp" || WasImported(((Component)val4).transform) || !dictionary.TryGetValue(PathOf(((Component)val4).transform), out var value))
					{
						continue;
					}
					Component[] components = ((Component)val4).GetComponents(type);
					Component[] components2 = value.GetComponents(type);
					int num = Array.IndexOf(components, (Component)(object)val4);
					if (num < 0 || num >= components2.Length)
					{
						continue;
					}
					Component theirs = components2[num];
					int num2 = filled;
					Type type2 = type;
					while (type2 != null && type2 != typeof(MonoBehaviour))
					{
						FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						foreach (FieldInfo f in fields)
						{
							try
							{
								filled += TakeTheGamesOwn(f, val4, theirs, examples);
							}
							catch (Exception)
							{
							}
						}
						type2 = type2.BaseType;
					}
					if (filled > num2)
					{
						objects++;
					}
				}
			}
		}
		catch (Exception ex2)
		{
			Log.LogWarning((object)("Could not fill the map's data from island " + slot + ": " + ex2.Message));
		}
		try
		{
			CompareAndTakeTheTwinsMaterials(src, ours, slot);
		}
		catch (Exception ex3)
		{
			Log.LogWarning((object)("Could not compare with the game's island: " + ex3.Message));
		}
		try
		{
			ReplaceWithTheGamesOwn(src, ours, slot);
		}
		catch (Exception ex4)
		{
			Log.LogWarning((object)("Could not swap in the game's own casino pieces: " + ex4.Message));
		}
		try
		{
			CloneWhatTheMapLost(src, ours, slot);
		}
		catch (Exception ex5)
		{
			Log.LogWarning((object)("Could not clone the map's lost objects: " + ex5.Message));
		}
		try
		{
			int num3 = SwapInGameMaterials(ours);
			if (num3 > 0)
			{
				Hooks.RecolourTheNpcs(ours, ((Scene)(ref ours)).name);
				Log.LogInfo((object)(num3 + " more material(s) swapped for the game's own now that island " + slot + " had them loaded - the sculpted ground included."));
			}
		}
		catch (Exception ex6)
		{
			Log.LogWarning((object)("Second material swap failed: " + ex6.Message));
		}
		foreach (object item in CloseTheBorrowedIsland(src, ours))
		{
			yield return item;
		}
		if (filled > 0)
		{
			Log.LogInfo((object)(filled + " reference(s) on " + objects + " object(s) now point at the game's own assets, read off island " + slot + " at the same paths. The map's copies could not load, so shops sold nothing, quests had no quest and spawners had no creature. E.g. " + string.Join(", ", examples.ToArray()) + "."));
		}
		else
		{
			Log.LogInfo((object)("Nothing to fill from island " + slot + " - the map's references were all the game's own already."));
		}
	}

	private static void CompareAndTakeTheTwinsMaterials(Scene src, Scene ours, int slot)
	{
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0233: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: 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_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: 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)
		//IL_025a: 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_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: 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_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02da: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0403: Unknown result type (might be due to invalid IL or missing references)
		//IL_0408: Unknown result type (might be due to invalid IL or missing references)
		//IL_0422: Unknown result type (might be due to invalid IL or missing references)
		//IL_0427: Unknown result type (might be due to invalid IL or missing references)
		//IL_042b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0430: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<string, Renderer> dictionary = new Dictionary<string, Renderer>();
		GameObject[] rootGameObjects = ((Scene)(ref src)).GetRootGameObjects();
		foreach (GameObject val in rootGameObjects)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				string key = PathOf(((Component)val2).transform);
				if (!dictionary.ContainsKey(key))
				{
					dictionary[key] = val2;
				}
			}
		}
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		List<string> list = new List<string>();
		rootGameObjects = ((Scene)(ref ours)).GetRootGameObjects();
		foreach (GameObject val3 in rootGameObjects)
		{
			if ((Object)(object)val3 == (Object)null)
			{
				continue;
			}
			Renderer[] componentsInChildren = val3.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val4 in componentsInChildren)
			{
				if ((Object)(object)val4 == (Object)null || WasImported(((Component)val4).transform) || !dictionary.TryGetValue(PathOf(((Component)val4).transform), out var value) || (Object)(object)value == (Object)null)
				{
					continue;
				}
				num++;
				bool flag = ((Object)val4).name.IndexOf("lava", StringComparison.OrdinalIgnoreCase) >= 0;
				List<string> list2 = new List<string>();
				if (((Component)val4).gameObject.layer != ((Component)value).gameObject.layer)
				{
					list2.Add("layer " + ((Component)val4).gameObject.layer + " vs " + ((Component)value).gameObject.layer);
				}
				if (val4.isPartOfStaticBatch != value.isPartOfStaticBatch)
				{
					list2.Add("staticBatch " + val4.isPartOfStaticBatch + " vs " + value.isPartOfStaticBatch);
				}
				if (val4.lightmapIndex != value.lightmapIndex)
				{
					list2.Add("lightmap " + val4.lightmapIndex + " vs " + value.lightmapIndex);
				}
				Bounds bounds = val4.bounds;
				Vector3 size = ((Bounds)(ref bounds)).size;
				bounds = value.bounds;
				Vector3 val5 = size - ((Bounds)(ref bounds)).size;
				if (((Vector3)(ref val5)).sqrMagnitude > 0.01f)
				{
					bounds = val4.bounds;
					val5 = ((Bounds)(ref bounds)).size;
					string text = ((Vector3)(ref val5)).ToString("0.0");
					bounds = value.bounds;
					val5 = ((Bounds)(ref bounds)).size;
					list2.Add("bounds " + text + " vs " + ((Vector3)(ref val5)).ToString("0.0"));
				}
				val5 = ((Component)val4).transform.lossyScale - ((Component)value).transform.lossyScale;
				if (((Vector3)(ref val5)).sqrMagnitude > 0.0001f)
				{
					val5 = ((Component)val4).transform.lossyScale;
					string text2 = ((Vector3)(ref val5)).ToString("0.00");
					val5 = ((Component)value).transform.lossyScale;
					list2.Add("scale " + text2 + " vs " + ((Vector3)(ref val5)).ToString("0.00"));
				}
				MeshFilter component = ((Component)val4).GetComponent<MeshFilter>();
				MeshFilter component2 = ((Component)value).GetComponent<MeshFilter>();
				if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && (Object)(object)component.sharedMesh != (Object)null && (Object)(object)component2.sharedMesh != (Object)null)
				{
					if (component.sharedMesh.vertexCount != component2.sharedMesh.vertexCount)
					{
						list2.Add("verts " + component.sharedMesh.vertexCount + " vs " + component2.sharedMesh.vertexCount);
					}
					bounds = component.sharedMesh.bounds;
					Vector3 size2 = ((Bounds)(ref bounds)).size;
					bounds = component2.sharedMesh.bounds;
					if (size2 != ((Bounds)(ref bounds)).size)
					{
						bounds = component.sharedMesh.bounds;
						val5 = ((Bounds)(ref bounds)).size;
						string text3 = ((Vector3)(ref val5)).ToString("0.00");
						bounds = component2.sharedMesh.bounds;
						val5 = ((Bounds)(ref bounds)).size;
						list2.Add("meshBounds " + text3 + " vs " + ((Vector3)(ref val5)).ToString("0.00"));
					}
				}
				Material[] sharedMaterials = val4.sharedMaterials;
				Material[] sharedMaterials2 = value.sharedMaterials;
				if (sharedMaterials.Length != sharedMaterials2.Length)
				{
					list2.Add("materialCount " + sharedMaterials.Length + " vs " + sharedMaterials2.Length);
				}
				bool flag2 = sharedMaterials2.Length != 0;
				for (int k = 0; k < sharedMaterials2.Length; k++)
				{
					if ((Object)(object)sharedMaterials2[k] == (Object)null || (Object)(object)sharedMaterials2[k].shader == (Object)null)
					{
						flag2 = false;
						break;
					}
				}
				for (int l = 0; l < Math.Min(sharedMaterials.Length, sharedMaterials2.Length); l++)
				{
					if ((Object)(object)sharedMaterials[l] == (Object)(object)sharedMaterials2[l])
					{
						continue;
					}
					list2.Add("mat" + l + " " + (((Object)(object)sharedMaterials[l] != (Object)null) ? (((Object)sharedMaterials[l]).name + "[" + (((Object)(object)sharedMaterials[l].shader != (Object)null) ? ((Object)sharedMaterials[l].shader).name : "-") + "]") : "null") + " vs " + (((Object)(object)sharedMaterials2[l] != (Object)null) ? (((Object)sharedMaterials2[l]).name + "[" + (((Object)(object)sharedMaterials2[l].shader != (Object)null) ? ((Object)sharedMaterials2[l].shader).name : "-") + "]") : "null"));
					if (!flag || !((Object)(object)sharedMaterials2[l] != (Object)null))
					{
						continue;
					}
					string[] array = new string[5] { "_Vertex_Height", "_Vertex_Speed", "_Vertex_Noise_Scale", "_Noise_Scale", "_Pixelate" };
					foreach (string text4 in array)
					{
						if (sharedMaterials2[l].HasProperty(text4))
						{
							list2.Add("twin." + text4.Substring(1) + "=" + sharedMaterials2[l].GetFloat(text4).ToString("0.###"));
						}
					}
				}
				if (flag2 && (sharedMaterials.Length != sharedMaterials2.Length || AnyDifferent(sharedMaterials, sharedMaterials2)))
				{
					val4.sharedMaterials = sharedMaterials2;
					num3++;
				}
				if (list2.Count > 0)
				{
					num2++;
					if (flag || list.Count < 12)
					{
						list.Add(((Object)val4).name + ": " + string.Join(", ", list2.ToArray()));
					}
				}
			}
		}
		Log.LogInfo((object)("Twin check against island " + slot + ": " + num + " renderer(s) compared, " + num2 + " drawn differently, " + num3 + " given the game's own materials outright." + ((list.Count > 0) ? (" Differences: " + string.Join(" | ", list.ToArray())) : "")));
	}

	private static bool AnyDifferent(Material[] a, Material[] b)
	{
		for (int i = 0; i < a.Length; i++)
		{
			if ((Object)(object)a[i] != (Object)(object)b[i])
			{
				return true;
			}
		}
		return false;
	}

	private static string KeyOf(Transform group, Transform anchor)
	{
		List<string> list = new List<string>();
		Transform val = anchor;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)group)
		{
			list.Insert(0, ((Object)val).name);
			val = val.parent;
		}
		list.Insert(0, ((Object)group).name);
		return string.Join("/", list.ToArray());
	}

	private static Transform AnchorOf(Transform group, string name)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		if ((Object)(object)group == (Object)null || !Anchors.TryGetValue(name, out var value) || string.IsNullOrEmpty(value))
		{
			return null;
		}
		foreach (Transform item in group)
		{
			Transform val = item;
			if (((Object)val).name == value)
			{
				return val;
			}
		}
		Transform[] componentsInChildren = ((Component)group).GetComponentsInChildren<Transform>(true);
		foreach (Transform val2 in componentsInChildren)
		{
			if ((Object)(object)val2 != (Object)(object)group && ((Object)val2).name == value)
			{
				return val2;
			}
		}
		return null;
	}

	private static void AlignByAnchor(Transform group, string name, bool haveGame, Vector3 gamePos, Quaternion gameRot)
	{
		//IL_0118: 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_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: 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)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: 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_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: 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_009f: 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_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_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		if (!Anchors.TryGetValue(name, out var value) || string.IsNullOrEmpty(value))
		{
			return;
		}
		Transform val = AnchorOf(group, name);
		string text = (((Object)(object)val != (Object)null) ? KeyOf(group, val) : (name + "/" + value));
		if ((Object)(object)val == (Object)null || !MapPlacement.TryGetValue(text, out var value2))
		{
			if (haveGame)
			{
				Transform val2 = AnchorOf(group, name);
				if ((Object)(object)val2 != (Object)null)
				{
					Quaternion val3 = Quaternion.Inverse(group.rotation) * val2.rotation;
					group.rotation = gameRot * Quaternion.Inverse(val3);
					group.position += gamePos - val2.position;
				}
			}
			Log.LogWarning((object)("Could not line up " + name + " with the map's " + value + " (" + (((Object)(object)val == (Object)null) ? "the game's group has none" : ("the map's copy had none at " + text)) + "); it stands where the game puts it."));
		}
		else
		{
			Quaternion val4 = Quaternion.Inverse(group.rotation) * val.rotation;
			group.rotation = value2.rot * Quaternion.Inverse(val4);
			group.position += value2.pos - val.position;
			ManualLogSource log = Log;
			string[] obj = new string[13]
			{
				"   ",
				name,
				" placed by its ",
				value,
				": the game had it at ",
				haveGame ? ((Vector3)(ref gamePos)).ToString("0.0") : "?",
				", the map's ",
				value,
				" at ",
				((Vector3)(ref value2.pos)).ToString("0.0"),
				", now at ",
				null,
				null
			};
			Vector3 position = val.position;
			obj[11] = ((Vector3)(ref position)).ToString("0.0");
			obj[12] = ".";
			log.LogInfo((object)string.Concat(obj));
		}
	}

	private static int KeepTheMapsMeshesWhereTheGamesAreBatched(Transform mine, Transform theirs)
	{
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)mine == (Object)null || (Object)(object)theirs == (Object)null)
		{
			return 0;
		}
		Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>();
		Transform[] componentsInChildren = ((Component)mine).GetComponentsInChildren<Transform>(true);
		foreach (Transform val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)(object)mine)
			{
				dictionary[RelativePath(mine, val)] = val;
			}
		}
		List<KeyValuePair<Transform, Transform>> list = new List<KeyValuePair<Transform, Transform>>();
		MeshRenderer[] componentsInChildren2 = ((Component)theirs).GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val2 in componentsInChildren2)
		{
			if (!((Object)(object)val2 == (Object)null) && ((Renderer)val2).isPartOfStaticBatch && !((Object)(object)((Component)val2).transform == (Object)(object)theirs) && dictionary.TryGetValue(RelativePath(theirs, ((Component)val2).transform), out var value) && !((Object)(object)((Component)value).GetComponent<MeshRenderer>() == (Object)null))
			{
				list.Add(new KeyValuePair<Transform, Transform>(((Component)val2).transform, value));
			}
		}
		int num = 0;
		foreach (KeyValuePair<Transform, Transform> item in list)
		{
			Transform key = item.Key;
			Transform value2 = item.Value;
			if (!((Object)(object)key == (Object)null) && !((Object)(object)value2 == (Object)null))
			{
				Transform parent = key.parent;
				int siblingIndex = key.GetSiblingIndex();
				Vector3 localPosition = key.localPosition;
				Quaternion localRotation = key.localRotation;
				Vector3 localScale = key.localScale;
				((Component)key).gameObject.SetActive(false);
				value2.SetParent(parent, false);
				value2.localPosition = localPosition;
				value2.localRotation = localRotation;
				value2.localScale = localScale;
				value2.SetSiblingIndex(siblingIndex);
				num++;
			}
		}
		return num;
	}

	private static void SettleTheTableRoot(Transform group, string name)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Expected O, but got Unknown
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result