Decompiled source of BiomePicker v0.2.1

plugins/Tobeyyy.BiomePicker.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BiomePicker.Dev;
using BiomePicker.Game;
using BiomePicker.UI;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Profiling;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.UI.ProceduralImage;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Tobeyyy.BiomePicker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.1.0")]
[assembly: AssemblyInformationalVersion("0.2.1+a3b4504a56432d23da4826c484c7e842476a04af")]
[assembly: AssemblyProduct("Tobeyyy.BiomePicker")]
[assembly: AssemblyTitle("BiomePicker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace BiomePicker
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("Tobeyyy.BiomePicker", "BiomePicker", "0.2.1")]
	public class Plugin : BaseUnityPlugin
	{
		internal static bool DevMode;

		internal static ConfigEntry<bool> AutoTest;

		internal static ConfigEntry<int> AutoTestLevel;

		internal static ConfigEntry<string> AutoTestLab;

		internal static ConfigEntry<bool> AutoTestQuit;

		internal static ConfigEntry<int> DonorLevel;

		internal static ConfigEntry<string> DevPlan;

		internal static ConfigEntry<bool> DevHotkeys;

		internal static ConfigEntry<bool> DevPlayKit;

		internal static ConfigEntry<bool> DevNadirKit;

		internal static ConfigEntry<bool> DevParity;

		internal static ConfigEntry<bool> DevShots;

		internal static ConfigEntry<bool> DevFast;

		internal static ConfigEntry<string> Plan;

		internal static string ConflictingPlugin;

		private static readonly string[] Conflicts = new string[6] { "PLL", "AllBiomes", "TrueFinalAscent", "TerrainRandomiser", "TerrainCustomiser", "PeakWorkshop" };

		public const string Id = "Tobeyyy.BiomePicker";

		internal static ManualLogSource Log { get; private set; } = null;

		internal static Plugin Instance { get; private set; }

		internal static Harmony Harmony { get; private set; }

		internal static string OutputFolder => Path.Combine(Paths.BepInExRootPath, "BiomePicker");

		public static string Name => "BiomePicker";

		public static string Version => "0.2.1";

		private void Awake()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Plan = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Plan", "", "The biomes of a run and their order, as picked at the boarding pass (empty = every installed biome in a row). In multiplayer the host's plan counts.");
			string text = Path.Combine(Paths.ConfigPath, "Tobeyyy.BiomePicker.Dev.cfg");
			DevMode = File.Exists(text);
			ConfigFile val = new ConfigFile(text, false, ((BaseUnityPlugin)this).Info.Metadata)
			{
				SaveOnConfigSet = DevMode
			};
			AutoTest = val.Bind<bool>("Dev", "AutoTest", false, "Drive the game from the main menu into a solo run on Level_<AutoTestLevel> and run the lab named in AutoTestLab.");
			AutoTestLevel = val.Bind<int>("Dev", "AutoTestLevel", 17, "Today's island for the auto-test (Level_N, 0..207 in PEAK 3.0).");
			AutoTestLab = val.Bind<string>("Dev", "AutoTestLab", "donor", "'donor' = load a second island inert, copy its slot-2 variant into today's island and play it (dumps, shots).");
			AutoTestQuit = val.Bind<bool>("Dev", "AutoTestQuit", true, "Quit the game when the auto-test is done.");
			DonorLevel = val.Bind<int>("Dev", "DonorLevel", -1, "Island to copy biomes from in the donor lab (-1 = the one most different from today's).");
			DevPlan = val.Bind<string>("Dev", "Plan", "", "Overrides General.Plan for the auto-tests (empty = General.Plan).");
			DevHotkeys = val.Bind<bool>("Dev", "Hotkeys", false, "F6: warp the local scout to the next campfire (the current round's end; on a last Kiln/Citadel its summit).");
			DevPlayKit = val.Bind<bool>("Dev", "PlayKit", false, "On every island: Lost City's playtest kit (jetpack, lantern, food, chain launcher; needs Lost City with its developer config).");
			DevParity = val.Bind<bool>("Dev", "Parity", true, "Auto-tests: measure every biome against vanilla (Parity.Sample: sky, sounds, hazards, pictures; ~9 s a round).");
			DevShots = val.Bind<bool>("Dev", "Shots", true, "Auto-tests: save the pictures (Shots.Shot); off, only what a check measures is rendered.");
			DevFast = val.Bind<bool>("Dev", "Fast", false, "Auto-tests: the campfire switch at 3x game speed, the fog switched fully on at once, shorter settling waits.");
			DevNadirKit = val.Bind<bool>("Dev", "NadirKit", false, "On every island: a backpack holding the same amulet four times on the back (instead of PlayKit's jetpack), for the way to the Nadir.");
			foreach (PluginInfo value2 in Chainloader.PluginInfos.Values)
			{
				string text2 = value2.Metadata.GUID + " " + value2.Metadata.Name;
				string[] conflicts = Conflicts;
				foreach (string value in conflicts)
				{
					if (text2.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0 && value2.Metadata.GUID != "Tobeyyy.BiomePicker")
					{
						ConflictingPlugin = value2.Metadata.Name;
					}
				}
			}
			Harmony = new Harmony("Tobeyyy.BiomePicker");
			Harmony.PatchAll(typeof(Plugin).Assembly);
			CustomBiomes.Register(new LostCityBiome(Harmony));
			CustomBiomes.Register(new SakuraBiome(Harmony));
			((Component)this).gameObject.AddComponent<RunDirector>();
			if (DevMode && (DevHotkeys.Value || DevPlayKit.Value || DevNadirKit.Value))
			{
				((Component)this).gameObject.AddComponent<DevKeys>();
			}
			if (DevMode && AutoTest.Value)
			{
				((Component)this).gameObject.AddComponent<AutoTestDriver>();
				if (AutoTestLab.Value != "airport")
				{
					DestroyTrap.Install(Harmony);
				}
			}
			Log.LogInfo((object)("Plugin " + Name + " " + Version + " loaded" + ((ConflictingPlugin != null) ? (" (inactive: " + ConflictingPlugin + " present)") : "") + (DevMode ? " (developer config found)" : "") + "."));
		}
	}
}
namespace BiomePicker.UI
{
	internal sealed class Fade : MonoBehaviour
	{
		private static Fade _instance;

		private CanvasGroup _group;

		private static Fade Get()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0081: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_instance != (Object)null)
			{
				return _instance;
			}
			GameObject val = new GameObject("BiomePicker Fade");
			Object.DontDestroyOnLoad((Object)(object)val);
			Canvas val2 = val.AddComponent<Canvas>();
			val2.renderMode = (RenderMode)0;
			val2.sortingOrder = 30000;
			_instance = val.AddComponent<Fade>();
			_instance._group = val.AddComponent<CanvasGroup>();
			_instance._group.alpha = 0f;
			_instance._group.blocksRaycasts = false;
			Image val3 = new GameObject("Black").AddComponent<Image>();
			((Component)val3).transform.SetParent(val.transform, false);
			((Graphic)val3).color = Color.black;
			((Graphic)val3).raycastTarget = false;
			RectTransform rectTransform = ((Graphic)val3).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = Vector2.zero;
			rectTransform.offsetMax = Vector2.zero;
			return _instance;
		}

		public static IEnumerator To(float alpha, float seconds)
		{
			Fade f = Get();
			float from = f._group.alpha;
			for (float t = 0f; t < seconds; t += Time.unscaledDeltaTime)
			{
				f._group.alpha = Mathf.Lerp(from, alpha, t / seconds);
				yield return null;
			}
			f._group.alpha = alpha;
		}

		public static void Clear()
		{
			if ((Object)(object)_instance != (Object)null)
			{
				_instance._group.alpha = 0f;
			}
		}
	}
	internal sealed class LoadBar : MonoBehaviour
	{
		private static LoadBar _instance;

		private CanvasGroup _group;

		private RectTransform _fill;

		private TextMeshProUGUI _label;

		private float _shown;

		public static void Show()
		{
			if ((Object)(object)_instance == (Object)null)
			{
				Build();
			}
			_instance._shown = 0f;
			_instance._group.alpha = 1f;
			((Behaviour)_instance).enabled = true;
		}

		private static void Build()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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_0144: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Expected O, but got Unknown
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Expected O, but got Unknown
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("BiomePicker LoadBar");
			Object.DontDestroyOnLoad((Object)(object)val);
			Canvas val2 = val.AddComponent<Canvas>();
			val2.renderMode = (RenderMode)0;
			val2.sortingOrder = 29000;
			CanvasScaler val3 = val.AddComponent<CanvasScaler>();
			val3.uiScaleMode = (ScaleMode)1;
			val3.referenceResolution = new Vector2(1920f, 1080f);
			val3.matchWidthOrHeight = 0.5f;
			_instance = val.AddComponent<LoadBar>();
			_instance._group = val.AddComponent<CanvasGroup>();
			_instance._group.blocksRaycasts = false;
			GameObject val4 = new GameObject("Frame", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(val.transform, false);
			RectTransform val5 = (RectTransform)val4.transform;
			Vector2 val6 = default(Vector2);
			((Vector2)(ref val6))..ctor(0.5f, 0f);
			val5.anchorMax = val6;
			val5.anchorMin = val6;
			val5.pivot = new Vector2(0.5f, 0f);
			val5.anchoredPosition = new Vector2(0f, 70f);
			val5.sizeDelta = new Vector2(720f, 64f);
			GameObject val7 = new GameObject("Track", new Type[1] { typeof(RectTransform) });
			val7.transform.SetParent(val4.transform, false);
			RectTransform val8 = (RectTransform)val7.transform;
			val8.anchorMin = new Vector2(0f, 0f);
			val8.anchorMax = new Vector2(1f, 0f);
			val8.pivot = new Vector2(0.5f, 0f);
			val8.sizeDelta = new Vector2(0f, 12f);
			Rounded(val7, new Color(0f, 0f, 0f, 0.45f), 6f);
			GameObject val9 = new GameObject("Fill", new Type[1] { typeof(RectTransform) });
			val9.transform.SetParent(val7.transform, false);
			_instance._fill = (RectTransform)val9.transform;
			_instance._fill.anchorMin = Vector2.zero;
			_instance._fill.anchorMax = new Vector2(0f, 1f);
			_instance._fill.pivot = new Vector2(0f, 0.5f);
			val6 = (_instance._fill.offsetMin = (_instance._fill.offsetMax = Vector2.zero));
			Rounded(val9, new Color(0.98f, 0.92f, 0.78f, 0.95f), 6f);
			GameObject val11 = new GameObject("Label", new Type[1] { typeof(RectTransform) });
			val11.transform.SetParent(val4.transform, false);
			RectTransform val12 = (RectTransform)val11.transform;
			val12.anchorMin = new Vector2(0f, 0f);
			val12.anchorMax = new Vector2(1f, 1f);
			val12.offsetMin = new Vector2(0f, 20f);
			val12.offsetMax = Vector2.zero;
			_instance._label = val11.AddComponent<TextMeshProUGUI>();
			TMP_FontAsset val13 = GameFont();
			if ((Object)(object)val13 != (Object)null)
			{
				((TMP_Text)_instance._label).font = val13;
			}
			((TMP_Text)_instance._label).fontSize = 26f;
			((Graphic)_instance._label).color = new Color(0.98f, 0.95f, 0.88f, 1f);
			((TMP_Text)_instance._label).alignment = (TextAlignmentOptions)1026;
			((TMP_Text)_instance._label).textWrappingMode = (TextWrappingModes)0;
			((Graphic)_instance._label).raycastTarget = false;
		}

		private static TMP_FontAsset GameFont()
		{
			TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
			foreach (TMP_Text val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.font != (Object)null && ((Object)val.font).name.IndexOf("LiberationSans", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return val.font;
				}
			}
			return null;
		}

		private static void Rounded(GameObject go, Color color, float radius)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			ProceduralImage val = go.AddComponent<ProceduralImage>();
			val.ModifierType = typeof(UniformModifier);
			UniformModifier component = go.GetComponent<UniformModifier>();
			if ((Object)(object)component != (Object)null)
			{
				component.Radius = radius;
			}
			((Graphic)val).color = color;
			((Graphic)val).raycastTarget = false;
		}

		private void Update()
		{
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			if (!LoadProgress.Shown)
			{
				_shown = Mathf.MoveTowards(_shown, 1f, Time.unscaledDeltaTime * 2f);
				_group.alpha = Mathf.MoveTowards(_group.alpha, 0f, Time.unscaledDeltaTime * 1.5f);
				if (_group.alpha <= 0f)
				{
					((Behaviour)this).enabled = false;
				}
			}
			else
			{
				float value = LoadProgress.Value;
				if (value > _shown)
				{
					_shown = Mathf.Min(value, _shown + Mathf.Max(0.02f, (value - _shown) * 4f) * Time.unscaledDeltaTime);
				}
				((TMP_Text)_label).text = $"{LoadProgress.Label}  {Mathf.FloorToInt(_shown * 100f)}%";
			}
			_fill.anchorMax = new Vector2(Mathf.Clamp01(_shown), 1f);
		}
	}
	[HarmonyPatch]
	internal sealed class PickerPanel : MonoBehaviour
	{
		private static readonly Color Paper = new Color(0.12f, 0.11f, 0.1f, 0.93f);

		private static readonly Color RowOn = new Color(0.22f, 0.2f, 0.17f, 0.95f);

		private static readonly Color RowOff = new Color(0.16f, 0.15f, 0.13f, 0.85f);

		private static readonly Color Ink = new Color(0.97f, 0.93f, 0.84f, 1f);

		private static readonly Color Faint = new Color(0.97f, 0.93f, 0.84f, 0.45f);

		private static readonly Color Accent = new Color(0.98f, 0.7f, 0.27f, 1f);

		private BoardingPass _pass;

		private TMP_FontAsset _font;

		private Material _fontMat;

		private Sprite _arrow;

		private RectTransform _rows;

		private TextMeshProUGUI _sub;

		private GameObject _footer;

		private RunPlan _plan;

		private string _shown;

		private float _nextPoll;

		private const float Width = 400f;

		private const float Margin = 14f;

		private const float Padding = 22f;

		private const float RowWidth = 356f;

		private const float ColumnGap = 12f;

		private GridLayoutGroup _grid;

		private int _columns = 1;

		private int _units;

		private static bool Host
		{
			get
			{
				if (PhotonNetwork.InRoom)
				{
					return PhotonNetwork.IsMasterClient;
				}
				return true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(BoardingPass), "Initialize")]
		private static void AfterInitialize(BoardingPass __instance)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			if ((Object)(object)((Component)__instance).GetComponentInChildren<PickerPanel>(true) != (Object)null)
			{
				return;
			}
			GameObject val = new GameObject("BiomePicker Panel", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(((Component)__instance).transform, false);
			try
			{
				val.AddComponent<PickerPanel>().Build(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("BiomePicker panel failed: " + ex));
				Object.Destroy((Object)(object)val);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(BoardingPass), "OnOpen")]
		private static void AfterOpen(BoardingPass __instance)
		{
			PickerPanel componentInChildren = ((Component)__instance).GetComponentInChildren<PickerPanel>(true);
			try
			{
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.Refresh(force: true);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("BiomePicker panel refresh failed: " + ex));
			}
		}

		private void Build(BoardingPass pass)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00c0: 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)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Expected O, but got Unknown
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Expected O, but got Unknown
			_pass = pass;
			_font = pass.ascentTitle.font;
			_fontMat = pass.ascentTitle.fontSharedMaterial;
			Image val = ((Component)pass.incrementAscentButton).GetComponentInChildren<Image>(true);
			Image[] componentsInChildren = ((Component)pass.incrementAscentButton).GetComponentsInChildren<Image>(true);
			foreach (Image val2 in componentsInChildren)
			{
				if ((Object)(object)val2.sprite != (Object)null && (Object)(object)((Component)val2).gameObject != (Object)(object)((Component)pass.incrementAscentButton).gameObject)
				{
					val = val2;
				}
			}
			_arrow = (((Object)(object)val != (Object)null) ? val.sprite : null);
			RectTransform val3 = (RectTransform)((Component)this).transform;
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor(1f, 0.5f);
			val3.anchorMax = val4;
			val3.anchorMin = val4;
			val3.pivot = new Vector2(1f, 0.5f);
			val3.anchoredPosition = new Vector2(-14f, 0f);
			val3.sizeDelta = new Vector2(400f, 0f);
			Rounded(((Component)this).gameObject, Paper, 22f);
			VerticalLayoutGroup val5 = ((Component)this).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)val5).padding = new RectOffset(22, 22, 20, 20);
			((HorizontalOrVerticalLayoutGroup)val5).spacing = 6f;
			bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)val5).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)val5).childControlWidth = childControlWidth;
			((HorizontalOrVerticalLayoutGroup)val5).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)val5).childForceExpandHeight = false;
			((Component)this).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			Text(((Component)this).transform, "BIOMES", 38f, Ink, (TextAlignmentOptions)513, 46f);
			_sub = Text(((Component)this).transform, "", 18f, Faint, (TextAlignmentOptions)513, 46f);
			((TMP_Text)_sub).textWrappingMode = (TextWrappingModes)1;
			GameObject val6 = new GameObject("Rows", new Type[1] { typeof(RectTransform) });
			val6.transform.SetParent(((Component)this).transform, false);
			_rows = (RectTransform)val6.transform;
			_grid = val6.AddComponent<GridLayoutGroup>();
			_grid.cellSize = new Vector2(356f, 42f);
			_grid.spacing = new Vector2(12f, 4f);
			_grid.startAxis = (Axis)1;
			_grid.constraint = (Constraint)2;
			_footer = new GameObject("Footer", new Type[1] { typeof(RectTransform) });
			_footer.transform.SetParent(((Component)this).transform, false);
			HorizontalLayoutGroup val7 = _footer.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)val7).spacing = 8f;
			childControlWidth = (((HorizontalOrVerticalLayoutGroup)val7).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)val7).childControlWidth = childControlWidth;
			((HorizontalOrVerticalLayoutGroup)val7).childForceExpandWidth = false;
			_footer.AddComponent<LayoutElement>().preferredHeight = 40f;
			Pill(_footer.transform, "ALL IN A ROW", delegate
			{
				Change(RunPlan.Default());
			});
			Refresh(force: true);
		}

		private void LateUpdate()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: 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_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: 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_01ca: 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_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: 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)
			if ((Object)(object)_pass == (Object)null || (Object)(object)_pass.startGameButton == (Object)null || (Object)(object)_rows == (Object)null)
			{
				return;
			}
			RectTransform val = (RectTransform)((Component)this).transform;
			RectTransform val2 = (RectTransform)((Transform)val).parent;
			Rect rect = val2.rect;
			Rect val3 = PassRect(_pass, val2);
			int units = _units;
			if (units != 0)
			{
				float num = LayoutUtility.GetPreferredHeight(val) - LayoutUtility.GetPreferredHeight(_rows);
				float num2 = num + HeightFor(units, 1);
				float num3 = Mathf.Min(new float[3]
				{
					(((Rect)(ref rect)).xMax - ((Rect)(ref val3)).xMax - 28f) / 400f,
					(((Rect)(ref rect)).height - 28f) / num2,
					1f
				});
				int num4 = ((units > 8) ? 3 : 2);
				float num5 = (float)num4 * 356f + (float)(num4 - 1) * 12f + 44f;
				float num6 = num + HeightFor(units, num4);
				float num7 = Mathf.Min(new float[3]
				{
					(((Rect)(ref rect)).yMax - ((Rect)(ref val3)).yMax - 28f) / num6,
					(((Rect)(ref rect)).width - 28f) / num5,
					1f
				});
				bool flag = ((_columns > 1) ? (num7 > num3 - 0.05f) : (num7 > num3 + 0.05f));
				int num8 = ((!flag) ? 1 : num4);
				if (num8 != _columns)
				{
					_columns = num8;
					ApplyColumns();
				}
				float num9 = Mathf.Max(flag ? num7 : num3, 0.3f);
				Vector2 val4 = default(Vector2);
				if (flag)
				{
					((Vector2)(ref val4))..ctor(0.5f, 1f);
					val.anchorMax = val4;
					val.anchorMin = val4;
					val.pivot = new Vector2(0.5f, 1f);
					val.sizeDelta = new Vector2(num5, 0f);
					float num10 = ((Rect)(ref rect)).yMax - ((Rect)(ref val3)).yMax;
					val.anchoredPosition = new Vector2(((Rect)(ref val3)).center.x - ((Rect)(ref rect)).center.x, 0f - Mathf.Max(14f, (num10 - num6 * num9) / 2f));
				}
				else
				{
					((Vector2)(ref val4))..ctor(1f, 0.5f);
					val.anchorMax = val4;
					val.anchorMin = val4;
					val.pivot = new Vector2(1f, 0.5f);
					val.sizeDelta = new Vector2(400f, 0f);
					val.anchoredPosition = new Vector2(-14f, 0f);
				}
				((Transform)val).localScale = new Vector3(num9, num9, 1f);
			}
		}

		private float HeightFor(int units, int columns)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.CeilToInt((float)units / (float)columns);
			return (float)num * _grid.cellSize.y + (float)(num - 1) * _grid.spacing.y;
		}

		private void ApplyColumns()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			_grid.constraintCount = Mathf.Max(1, Mathf.CeilToInt((float)_units / (float)_columns));
			LayoutRebuilder.MarkLayoutForRebuild((RectTransform)((Component)this).transform);
		}

		internal static Rect PassRect(BoardingPass pass, RectTransform space)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//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_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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			Rect result = Bounds((RectTransform)((Component)pass.startGameButton).transform, space);
			Rect rect = space.rect;
			float num = ((Rect)(ref rect)).height * 0.9f;
			Transform parent = ((Component)pass.startGameButton).transform.parent;
			while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)((Component)pass).transform)
			{
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				if (val != null && !((Object)(object)((Component)parent).GetComponent<PickerPanel>() != (Object)null))
				{
					Rect val2 = Bounds(val, space);
					if (((Rect)(ref val2)).height < num)
					{
						float width = ((Rect)(ref val2)).width;
						rect = space.rect;
						if (width < ((Rect)(ref rect)).width && ((Rect)(ref val2)).width * ((Rect)(ref val2)).height > ((Rect)(ref result)).width * ((Rect)(ref result)).height)
						{
							result = val2;
						}
					}
				}
				parent = parent.parent;
			}
			return result;
		}

		private static Rect Bounds(RectTransform rt, RectTransform space)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			rt.GetWorldCorners(array);
			Vector3 val = ((Transform)space).InverseTransformPoint(array[0]);
			Vector3 val2 = ((Transform)space).InverseTransformPoint(array[2]);
			return Rect.MinMaxRect(Mathf.Min(val.x, val2.x), Mathf.Min(val.y, val2.y), Mathf.Max(val.x, val2.x), Mathf.Max(val.y, val2.y));
		}

		private void Update()
		{
			if (Time.unscaledTime < _nextPoll)
			{
				return;
			}
			_nextPoll = Time.unscaledTime + 0.5f;
			try
			{
				Refresh(force: false);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("BiomePicker panel refresh failed: " + ex));
				((Behaviour)this).enabled = false;
			}
		}

		private void Refresh(bool force)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			RunPlan runPlan = (Host ? PlanSync.Local : (PlanSync.Room ?? null));
			string text = (Host ? "h:" : "c:") + ((runPlan != null) ? runPlan.Serialize() : "-");
			if (!force && text == _shown)
			{
				return;
			}
			_shown = text;
			_plan = runPlan;
			foreach (Transform item in (Transform)_rows)
			{
				Transform val = item;
				((Component)val).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			_units = 0;
			_footer.SetActive(Host);
			if (runPlan == null)
			{
				((TMP_Text)_sub).text = "The host doesn't have BiomePicker: a normal run.";
				return;
			}
			int num = 0;
			BiomeEntry biomeEntry = null;
			foreach (BiomeEntry item2 in runPlan.Played)
			{
				if (item2.Id != "peak")
				{
					num++;
					biomeEntry = item2;
				}
			}
			string arg = ((biomeEntry != null && biomeEntry.Slot == 4) ? "then the Peak" : "then the island's own Caldera + Kiln or Gloom + Citadel up to the Peak");
			((TMP_Text)_sub).text = (Host ? $"{num} biomes, {arg}. Tick to keep, arrows to move." : $"The host's plan: {num} biomes, {arg}.");
			List<string[]> list = runPlan.Units();
			int num2 = 0;
			for (int i = 0; i < list.Count; i++)
			{
				BiomeEntry[] array = Array.ConvertAll(list[i], RunPlan.Find);
				if (Array.IndexOf(array, null) < 0)
				{
					bool flag = !runPlan.Off.Contains(array[0].Id);
					if (flag)
					{
						num2++;
					}
					Row(i, array, flag, flag ? num2 : 0);
					_units++;
				}
			}
			ApplyColumns();
		}

		private void Change(RunPlan p)
		{
			if (Host)
			{
				PlanSync.Save(p);
				Refresh(force: true);
			}
		}

		private void Row(int index, BiomeEntry[] es, bool on, int number)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			BiomeEntry e = es[0];
			GameObject val = new GameObject(e.Id, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)_rows, false);
			Rounded(val, on ? RowOn : RowOff, 10f);
			HorizontalLayoutGroup val2 = val.AddComponent<HorizontalLayoutGroup>();
			((LayoutGroup)val2).padding = new RectOffset(10, 8, 4, 4);
			((HorizontalOrVerticalLayoutGroup)val2).spacing = 8f;
			((LayoutGroup)val2).childAlignment = (TextAnchor)3;
			bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)val2).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)val2).childControlWidth = childControlWidth;
			((HorizontalOrVerticalLayoutGroup)val2).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)val2).childForceExpandHeight = false;
			val.AddComponent<LayoutElement>().preferredHeight = 42f;
			TextMeshProUGUI val3 = Text(val.transform, (number > 0) ? number.ToString() : "", 20f, Accent, (TextAlignmentOptions)516, 34f);
			((Component)val3).GetComponent<LayoutElement>().preferredWidth = 26f;
			if (!e.Fixed && Host)
			{
				Box(val.transform, on, delegate
				{
					RunPlan runPlan = _plan.Clone();
					runPlan.Toggle(e.Id);
					Change(runPlan);
				});
			}
			else
			{
				Spacer(val.transform, 26f);
			}
			string s = string.Join(" + ", Array.ConvertAll(es, (BiomeEntry x) => (x.Short ?? x.Title).ToUpperInvariant()));
			TextMeshProUGUI val4 = Text(val.transform, s, 21f, on ? Ink : Faint, (TextAlignmentOptions)513, 34f);
			((Component)val4).GetComponent<LayoutElement>().flexibleWidth = 1f;
			if (e.Fixed)
			{
				((Component)Text(val.transform, (e.Id == "shore") ? "START" : "FINISH", 14f, Faint, (TextAlignmentOptions)516, 34f)).GetComponent<LayoutElement>().preferredWidth = 74f;
			}
			else if (Host)
			{
				Arrow(val.transform, 45f, _plan.CanMove(index, -1), delegate
				{
					RunPlan runPlan = _plan.Clone();
					runPlan.Move(index, -1);
					Change(runPlan);
				});
				Arrow(val.transform, -135f, _plan.CanMove(index, 1), delegate
				{
					RunPlan runPlan = _plan.Clone();
					runPlan.Move(index, 1);
					Change(runPlan);
				});
			}
		}

		private TextMeshProUGUI Text(Transform parent, string s, float size, Color color, TextAlignmentOptions align, float height)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val2).font = _font;
			if ((Object)(object)_fontMat != (Object)null)
			{
				((TMP_Text)val2).fontSharedMaterial = _fontMat;
			}
			((TMP_Text)val2).fontSize = size;
			((Graphic)val2).color = color;
			((TMP_Text)val2).alignment = align;
			((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0;
			((Graphic)val2).raycastTarget = false;
			((TMP_Text)val2).text = s;
			val.AddComponent<LayoutElement>().preferredHeight = height;
			return val2;
		}

		private static void Spacer(Transform parent, float w)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			GameObject val = new GameObject("Spacer", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			val2.preferredWidth = w;
			val2.preferredHeight = 26f;
		}

		private static Graphic Rounded(GameObject go, Color color, float radius)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			ProceduralImage val = go.AddComponent<ProceduralImage>();
			val.ModifierType = typeof(UniformModifier);
			UniformModifier component = go.GetComponent<UniformModifier>();
			if ((Object)(object)component != (Object)null)
			{
				component.Radius = radius;
			}
			((Graphic)val).color = color;
			return (Graphic)(object)val;
		}

		private void Box(Transform parent, bool on, Action click)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_006a: 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_00a2: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_0128: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Keep", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			float preferredWidth = (val2.preferredHeight = 26f);
			val2.preferredWidth = preferredWidth;
			Graphic targetGraphic = Rounded(val, new Color(1f, 1f, 1f, 0.16f), 6f);
			Button val3 = val.AddComponent<Button>();
			((Selectable)val3).targetGraphic = targetGraphic;
			((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
			{
				click();
			});
			GameObject val4 = new GameObject("Tick", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(val.transform, false);
			RectTransform val5 = (RectTransform)val4.transform;
			val5.anchorMin = Vector2.zero;
			val5.anchorMax = Vector2.one;
			val5.offsetMin = new Vector2(5f, 5f);
			val5.offsetMax = new Vector2(-5f, -5f);
			Graphic val6 = Rounded(val4, Accent, 3f);
			val6.raycastTarget = false;
			val4.SetActive(on);
		}

		private void Arrow(Transform parent, float angle, bool enabled, Action click)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject((angle > 0f) ? "Up" : "Down", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			float preferredWidth = (val2.preferredHeight = 30f);
			val2.preferredWidth = preferredWidth;
			Graphic targetGraphic = Rounded(val, new Color(0f, 0f, 0f, enabled ? 0.35f : 0.12f), 8f);
			Button val3 = val.AddComponent<Button>();
			((Selectable)val3).targetGraphic = targetGraphic;
			((Selectable)val3).interactable = enabled;
			((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
			{
				click();
			});
			GameObject val4 = new GameObject("Icon", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(val.transform, false);
			RectTransform val5 = (RectTransform)val4.transform;
			Vector2 val6 = default(Vector2);
			((Vector2)(ref val6))..ctor(0.5f, 0.5f);
			val5.anchorMax = val6;
			val5.anchorMin = val6;
			val5.sizeDelta = new Vector2(16f, 16f);
			((Transform)val5).localRotation = Quaternion.Euler(0f, 0f, angle);
			if ((Object)(object)_arrow != (Object)null)
			{
				Image val7 = val4.AddComponent<Image>();
				val7.sprite = _arrow;
				val7.preserveAspect = true;
				((Graphic)val7).color = (enabled ? Ink : Faint);
				((Graphic)val7).raycastTarget = false;
			}
			else
			{
				((Transform)val5).localRotation = Quaternion.identity;
				Text(val4.transform, (angle > 0f) ? "UP" : "DN", 12f, enabled ? Ink : Faint, (TextAlignmentOptions)514, 16f);
			}
		}

		private void Pill(Transform parent, string label, Action click)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(label, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			val2.preferredWidth = 170f;
			val2.preferredHeight = 36f;
			Graphic targetGraphic = Rounded(val, new Color(0f, 0f, 0f, 0.35f), 18f);
			Button val3 = val.AddComponent<Button>();
			((Selectable)val3).targetGraphic = targetGraphic;
			((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
			{
				click();
			});
			TextMeshProUGUI val4 = Text(val.transform, label, 16f, Ink, (TextAlignmentOptions)514, 36f);
			RectTransform rectTransform = ((TMP_Text)val4).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			Vector2 offsetMin = (rectTransform.offsetMax = Vector2.zero);
			rectTransform.offsetMin = offsetMin;
		}
	}
}
namespace BiomePicker.Game
{
	internal static class CopyFixups
	{
		private static int _nextFakeIndex = -1;

		private static readonly FieldRef<GenericOptimizer, bool> ScriptsEnabled = AccessTools.FieldRefAccess<GenericOptimizer, bool>("scriptsEnabled");

		public static int FakeItemsAdded { get; private set; }

		public static void Reset()
		{
			_nextFakeIndex = -1;
			FakeItemsAdded = 0;
		}

		public static void Apply(GameObject copy, MapHandler mh)
		{
			Biome[] componentsInChildren = copy.GetComponentsInChildren<Biome>(true);
			foreach (Biome val in componentsInChildren)
			{
				val.mapHandler = mh;
			}
			SpawnedItemTracker[] componentsInChildren2 = copy.GetComponentsInChildren<SpawnedItemTracker>(true);
			foreach (SpawnedItemTracker val2 in componentsInChildren2)
			{
				Object.DestroyImmediate((Object)(object)val2);
			}
			FakeItemManager instance = FakeItemManager.Instance;
			if (_nextFakeIndex < 0)
			{
				_nextFakeIndex = (from f in instance.allFakeItems
					where (Object)(object)f != (Object)null
					select f.index).DefaultIfEmpty(-1).Max() + 1;
			}
			FakeItem[] componentsInChildren3 = copy.GetComponentsInChildren<FakeItem>(true);
			foreach (FakeItem val3 in componentsInChildren3)
			{
				val3.index = _nextFakeIndex++;
				val3.pickedUp = false;
				instance.allFakeItems.Add(val3);
				FakeItemsAdded++;
			}
		}

		public static (int restored, int optimizers) AsBeforeWaking(GameObject original, GameObject copy)
		{
			GenericOptimizer[] componentsInChildren = original.GetComponentsInChildren<GenericOptimizer>(true);
			GenericOptimizer[] componentsInChildren2 = copy.GetComponentsInChildren<GenericOptimizer>(true);
			if (componentsInChildren.Length != componentsInChildren2.Length)
			{
				return (restored: 0, optimizers: componentsInChildren2.Length);
			}
			IList list = (IList)AccessTools.Field(typeof(ItemOptimizationManager), "GENERIC_LIST").GetValue(null);
			int num = 0;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (!list.Contains(componentsInChildren[i]) || ScriptsEnabled.Invoke(componentsInChildren[i]))
				{
					continue;
				}
				foreach (MonoBehaviour item in componentsInChildren2[i].scriptsToDisable ?? new List<MonoBehaviour>())
				{
					if ((Object)(object)item != (Object)null && ((Component)item).transform.IsChildOf(copy.transform))
					{
						((Behaviour)item).enabled = true;
					}
				}
				foreach (Animator item2 in componentsInChildren2[i].animatorsToDisable ?? new List<Animator>())
				{
					if ((Object)(object)item2 != (Object)null && ((Component)item2).transform.IsChildOf(copy.transform))
					{
						((Behaviour)item2).enabled = true;
					}
				}
				num++;
			}
			return (restored: num, optimizers: componentsInChildren2.Length);
		}

		public static int RegisterViews(GameObject root)
		{
			int num = 0;
			PhotonView[] componentsInChildren = root.GetComponentsInChildren<PhotonView>(true);
			foreach (PhotonView val in componentsInChildren)
			{
				if (val.sceneViewId != 0 && val.ViewID == 0 && !val.isRuntimeInstantiated)
				{
					if ((Object)(object)PhotonNetwork.GetPhotonView(val.sceneViewId) != (Object)null)
					{
						Plugin.Log.LogWarning((object)$"view ID {val.sceneViewId} of {((Object)val).name} is taken; it stays unregistered until it wakes");
						continue;
					}
					val.ViewID = val.sceneViewId;
					val.FindObservables(false);
					num++;
				}
			}
			return num;
		}

		public static IEnumerable<string> Singletons(GameObject root)
		{
			return (from m in root.GetComponentsInChildren<MonoBehaviour>(true)
				where (Object)(object)m != (Object)null && IsSingleton(((object)m).GetType())
				select ((object)m).GetType().Name).Distinct();
		}

		private static bool IsSingleton(Type t)
		{
			Type baseType = t.BaseType;
			while (baseType != null)
			{
				if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == typeof(Singleton<>))
				{
					return true;
				}
				baseType = baseType.BaseType;
			}
			return false;
		}

		public static void UsePeakOf(GameObject content)
		{
			if (!((Object)(object)content == (Object)null))
			{
				PeakHandler componentInChildren = content.GetComponentInChildren<PeakHandler>(true);
				if (!((Object)(object)componentInChildren == (Object)null))
				{
					AccessTools.Field(typeof(Singleton<PeakHandler>), "_instance").SetValue(null, componentInChildren);
				}
			}
		}
	}
	internal sealed class CustomStage
	{
		private sealed class Lift : IDisposable
		{
			private readonly GameObject _go;

			private readonly Vector3 _by;

			private readonly List<GameObject> _woken = new List<GameObject>();

			public Lift(GameObject go, Vector3 by, bool wake)
			{
				//IL_0019: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f8: 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_0116: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_009b: Expected O, but got Unknown
				_go = go;
				_by = by;
				if ((Object)(object)_go == (Object)null)
				{
					return;
				}
				if (wake)
				{
					Transform val = _go.transform;
					while ((Object)(object)val != (Object)null)
					{
						if (!((Component)val).gameObject.activeSelf)
						{
							_woken.Add(((Component)val).gameObject);
							((Component)val).gameObject.SetActive(true);
						}
						val = val.parent;
					}
					foreach (Transform item in _go.transform)
					{
						Transform val2 = item;
						if (!((Component)val2).gameObject.activeSelf && ((Object)val2).name.EndsWith("_Segment"))
						{
							_woken.Add(((Component)val2).gameObject);
							((Component)val2).gameObject.SetActive(true);
						}
					}
				}
				if (_by != Vector3.zero)
				{
					Transform transform = _go.transform;
					transform.position += _by;
				}
				Physics.SyncTransforms();
			}

			public void Dispose()
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_go == (Object)null))
				{
					if (_by != Vector3.zero)
					{
						Transform transform = _go.transform;
						transform.position -= _by;
					}
					for (int num = _woken.Count - 1; num >= 0; num--)
					{
						_woken[num].SetActive(false);
					}
					Physics.SyncTransforms();
				}
			}
		}

		public int Slot;

		public MapHandler Map;

		public Scene Scene;

		public Campfire Start;

		public Vector3 Offset;

		public GameObject Shore;

		public VariantPart Today;

		public Transform Home;

		public ulong Seed;

		public Func<GameObject, GameObject> CopyToday;

		public GameObject Unit;

		public GameObject Content;

		public GameObject EndCamp;

		public DayNightProfile Sky;

		public IDisposable ShoreAtStart()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return new Lift(Shore, Offset, wake: true);
		}

		public IDisposable SlotHere()
		{
			//IL_000c: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			return new Lift(Today.Unit, Offset - Stack.LiftOf(Today.Unit.transform), wake: false);
		}
	}
	internal interface ICustomBiome
	{
		string Id { get; }

		string Name { get; }

		string Title { get; }

		bool Available { get; }

		IEnumerator Build(CustomStage stage);

		void Enter(Round r);

		void Leave(Round r);
	}
	internal static class CustomBiomes
	{
		private static readonly List<ICustomBiome> All = new List<ICustomBiome>();

		public static void Register(ICustomBiome b)
		{
			All.Add(b);
			Plugin.Log.LogInfo((object)("Custom biome " + b.Name + ": " + (b.Available ? "available" : "not installed")));
		}

		public static ICustomBiome Find(string id)
		{
			return All.Find((ICustomBiome b) => b.Id == id);
		}
	}
	internal static class DonorGuard
	{
		private static readonly HashSet<string> Donors = new HashSet<string>();

		private static bool _patched;

		private static readonly List<MethodBase> Patched = new List<MethodBase>();

		internal static Action<Scene> Loaded;

		private static readonly Type[] ContentSingletons = new Type[1] { typeof(PeakHandler) };

		private static readonly Dictionary<Type, object> Saved = new Dictionary<Type, object>();

		internal static readonly Dictionary<string, int> Skipped = new Dictionary<string, int>();

		private static readonly string[] Lifecycle = new string[5] { "Awake", "OnEnable", "OnDisable", "Start", "OnDestroy" };

		internal static int PatchedMethods { get; private set; }

		internal static bool IsPatched => _patched;

		internal static int FailedMethods { get; private set; }

		internal static long PatchMs { get; private set; }

		internal static void FreeSingletons()
		{
			Saved.Clear();
			Type[] contentSingletons = ContentSingletons;
			foreach (Type type in contentSingletons)
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(Singleton<>).MakeGenericType(type), "_instance");
				Saved[type] = fieldInfo.GetValue(null);
				fieldInfo.SetValue(null, null);
			}
		}

		internal static void RestoreSingletons()
		{
			foreach (KeyValuePair<Type, object> item in Saved)
			{
				AccessTools.Field(typeof(Singleton<>).MakeGenericType(item.Key), "_instance").SetValue(null, item.Value);
			}
			Saved.Clear();
		}

		internal static void Add(string scene)
		{
			Donors.Add(scene);
		}

		internal static void Remove(string scene)
		{
			Donors.Remove(scene);
		}

		internal static bool IsDonorScene(string scene)
		{
			return Donors.Contains(scene);
		}

		private static bool IsDonor(object o)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (Donors.Count == 0)
			{
				return false;
			}
			Component val = (Component)((o is Component) ? o : null);
			if (val == null || (Object)(object)val == (Object)null)
			{
				return false;
			}
			Scene scene = val.gameObject.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				return Donors.Contains(((Scene)(ref scene)).name);
			}
			return false;
		}

		private static void Count(MethodBase m)
		{
			string name = m.Name;
			Skipped.TryGetValue(name, out var value);
			Skipped[name] = value + 1;
		}

		private static bool SkipVoid(object __instance, MethodBase __originalMethod)
		{
			if (!IsDonor(__instance))
			{
				return true;
			}
			Count(__originalMethod);
			return false;
		}

		private static bool SkipEnumerator(object __instance, MethodBase __originalMethod, ref IEnumerator __result)
		{
			if (!IsDonor(__instance))
			{
				return true;
			}
			Count(__originalMethod);
			__result = Empty();
			return false;
		}

		private static IEnumerator Empty()
		{
			yield break;
		}

		private static bool SceneLoadedPrefix(Scene scene)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!IsDonorScene(((Scene)(ref scene)).name))
			{
				return true;
			}
			RestoreSingletons();
			try
			{
				Loaded?.Invoke(scene);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Donor scene setup failed: " + ex));
			}
			return false;
		}

		private static bool SceneUnloadedPrefix(Scene scene)
		{
			return !IsDonorScene(((Scene)(ref scene)).name);
		}

		internal static void EnsurePatched(Harmony harmony)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			if (_patched)
			{
				return;
			}
			_patched = true;
			Stopwatch stopwatch = Stopwatch.StartNew();
			harmony.Patch((MethodBase)AccessTools.Method(typeof(SceneManager), "Internal_SceneLoaded", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DonorGuard), "SceneLoadedPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(SceneManager), "Internal_SceneUnloaded", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DonorGuard), "SceneUnloadedPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			HarmonyMethod val = new HarmonyMethod(typeof(DonorGuard), "SkipVoid", (Type[])null);
			HarmonyMethod val2 = new HarmonyMethod(typeof(DonorGuard), "SkipEnumerator", (Type[])null);
			HashSet<MethodBase> hashSet = new HashSet<MethodBase>();
			foreach (MethodInfo item in LifecycleMethods())
			{
				if (!hashSet.Add(item))
				{
					continue;
				}
				try
				{
					if (item.ReturnType == typeof(void))
					{
						harmony.Patch((MethodBase)item, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						goto IL_012c;
					}
					if (typeof(IEnumerator).IsAssignableFrom(item.ReturnType))
					{
						harmony.Patch((MethodBase)item, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						goto IL_012c;
					}
					goto end_IL_00da;
					IL_012c:
					Patched.Add(item);
					PatchedMethods++;
					end_IL_00da:;
				}
				catch (Exception ex)
				{
					FailedMethods++;
					if (FailedMethods <= 5)
					{
						Plugin.Log.LogWarning((object)$"Donor guard: could not patch {item.DeclaringType}.{item.Name}: {ex.Message}");
					}
				}
			}
			PatchMs = stopwatch.ElapsedMilliseconds;
			Plugin.Log.LogInfo((object)$"Donor guard: {PatchedMethods} lifecycle methods patched in {PatchMs} ms ({FailedMethods} failed).");
		}

		internal static void Unpatch(Harmony harmony)
		{
			if (!_patched || Donors.Count > 0)
			{
				return;
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			foreach (MethodBase item in Patched)
			{
				try
				{
					harmony.Unpatch(item, (HarmonyPatchType)1, harmony.Id);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)$"Donor guard: could not unpatch {item.DeclaringType}.{item.Name}: {ex.Message}");
				}
			}
			harmony.Unpatch((MethodBase)AccessTools.Method(typeof(SceneManager), "Internal_SceneLoaded", (Type[])null, (Type[])null), (HarmonyPatchType)1, harmony.Id);
			harmony.Unpatch((MethodBase)AccessTools.Method(typeof(SceneManager), "Internal_SceneUnloaded", (Type[])null, (Type[])null), (HarmonyPatchType)1, harmony.Id);
			Plugin.Log.LogInfo((object)$"Donor guard: {Patched.Count} lifecycle methods unpatched in {stopwatch.ElapsedMilliseconds} ms.");
			Patched.Clear();
			PatchedMethods = 0;
			_patched = false;
		}

		private static IEnumerable<MethodInfo> LifecycleMethods()
		{
			string managed = Path.GetFullPath(Path.Combine(Application.dataPath, "Managed"));
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (assembly.IsDynamic || !IsGameAssembly(assembly, managed))
				{
					continue;
				}
				Type[] array;
				try
				{
					array = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					array = ex.Types.Where((Type t) => t != null).ToArray();
				}
				Type[] array2 = array;
				foreach (Type type in array2)
				{
					if (type.ContainsGenericParameters || !typeof(MonoBehaviour).IsAssignableFrom(type))
					{
						continue;
					}
					Type b = type;
					while (b != null && b != typeof(MonoBehaviour))
					{
						if (!b.IsGenericType)
						{
							string[] lifecycle = Lifecycle;
							foreach (string name in lifecycle)
							{
								MethodInfo method = b.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
								if (!(method == null) && !method.IsAbstract && !method.IsGenericMethod)
								{
									MethodBody methodBody;
									try
									{
										methodBody = method.GetMethodBody();
									}
									catch
									{
										methodBody = null;
									}
									if (methodBody != null)
									{
										yield return method;
									}
								}
							}
						}
						b = b.BaseType;
					}
				}
			}
		}

		private static bool IsGameAssembly(Assembly asm, string managed)
		{
			string location;
			try
			{
				location = asm.Location;
			}
			catch
			{
				return false;
			}
			if (string.IsNullOrEmpty(location))
			{
				return false;
			}
			if (!string.Equals(Path.GetFullPath(Path.GetDirectoryName(location)), managed, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string name = asm.GetName().Name;
			if (!(name == "mscorlib") && !(name == "netstandard") && !name.StartsWith("System") && !name.StartsWith("Mono."))
			{
				if (name.StartsWith("UnityEngine."))
				{
					return !name.EndsWith("Module");
				}
				return true;
			}
			return false;
		}
	}
	internal sealed class DonorIsland
	{
		public int Level;

		public string SceneName;

		public Scene Scene;

		public MapHandler Map;

		public LightVolume Light;

		public double BundleSeconds;

		public double LoadSeconds;

		public long WorkingSetBefore;

		public long WorkingSetAfter;

		public int RootCount;

		public string Error;

		public bool Ok
		{
			get
			{
				if (Error == null)
				{
					return (Object)(object)Map != (Object)null;
				}
				return false;
			}
		}

		public static IEnumerator Load(Harmony harmony, int level, Action<DonorIsland> done)
		{
			DonorIsland d = new DonorIsland
			{
				Level = level,
				SceneName = SingletonAsset<MapBaker>.Instance.GetLevel(level)
			};
			DonorGuard.EnsurePatched(harmony);
			DonorGuard.Skipped.Clear();
			d.WorkingSetBefore = Process.GetCurrentProcess().WorkingSet64;
			Stopwatch sw = Stopwatch.StartNew();
			MapBundleService service = GameHandler.GetService<MapBundleService>();
			MapBundleData bundle = ((service != null) ? service.LoadBundlesNearestIndex(level, false) : null);
			while (bundle != null && bundle.Loading)
			{
				yield return null;
			}
			d.BundleSeconds = sw.Elapsed.TotalSeconds;
			sw.Restart();
			DonorGuard.Add(d.SceneName);
			DonorGuard.Loaded = delegate(Scene scene)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				d.OnLoaded(scene);
			};
			DonorGuard.FreeSingletons();
			AsyncOperation op;
			try
			{
				op = SceneManager.LoadSceneAsync(d.SceneName, (LoadSceneMode)1);
			}
			catch (Exception ex)
			{
				op = null;
				d.Error = ex.Message;
			}
			if (op == null)
			{
				DonorIsland donorIsland = d;
				if (donorIsland.Error == null)
				{
					donorIsland.Error = "LoadSceneAsync returned null";
				}
				DonorGuard.RestoreSingletons();
				DonorGuard.Remove(d.SceneName);
				done(d);
				yield break;
			}
			while (!op.isDone)
			{
				LoadProgress.Report(op.progress / 0.9f);
				yield return null;
			}
			DonorGuard.Loaded = null;
			d.LoadSeconds = sw.Elapsed.TotalSeconds;
			d.WorkingSetAfter = Process.GetCurrentProcess().WorkingSet64;
			if ((Object)(object)d.Map == (Object)null && d.Error == null)
			{
				d.Error = "no MapHandler in " + d.SceneName;
			}
			done(d);
		}

		private void OnLoaded(Scene scene)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Scene = scene;
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			RootCount = rootGameObjects.Length;
			GameObject[] array = rootGameObjects;
			foreach (GameObject val in array)
			{
				if ((Object)(object)Map == (Object)null)
				{
					Map = val.GetComponentInChildren<MapHandler>(true);
				}
				if ((Object)(object)Light == (Object)null)
				{
					Light = val.GetComponentInChildren<LightVolume>(true);
				}
				val.SetActive(false);
			}
		}

		public GameObject Copy(GameObject source, ViewIds ids)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = source.transform;
			Vector3 position = transform.position;
			Quaternion rotation = transform.rotation;
			Vector3 lossyScale = transform.lossyScale;
			source.SetActive(false);
			GameObject val = Object.Instantiate<GameObject>(source);
			((Object)val).name = ((Object)source).name;
			val.transform.SetPositionAndRotation(position, rotation);
			val.transform.localScale = lossyScale;
			PhotonView[] componentsInChildren = val.GetComponentsInChildren<PhotonView>(true);
			foreach (PhotonView val2 in componentsInChildren)
			{
				if (val2.sceneViewId != 0 && !val2.isRuntimeInstantiated)
				{
					val2.ViewID = (val2.sceneViewId = ids.Next());
					val2.FindObservables(false);
				}
			}
			return val;
		}

		public IEnumerator Unload()
		{
			if (((Scene)(ref Scene)).IsValid())
			{
				AsyncOperation op = SceneManager.UnloadSceneAsync(Scene);
				while (op != null && !op.isDone)
				{
					yield return null;
				}
				DonorGuard.Remove(SceneName);
			}
		}
	}
	internal sealed class ViewIds
	{
		public const int Top = 8999;

		private readonly HashSet<int> _used = new HashSet<int>();

		private int _next = 8999;

		public int Lowest => _next + 1;

		public ViewIds()
		{
			//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)
			PhotonView[] array = Object.FindObjectsByType<PhotonView>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (PhotonView val in array)
			{
				Scene scene = ((Component)val).gameObject.scene;
				if (!DonorGuard.IsDonorScene(((Scene)(ref scene)).name))
				{
					if (val.sceneViewId != 0)
					{
						_used.Add(val.sceneViewId);
					}
					if (val.ViewID != 0)
					{
						_used.Add(val.ViewID);
					}
				}
			}
		}

		public int Next()
		{
			while (_used.Contains(_next) || (Object)(object)PhotonNetwork.GetPhotonView(_next) != (Object)null)
			{
				_next--;
			}
			if (_next <= 0)
			{
				throw new InvalidOperationException("no free scene view IDs left");
			}
			_used.Add(_next);
			return _next--;
		}
	}
	[HarmonyPatch]
	internal static class GlobalSpawners
	{
		public static Dictionary<string, List<GameObject>> ByBiome(MapHandler map, List<VariantPart> parts)
		{
			//IL_009a: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, List<GameObject>> dictionary = new Dictionary<string, List<GameObject>>();
			if ((Object)(object)map == (Object)null || (Object)(object)map.globalParent == (Object)null)
			{
				return dictionary;
			}
			List<(string, Collider[])> list = (from p in parts
				where (Object)(object)p.Parent != (Object)null
				select (Id: p.Id, Colliders: p.Parent.GetComponentsInChildren<Collider>(true))).ToList();
			MonoBehaviour[] componentsInChildren = ((Component)map.globalParent).GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!(val is ISpawner))
				{
					continue;
				}
				Vector3 position = ((Component)val).transform.position;
				string text = null;
				float num2 = float.MaxValue;
				foreach (var (text2, colliders) in list)
				{
					using Stack.GroundProbe groundProbe = new Stack.GroundProbe(colliders, position, 8f);
					if (groundProbe.Count != 0)
					{
						float? num3 = groundProbe.Nearest(position, 8f);
						if (num3.HasValue && num3.Value < num2)
						{
							num2 = num3.Value;
							text = text2;
						}
					}
				}
				if (text != null)
				{
					if (!dictionary.TryGetValue(text, out var value))
					{
						value = (dictionary[text] = new List<GameObject>());
					}
					if (!value.Contains(((Component)val).gameObject))
					{
						value.Add(((Component)val).gameObject);
					}
				}
			}
			return dictionary;
		}

		public static int CopyInto(Dictionary<string, List<GameObject>> spawners, string id, GameObject content, Vector3 by, Func<GameObject, GameObject> copy)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0076: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)content == (Object)null || !spawners.TryGetValue(id, out var value) || value.Count == 0)
			{
				return 0;
			}
			GameObject val = new GameObject("BiomePicker island spawners");
			val.transform.SetParent(content.transform, false);
			foreach (GameObject item in value)
			{
				GameObject val2 = copy(item);
				val2.transform.SetParent(val.transform, true);
				val2.transform.position = item.transform.position + by;
				val2.SetActive(true);
			}
			return value.Count;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MapHandler), "Update")]
		private static bool HoldFirstSpawn(MapHandler __instance)
		{
			if (!__instance.hasSpawnedInitialSpawners)
			{
				return !RunDirector.SettingUp;
			}
			return true;
		}
	}
	internal static class IslandCatalog
	{
		public const int BundleSize = 32;

		public static MapBaker Baker => SingletonAsset<MapBaker>.Instance;

		public static int Count
		{
			get
			{
				if (!((Object)(object)Baker != (Object)null) || Baker.ScenePaths == null)
				{
					return 0;
				}
				return Baker.ScenePaths.Length;
			}
		}

		public static string Code(int level)
		{
			if (!((Object)(object)Baker != (Object)null))
			{
				return "";
			}
			return Baker.GetBiomeID(level);
		}

		public static int LevelOf(string sceneName)
		{
			int num = sceneName.IndexOf("Level_");
			if (num < 0)
			{
				return -1;
			}
			if (!int.TryParse(sceneName.Substring(num + 6), out var result))
			{
				return -1;
			}
			return result;
		}

		public static int BundleOf(int level)
		{
			return level / 32;
		}

		public static int MostDifferent(int level)
		{
			string text = Code(level);
			int result = -1;
			int num = int.MinValue;
			for (int i = 0; i < Count; i++)
			{
				if (i == level)
				{
					continue;
				}
				string text2 = Code(i);
				int num2 = 0;
				for (int j = 0; j < Mathf.Max(text2.Length, text.Length); j++)
				{
					if (j >= text2.Length || j >= text.Length || text2[j] != text[j])
					{
						num2++;
					}
				}
				int num3 = num2 * 1000 + ((BundleOf(i) == BundleOf(level)) ? 500 : 0) - Mathf.Abs(i - level);
				if (num3 > num)
				{
					num = num3;
					result = i;
				}
			}
			return result;
		}

		public static IEnumerable<string> Describe()
		{
			for (int i = 0; i < Count; i++)
			{
				yield return $"{i,3} {Baker.GetLevel(i),-10} {Code(i)}";
			}
		}
	}
	internal static class LightGrids
	{
		private static readonly MethodInfo Load = AccessTools.Method(typeof(LightVolume), "LoadLightMapData", (Type[])null, (Type[])null);

		private static readonly MethodInfo Vars = AccessTools.Method(typeof(LightVolume), "SetShaderVars", (Type[])null, (Type[])null);

		private static readonly FieldInfo Instance = AccessTools.Field(typeof(LightVolume), "instance");

		private static readonly Dictionary<LightVolume, Vector3> Home = new Dictionary<LightVolume, Vector3>();

		private static LightVolume _today;

		private static LightVolume _current;

		public static void Reset()
		{
			Home.Clear();
			_today = LightVolume.Instance();
			_current = _today;
		}

		public static void Use(LightVolume grid, Vector3 lift)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			LightVolume val = (((Object)(object)grid != (Object)null) ? grid : _today);
			if (!((Object)(object)val == (Object)null))
			{
				Stopwatch stopwatch = Stopwatch.StartNew();
				bool flag = (Object)(object)val != (Object)(object)_current;
				if (flag)
				{
					Load.Invoke(val, null);
				}
				if (!Home.TryGetValue(val, out var value))
				{
					value = (Home[val] = val.gridOffset);
				}
				Vector3 val2 = value + lift;
				if (flag || !(val.gridOffset == val2))
				{
					val.gridOffset = val2;
					Vars.Invoke(val, null);
					Instance.SetValue(null, val);
					_current = val;
					Plugin.Log.LogInfo((object)string.Format("Light grid: {0}{1} in {2} ms", ((Object)(object)val == (Object)(object)_today) ? "today's" : ((Object)val).name, (lift != Vector3.zero) ? $" lifted by {lift:F1}" : "", stopwatch.ElapsedMilliseconds));
				}
			}
		}
	}
	internal static class LoadProgress
	{
		private sealed class Step
		{
			public string Key;

			public string Label;

			public float Expected;

			public bool Done;

			public float Fraction = -1f;

			public Stopwatch Clock;
		}

		[Serializable]
		private sealed class TimingsFile
		{
			public List<string> keys = new List<string>();

			public List<float> seconds = new List<float>();
		}

		private static readonly Dictionary<string, float> Defaults = new Dictionary<string, float>
		{
			["island"] = 10f,
			["guard"] = 1.5f,
			["donor"] = 4.8f,
			["copy"] = 0.3f,
			["camps"] = 0.4f,
			["lostcity"] = 5.5f,
			["sakura"] = 18f,
			["finish"] = 1.3f,
			["setup"] = 25f
		};

		private static Dictionary<string, float> _timings;

		private static readonly List<Step> Steps = new List<Step>();

		private static Step _current;

		private static Stopwatch _setup;

		public static bool Shown { get; private set; }

		private static string FilePath => Path.Combine(Paths.CachePath, "BiomePicker.timings.json");

		public static float Value
		{
			get
			{
				float num = Steps.Sum((Step s) => s.Expected);
				float num2 = 0f;
				if (num <= 0f)
				{
					return 0f;
				}
				foreach (Step step in Steps)
				{
					if (step.Done)
					{
						num2 += step.Expected;
					}
					else if (step.Clock != null)
					{
						float num3 = ((step.Fraction >= 0f) ? step.Fraction : Mathf.Min(0.95f, (float)step.Clock.Elapsed.TotalSeconds / step.Expected));
						num2 += num3 * step.Expected;
					}
				}
				return Mathf.Clamp01(num2 / num);
			}
		}

		public static string Label => (_current ?? Steps.FirstOrDefault((Step s) => !s.Done))?.Label ?? "Almost there";

		private static float Expect(string key)
		{
			if (_timings == null)
			{
				LoadTimings();
			}
			if (_timings.TryGetValue(key, out var value) && value > 0f)
			{
				return value;
			}
			if (!Defaults.TryGetValue(key, out var value2))
			{
				return 1f;
			}
			return value2;
		}

		public static void Begin()
		{
			Steps.Clear();
			_current = null;
			_setup = null;
			Shown = true;
			Add("island", "Flying to the island");
			Start("island");
			Add("setup", "Setting up the run");
		}

		public static void BeginSetup()
		{
			if (Shown)
			{
				Steps.RemoveAll((Step s) => s.Key == "setup" && !s.Done);
				_setup = Stopwatch.StartNew();
			}
		}

		public static void Add(string key, string label)
		{
			if (Shown)
			{
				Steps.Add(new Step
				{
					Key = key,
					Label = label,
					Expected = Expect(key)
				});
			}
		}

		public static void Start(string key)
		{
			if (!Shown)
			{
				return;
			}
			Step s = Steps.FirstOrDefault((Step x) => !x.Done && x.Key == key && x.Clock == null);
			if (s == null)
			{
				return;
			}
			foreach (Step item in Steps.TakeWhile((Step x) => x != s))
			{
				Finish(item);
			}
			s.Clock = Stopwatch.StartNew();
			_current = s;
		}

		public static void Report(float fraction)
		{
			if (_current != null)
			{
				_current.Fraction = Mathf.Clamp01(fraction);
			}
		}

		public static void End(string key)
		{
			Step step = Steps.FirstOrDefault((Step x) => x.Key == key && x.Clock != null && !x.Done);
			if (step != null)
			{
				Finish(step);
				Remember(step.Key, (float)step.Clock.Elapsed.TotalSeconds);
			}
		}

		private static void Finish(Step s)
		{
			s.Done = true;
			if (_current == s)
			{
				_current = null;
			}
		}

		public static void Complete()
		{
			if (_setup != null)
			{
				Remember("setup", (float)_setup.Elapsed.TotalSeconds);
			}
			_setup = null;
			foreach (Step step in Steps)
			{
				step.Done = true;
			}
			_current = null;
			Shown = false;
			SaveTimings();
		}

		private static void Remember(string key, float seconds)
		{
			if (_timings == null)
			{
				LoadTimings();
			}
			if (!(seconds <= 0.01f))
			{
				if (key == "copy" || key == "camps")
				{
					_timings[key] = (_timings.TryGetValue(key, out var value) ? Mathf.Lerp(value, seconds, 0.3f) : seconds);
				}
				else
				{
					_timings[key] = (_timings.TryGetValue(key, out var value2) ? Mathf.Lerp(value2, seconds, 0.6f) : seconds);
				}
			}
		}

		private static void LoadTimings()
		{
			_timings = new Dictionary<string, float>();
			try
			{
				if (File.Exists(FilePath))
				{
					TimingsFile timingsFile = JsonUtility.FromJson<TimingsFile>(File.ReadAllText(FilePath));
					for (int i = 0; i < Mathf.Min(timingsFile.keys.Count, timingsFile.seconds.Count); i++)
					{
						_timings[timingsFile.keys[i]] = timingsFile.seconds[i];
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("loading-bar timings unreadable: " + ex.Message));
			}
		}

		private static void SaveTimings()
		{
			if (_timings == null)
			{
				return;
			}
			try
			{
				TimingsFile timingsFile = new TimingsFile();
				foreach (KeyValuePair<string, float> timing in _timings)
				{
					timingsFile.keys.Add(timing.Key);
					timingsFile.seconds.Add(timing.Value);
				}
				Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
				File.WriteAllText(FilePath, JsonUtility.ToJson((object)timingsFile));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("loading-bar timings not saved: " + ex.Message));
			}
		}
	}
	internal sealed class LostCityBiome : ICustomBiome
	{
		private const string StandIn = "BiomePicker";

		private static Type _runtime;

		private static MethodInfo _takeOver;

		private static MethodInfo _forNewCity;

		private static MethodInfo _seedFor;

		private static MethodInfo _afterInit;

		private static MethodInfo _setCurrent;

		private static FieldInfo _conflict;

		private static FieldInfo _fogHandler;

		private static FieldInfo _fogBase;

		private static string _saved;

		private static bool _swapped;

		public string Id => "lostcity";

		public string Name => "Lost City";

		public string Title => "LOST CITY";

		public bool Available
		{
			get
			{
				if (_takeOver != null && _forNewCity != null && _seedFor != null && _afterInit != null)
				{
					return _setCurrent != null;
				}
				return false;
			}
		}

		public LostCityBiome(Harmony harmony)
		{
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_01ac: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("Tobeyyy.LostCity", out var value) && !((Object)(object)value.Instance == (Object)null))
			{
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				_runtime = assembly.GetType("LostCity.Game.CityRuntime");
				Type type = assembly.GetType("LostCity.Game.SessionRules");
				_takeOver = AccessTools.Method(_runtime, "TakeOver", (Type[])null, (Type[])null);
				_forNewCity = AccessTools.Method(type, "ForNewCity", (Type[])null, (Type[])null);
				_seedFor = AccessTools.Method(assembly.GetType("LostCity.Game.Seeds"), "ForScene", (Type[])null, (Type[])null);
				_afterInit = AccessTools.Method(_runtime, "AfterInitializeMap", (Type[])null, (Type[])null);
				_setCurrent = AccessTools.PropertySetter(_runtime, "Current");
				_conflict = AccessTools.Field(assembly.GetType("LostCity.Plugin"), "ConflictingPlugin");
				Type type2 = assembly.GetType("LostCity.Game.FogPace");
				_fogHandler = AccessTools.Field(type2, "_handler");
				_fogBase = AccessTools.Field(type2, "_baseSpeed");
				MethodInfo methodInfo = AccessTools.Method(assembly.GetType("LostCity.Game.Handshake"), "Notice", (Type[])null, (Type[])null);
				if (_conflict != null && methodInfo != null)
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(LostCityBiome), "NoNoticeAboutUs", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				if (_conflict != null)
				{
					harmony.Patch((MethodBase)AccessTools.Method(_runtime, "OnSceneLoaded", (Type[])null, (Type[])null), new HarmonyMethod(typeof(LostCityBiome), "BeforeSceneLoaded", (Type[])null), new HarmonyMethod(typeof(LostCityBiome), "AfterSceneLoaded", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo2 = AccessTools.Method(assembly.GetType("LostCity.Game.HostWarp"), "Update", (Type[])null, (Type[])null);
				if (methodInfo2 != null)
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(LostCityBiome), "NoWarpInRuns", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				if (_fogHandler != null && _fogBase != null)
				{
					harmony.Patch((MethodBase)AccessTools.Method(type2, "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(LostCityBiome), "FogOnlyInTheCity", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static bool NoWarpInRuns()
		{
			return !RunDirector.Active;
		}

		private static void BeforeSceneLoaded(Scene scene)
		{
			if (PlanSync.WillRun(((Scene)(ref scene)).name))
			{
				_saved = (string)_conflict.GetValue(null);
				_conflict.SetValue(null, "BiomePicker");
				_swapped = true;
			}
		}

		private static bool NoNoticeAboutUs(string text)
		{
			if (!_swapped || text == null || !text.Contains("BiomePicker"))
			{
				return true;
			}
			Plugin.Log.LogInfo((object)"Lost City's \"is off\" notice kept off the screen: Lost City is a round of this run.");
			return false;
		}

		private static void AfterSceneLoaded()
		{
			if (_swapped)
			{
				_conflict.SetValue(null, _saved);
				_swapped = false;
			}
		}

		private static bool FogOnlyInTheCity(object __instance)
		{
			if (!RunDirector.Active)
			{
				return true;
			}
			if (RunDirector.CurrentRound?.Id == "lostcity")
			{
				return true;
			}
			object? value = _fogHandler.GetValue(__instance);
			OrbFogHandler val = (OrbFogHandler)((value is OrbFogHandler) ? value : null);
			if (val != null && (Object)(object)val != (Object)null)
			{
				float num = (float)_fogBase.GetValue(__instance);
				if (num > 0f && !Mathf.Approximately(val.speed, num))
				{
					val.speed = num;
				}
			}
			return false;
		}

		public IEnumerator Build(CustomStage st)
		{
			VariantPart today = st.Today;
			MapHandler map = st.Map;
			GameObject val = st.CopyToday(today.Unit);
			Transform transform = val.transform;
			transform.position += st.Offset;
			GameObject val2 = Variants.Find(val, Variants.Relative(today.Unit.transform, today.Parent.transform));
			GameObject val3 = Variants.Find(val, Variants.Relative(today.Unit.transform, today.Campfire.transform));
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				throw new InvalidOperationException("Lost City: the copy of today's slot misses its parts");
			}
			MapSegment val4 = map.segments[st.Slot];
			GameObject segmentParent = val4._segmentParent;
			GameObject segmentCampfire = val4._segmentCampfire;
			DayNightProfile dayNightProfile = val4._dayNightProfile;
			BiomeType biome = val4._biome;
			bool hasVariant = val4.hasVariant;
			val2.SetActive(true);
			val3.SetActive(true);
			val.SetActive(true);
			Physics.SyncTransforms();
			IDisposable disposable = st.ShoreAtStart();
			object obj2;
			try
			{
				val4._segmentParent = val2;
				val4._segmentCampfire = val3;
				val4._dayNightProfile = today.Sky;
				val4._biome = today.Biome;
				val4.hasVariant = false;
				object[] array = new object[1];
				object obj = _forNewCity.Invoke(null, array);
				if (array[0] is string text)
				{
					Plugin.Log.LogWarning((object)("Lost City: " + text));
				}
				if (obj == null)
				{
					throw new InvalidOperationException("Lost City has no rules in this lobby (the host has no Lost City)");
				}
				ulong num = (ulong)_seedFor.Invoke(null, new object[2]
				{
					((Scene)(ref st.Scene)).name,
					obj
				});
				obj2 = _takeOver.Invoke(null, new object[4] { st.Scene, map, num, obj });
				_setCurrent.Invoke(null, new object[1] { obj2 });
				_afterInit.Invoke(null, null);
			}
			finally
			{
				disposable.Dispose();
				val4._segmentParent = segmentParent;
				val4._segmentCampfire = segmentCampfire;
				val4._dayNightProfile = dayNightProfile;
				val4._biome = biome;
				val4.hasVariant = hasVariant;
			}
			GameObject val5 = (GameObject)AccessTools.Field(obj2.GetType(), "Root").GetValue(obj2);
			val5.transform.SetParent(val.transform, true);
			val5.SetActive(false);
			val3.SetActive(false);
			val.SetActive(false);
			((Object)val).name = "BiomePicker Lost City";
			st.Unit = val;
			st.Content = val5;
			st.EndCamp = val3;
			yield break;
		}

		public void Enter(Round r)
		{
		}

		public void Leave(Round r)
		{
		}
	}
	[HarmonyPatch]
	internal static class PlanSync
	{
		public const string RoomKey = "BiomePicker.plan";

		public static RunPlan Local
		{
			get
			{
				string text = Plugin.DevPlan?.Value;
				return RunPlan.Parse((!string.IsNullOrWhiteSpace(text)) ? text : Plugin.Plan.Value);
			}
		}

		public static RunPlan Room
		{
			get
			{
				if (!PhotonNetwork.InRoom)
				{
					return null;
				}
				if (!((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"BiomePicker.plan", out object value) || !(value is string text))
				{
					return null;
				}
				return RunPlan.Parse(text);
			}
		}

		public static void Save(RunPlan plan)
		{
			Plugin.Plan.Value = plan.Serialize();
			Publish(plan);
		}

		public static void Publish(RunPlan plan)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				PhotonNetwork.CurrentRoom.SetCustomProperties(new Hashtable { [(object)"BiomePicker.plan"] = plan.Serialize() }, (Hashtable)null, (WebFlags)null);
			}
		}

		public static bool WillRun(string scene)
		{
			if ((scene.StartsWith("Level_") || scene.Contains("Island")) && !RunSettings.isMiniRun && Plugin.ConflictingPlugin == null && Plugin.DevPlan?.Value != "off")
			{
				if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
				{
					return Room != null;
				}
				return true;
			}
			return false;
		}

		public static RunPlan ForIsland()
		{
			if (RunSettings.isMiniRun || Plugin.ConflictingPlugin != null || Plugin.DevPlan?.Value == "off")
			{
				return null;
			}
			if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient)
			{
				RunPlan local = Local;
				Publish(local);
				return local;
			}
			return Room;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(AirportCheckInKiosk), "LoadIslandMaster")]
		private static void BeforeIslandLoad()
		{
			Publish(Local);
		}
	}
	[HarmonyPatch]
	internal static class Resume
	{
		[Serializable]
		private sealed class Save
		{
			public string runId;

			public string scene;

			public string plan;

			public int round;
		}

		private static string FilePath => Path.Combine(Application.persistentDataPath, "biomepicker.quicksave.json");

		public static int PendingRound { get; private set; }

		public static RunPlan ForContinue(string scene)
		{
			PendingRound = 0;
			if (!Quicksave.ShouldUseSaveData || !File.Exists(FilePath))
			{
				return null;
			}
			try
			{
				Save save = JsonUtility.FromJson<Save>(File.ReadAllText(FilePath));
				if (save == null || save.scene != scene || save.runId != Quicksave.SavedRunId)
				{
					return null;
				}
				PendingRound = save.round;
				Plugin.Log.LogInfo((object)$"BiomePicker: continuing run {save.runId} at round {save.round} ({save.plan})");
				return RunPlan.Parse(save.plan);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("BiomePicker save unreadable: " + ex.Message));
				return null;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Quicksave), "SaveNow")]
		private static void AfterSave()
		{
			//IL_0044: 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)
			if (!RunDirector.Active || (Object)(object)RunManager.Instance == (Object)null)
			{
				return;
			}
			try
			{
				Save obj = new Save
				{
					runId = RunManager.Instance.RunId.ToString()
				};
				Scene scene = ((Component)Singleton<MapHandler>.Instance).gameObject.scene;
				obj.scene = ((Scene)(ref scene)).name;
				obj.plan = RunDirector.Plan?.Serialize();
				obj.round = RunDirector.Current;
				Save save = obj;
				File.WriteAllText(FilePath, JsonUtility.ToJson((object)save));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("BiomePicker save failed: " + ex.Message));
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MapHandler), "JumpToSegment")]
		private static bool BeforeJump(Segment segment)
		{
			if (PendingRound <= 0 || !RunDirector.Active || !PhotonNetwork.IsMasterClient)
			{
				return true;
			}
			int index = Mathf.Min(PendingRound, RoundTable.Rounds.Count - 1);
			PendingRound = 0;
			RunDirector.ContinueAt(index);
			return false;
		}
	}
	internal sealed class Round
	{
		public int Index;

		public BiomeEntry Entry;

		public Vector3 Offset;

		public Vector3 FogShift;

		public bool ToThePeak;

		public GameObject Unit;

		public GameObject Content;

		public GameObject EndCamp;

		public GameObject PartnerParent;

		public GameObject PartnerCamp;

		public Transform Statue;

		public DayNightProfile Sky;

		public BiomeType Biome;

		public LightVolume Light;

		public GameObject StartStatue;

		public bool SummitCamp;

		public List<Vector3> Platform;

		public float Sink;

		public bool BringsFloor;

		public List<Vector3> CampCells;

		public bool SummitGrounded;

		public bool Last;

		public readonly List<GameObject> Hide = new List<GameObject>();

		public string Source = "today";

		public ICustomBiome Custom;

		public int Island = -1;

		public bool FakeMountainOff;

		public string Id => Entry.Id;

		public int Slot => Entry.Slot;

		public string Title => Entry.Title;

		public override string ToString()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			string[] array = new string[7];
			object[] obj = new object[8]
			{
				Index,
				Id,
				Slot,
				ToThePeak ? " (up to the Peak)" : "",
				Source,
				Offset,
				null,
				null
			};
			GameObject unit = Unit;
			obj[6] = ((unit != null) ? ((Object)unit).name : null);
			GameObject content = Content;
			obj[7] = ((content != null) ? ((Object)content).name : null);
			array[0] = string.Format("#{0} {1} slot {2}{3} from {4}: lift {5:F1}, unit {6}, content {7}, ", obj);
			array[1] = "end ";
			GameObject endCamp = EndCamp;
			array[2] = ((endCamp != null) ? ((Object)endCamp).name : null) ?? "-";
			array[3] = ", sky ";
			DayNightProfile sky = Sky;
			array[4] = ((sky != null) ? ((Object)sky).name : null) ?? "-";
			array[5] = ", light ";
			array[6] = (((Object)(object)Light != (Object)null) ? "own" : "today's");
			return string.Concat(array);
		}
	}
	internal static class RoundTable
	{
		private sealed class PartPaths
		{
			public string Parent;

			public string Campfire;

			public DayNightProfile Sky;

			public static PartPaths Of(VariantPart p)
			{
				return new PartPaths
				{
					Parent = Variants.Relative(p.Unit.transform, p.Parent.transform),
					Campfire = (((Object)(object)p.Campfire != (Object)null) ? Variants.Relative(p.Unit.transform, p.Campfire.transform) : null),
					Sky = p.Sky
				};
			}
		}

		public static readonly List<Round> Rounds = new List<Round>();

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

		private static GameObject _noCamp;

		public static bool Ready { get; private set; }

		public static bool Busy { get; private set; }

		public static string Error { get; private set; }

		public static string Report { get; private set; } = "";

		public static void Clear()
		{
			Rounds.Clear();
			SlotUnits.Clear();
			Stack.Reset();
			StackPatches.Reset();
			Ready = false;
			Busy = false;
			Error = null;
			Report = "";
		}

		public static IEnumerator Build(RunPlan plan)
		{
			Clear();
			CopyFixups.Reset();
			Busy = true;
			StringBuilder log = new StringBuilder();
			Stopwatch sw = Stopwatch.StartNew();
			IEnumerator body = BuildBody(plan, Note);
			while (true)
			{
				bool flag;
				try
				{
					flag = body.MoveNext();
				}
				catch (Exception ex)
				{
					Error = ex.ToString();
					Plugin.Log.LogError((object)("BiomePicker could not set up the run, it plays as a normal run: " + ex));
					Rounds.Clear();
					break;
				}
				if (!flag)
				{
					break;
				}
				yield return body.Current;
			}
			Note(string.Format("set up in {0} ms: {1}", sw.ElapsedMilliseconds, (Error == null) ? (Rounds.Count + " rounds") : "FAILED"));
			Report = log.ToString();
			Ready = Error == null && Rounds.Count > 1;
			Busy = false;
			void Note(string s)
			{
				log.AppendLine(s);
				Plugin.Log.LogInfo((object)("[Rounds] " + s));
			}
		}

		private static IEnumerator BuildBody(RunPlan plan, Action<string> note)
		{
			MapHandler mh = Singleton<MapHandler>.Instance;
			Scene scene = ((Compo