Decompiled source of PLL Library v1.2.0

PLL_Library.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Peak.Network;
using Photon.Pun;
using Photon.Realtime;
using TerrainRandomiser;
using TerrainRandomiser.TerrainGeneration;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Aeralis Foundation")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Library for custom segments. (Works as an independent mod)")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+e8bed72db5b1ae204a6c57dde40e8c11fa9193e5")]
[assembly: AssemblyProduct("AF.PLL.Library")]
[assembly: AssemblyTitle("AF.PLL.Library")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Aurora-Aeralis/PLL_Library")]
[assembly: AssemblyVersion("1.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
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 PLL.Library
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "af.pll.library";

		public const string PLUGIN_NAME = "AF.PLL.Library";

		public const string PLUGIN_VERSION = "1.2.0";
	}
	public static class PLLLibrary
	{
		public const string PluginGuid = "af.pll.library";

		public const string PluginName = "AF.PLL.Library";

		public const string PluginVersion = "1.2.0";
	}
	[BepInPlugin("af.pll.library", "AF.PLL.Library", "1.2.0")]
	[BepInDependency("com.snosz.terrainrandomiser", "1.1.7")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public static ManualLogSource PLLLog { get; private set; }

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			PLLLog = ((BaseUnityPlugin)this).Logger;
			FileManager.Initialize(((BaseUnityPlugin)this).Info.Metadata);
			new Harmony("af.pll.library").PatchAll(typeof(Plugin).Assembly);
			PLLLog.LogInfo((object)"AF.PLL.Library 1.2.0 loaded.");
		}
	}
	public static class FileManager
	{
		private const string DefaultLayoutOrder = "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak";

		internal const string DefaultRepeatable = "Tropics > Roots > Alpine > Mesa > Caldera";

		internal const string DefaultChances = "1 > 1 > 1 > 1 > 1";

		private const int DefaultScale = 8;

		public static ConfigEntry<string> LayoutOrder { get; private set; }

		public static ConfigEntry<bool> DoOrder { get; private set; }

		public static ConfigEntry<bool> InfiniteMap { get; private set; }

		public static ConfigEntry<string> InfiniteMapRepeatable { get; private set; }

		public static ConfigEntry<string> InfiniteMapChances { get; private set; }

		public static ConfigEntry<int> InfiniteMapScale { get; private set; }

		public static ConfigEntry<int> InfiniteMapBeginIndex { get; private set; }

		public static ConfigEntry<bool> InfiniteMapRemoveOld { get; private set; }

		public static ConfigEntry<bool> Winnable { get; private set; }

		public static ConfigEntry<bool> PeakAtEnd { get; private set; }

		public static ConfigEntry<bool> WaterFollowsBeach { get; private set; }

		public static ConfigEntry<bool> RelocatePlane { get; private set; }

		public static ConfigEntry<bool> RelocateStart { get; private set; }

		public static ConfigEntry<bool> LazyGeneration { get; private set; }

		public static ConfigEntry<bool> LazyFeatures { get; private set; }

		public static ConfigEntry<bool> Fogless { get; private set; }

		public static ConfigEntry<bool> NoWater { get; private set; }

		public static ConfigEntry<bool> NoPlane { get; private set; }

		public static ConfigEntry<bool> RemoveOld { get; private set; }

		internal static void Initialize(BepInPlugin ownerMetadata)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(Paths.ConfigPath, "AF", "PLL_Library");
			string text2 = Path.Combine(text, "config.cfg");
			Directory.CreateDirectory(text);
			bool flag = File.Exists(text2);
			bool flag2 = flag && new ConfigFile(text2, false, ownerMetadata)
			{
				SaveOnConfigSet = false
			}.Bind<string>("Version", "LibraryVersion", string.Empty, (ConfigDescription)null).Value != "1.2.0";
			bool flag3 = !flag || TypeMatches(text2, "Version", "LibraryVersion", typeof(string).Name);
			bool flag4 = !flag || TypeMatches(text2, "Map", "LayoutOrder", typeof(string).Name);
			bool flag5 = !flag || TypeMatches(text2, "Map", "DoOrder", typeof(bool).Name);
			bool flag6 = !flag || TypeMatches(text2, "Map", "InfiniteMap", typeof(bool).Name);
			bool flag7 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Repeatable", typeof(string).Name);
			bool flag8 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Chances", typeof(string).Name);
			bool flag9 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Scale", typeof(int).Name);
			bool flag10 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Begin Index", typeof(int).Name);
			bool flag11 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Remove Old", typeof(bool).Name);
			bool flag12 = !flag || TypeMatches(text2, "Behaviors", "Winnable", typeof(bool).Name);
			bool flag13 = !flag || TypeMatches(text2, "Behaviors", "Peak at end", typeof(bool).Name);
			bool flag14 = !flag || TypeMatches(text2, "Behaviors", "Water follows Beach", typeof(bool).Name);
			bool flag15 = !flag || TypeMatches(text2, "Prerequisites", "Relocate Plane", typeof(bool).Name);
			bool flag16 = !flag || TypeMatches(text2, "Prerequisites", "Relocate Start", typeof(bool).Name);
			bool flag17 = !flag || TypeMatches(text2, "Optimizations", "Lazy Generation", typeof(bool).Name);
			bool flag18 = !flag || TypeMatches(text2, "Optimizations", "Lazy Features", typeof(bool).Name);
			bool flag19 = !flag || TypeMatches(text2, "Optimizations", "Fogless", typeof(bool).Name);
			bool flag20 = !flag || TypeMatches(text2, "Optimizations", "No Water", typeof(bool).Name);
			bool flag21 = !flag || TypeMatches(text2, "Optimizations", "No Plane", typeof(bool).Name);
			bool flag22 = !flag || TypeMatches(text2, "Optimizations", "Remove Old", typeof(bool).Name);
			bool flag23 = flag2 || !flag3 || !SchemaMatches(text2);
			flag23 = flag23 || !flag4 || !flag5 || !flag6 || !flag7 || !flag8 || !flag9 || !flag10 || !flag11 || !flag12 || !flag13 || !flag14 || !flag15 || !flag16 || !flag17 || !flag18 || !flag19 || !flag20 || !flag21 || !flag22;
			ConfigFile val = BindConfig(text2, ownerMetadata);
			if (!flag4)
			{
				LayoutOrder.Value = "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak";
			}
			if (!flag5)
			{
				DoOrder.Value = true;
			}
			if (!flag6)
			{
				InfiniteMap.Value = false;
			}
			if (!flag7)
			{
				InfiniteMapRepeatable.Value = "Tropics > Roots > Alpine > Mesa > Caldera";
			}
			if (!flag8)
			{
				InfiniteMapChances.Value = "1 > 1 > 1 > 1 > 1";
			}
			if (!flag9)
			{
				InfiniteMapScale.Value = 8;
			}
			if (!flag10)
			{
				InfiniteMapBeginIndex.Value = -1;
			}
			if (!flag11)
			{
				InfiniteMapRemoveOld.Value = false;
			}
			if (!flag12)
			{
				Winnable.Value = true;
			}
			if (!flag13)
			{
				PeakAtEnd.Value = false;
			}
			if (!flag14)
			{
				WaterFollowsBeach.Value = true;
			}
			if (!flag15)
			{
				RelocatePlane.Value = true;
			}
			if (!flag16)
			{
				RelocateStart.Value = true;
			}
			if (!flag17)
			{
				LazyGeneration.Value = true;
			}
			if (!flag18)
			{
				LazyFeatures.Value = false;
			}
			if (!flag19)
			{
				Fogless.Value = false;
			}
			if (!flag20)
			{
				NoWater.Value = false;
			}
			if (!flag21)
			{
				NoPlane.Value = false;
			}
			if (!flag22)
			{
				RemoveOld.Value = false;
			}
			if (flag23)
			{
				string value = LayoutOrder.Value;
				bool value2 = DoOrder.Value;
				bool value3 = InfiniteMap.Value;
				string value4 = InfiniteMapRepeatable.Value;
				string value5 = InfiniteMapChances.Value;
				int value6 = InfiniteMapScale.Value;
				int value7 = InfiniteMapBeginIndex.Value;
				bool value8 = InfiniteMapRemoveOld.Value;
				bool value9 = Winnable.Value;
				bool value10 = PeakAtEnd.Value;
				bool value11 = WaterFollowsBeach.Value;
				bool value12 = RelocatePlane.Value;
				bool value13 = RelocateStart.Value;
				bool value14 = LazyGeneration.Value;
				bool value15 = LazyFeatures.Value;
				bool value16 = Fogless.Value;
				bool value17 = NoWater.Value;
				bool value18 = NoPlane.Value;
				bool value19 = RemoveOld.Value;
				File.Delete(text2);
				val = BindConfig(text2, ownerMetadata);
				LayoutOrder.Value = value;
				DoOrder.Value = value2;
				InfiniteMap.Value = value3;
				InfiniteMapRepeatable.Value = value4;
				InfiniteMapChances.Value = value5;
				InfiniteMapScale.Value = value6;
				InfiniteMapBeginIndex.Value = value7;
				InfiniteMapRemoveOld.Value = value8;
				Winnable.Value = value9;
				PeakAtEnd.Value = value10;
				WaterFollowsBeach.Value = value11;
				RelocatePlane.Value = value12;
				RelocateStart.Value = value13;
				LazyGeneration.Value = value14;
				LazyFeatures.Value = value15;
				Fogless.Value = value16;
				NoWater.Value = value17;
				NoPlane.Value = value18;
				RemoveOld.Value = value19;
			}
			val.Save();
			val.SaveOnConfigSet = true;
		}

		private static ConfigFile BindConfig(string path, BepInPlugin ownerMetadata)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			ConfigFile val = new ConfigFile(path, false, ownerMetadata)
			{
				SaveOnConfigSet = false
			};
			val.Bind<string>("Version", "LibraryVersion", "1.2.0", "Tracks the PLL Library version.");
			LayoutOrder = val.Bind<string>("Map", "LayoutOrder", "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak", "Defines the map layout order; Peak is the structural attachment in Caldera > Volcano > Peak.");
			DoOrder = val.Bind<bool>("Map", "DoOrder", true, "Enables LayoutOrder for the map.");
			InfiniteMap = val.Bind<bool>("Map", "InfiniteMap", false, "Enables infinite map generation.");
			InfiniteMapRepeatable = val.Bind<string>("Fields", "InfiniteMap: Repeatable", "Tropics > Roots > Alpine > Mesa > Caldera", "Segment names eligible for repetition, separated by >.");
			InfiniteMapChances = val.Bind<string>("Fields", "InfiniteMap: Chances", "1 > 1 > 1 > 1 > 1", "Non-negative weights mapped by position to InfiniteMap: Repeatable, separated by >.");
			InfiniteMapScale = val.Bind<int>("Fields", "InfiniteMap: Scale", 8, new ConfigDescription("Total number of segments created by InfiniteMap.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 255), Array.Empty<object>()));
			InfiniteMapBeginIndex = val.Bind<int>("Fields", "InfiniteMap: Begin Index", -1, "-1 appends generated segments after the final zone; other values are clamped to a zero-based logical segment boundary.");
			InfiniteMapRemoveOld = val.Bind<bool>("Fields", "InfiniteMap: Remove Old", false, "Removes the default layout so only InfiniteMap: Repeatable segments are used.");
			Winnable = val.Bind<bool>("Behaviors", "Winnable", true, "Enables the configured final-zone win behavior.");
			PeakAtEnd = val.Bind<bool>("Behaviors", "Peak at end", false, "Places Peak at the end of the generated layout.");
			WaterFollowsBeach = val.Bind<bool>("Behaviors", "Water follows Beach", true, "Activates the water floor when Beach is reached; otherwise enables it beneath the first segment from the start.");
			RelocatePlane = val.Bind<bool>("Prerequisites", "Relocate Plane", true, "Relocates the crashed plane to the player start when the layout does not begin with Beach.");
			RelocateStart = val.Bind<bool>("Prerequisites", "Relocate Start", true, "Aligns the world start with the beginning of the first segment.");
			LazyGeneration = val.Bind<bool>("Optimizations", "Lazy Generation", true, "Defers procedural prop generation until its prerequisite zone is reached.");
			LazyFeatures = val.Bind<bool>("Optimizations", "Lazy Features", false, "Extends Lazy Generation by keeping future cloned feature components inactive until segment load. Generating more than six new segments without it may take over 10 minutes, especially due to lighting.");
			Fogless = val.Bind<bool>("Optimizations", "Fogless", false, "Disables the fog sphere and its relocation behavior.");
			NoWater = val.Bind<bool>("Optimizations", "No Water", false, "Disables Beach water and all water relocation behavior.");
			NoPlane = val.Bind<bool>("Optimizations", "No Plane", false, "Removes the crashed plane and its affiliates except spawn points.");
			RemoveOld = val.Bind<bool>("Optimizations", "Remove Old", false, "Destroys map zones older than the immediately previous zone after progression.");
			return val;
		}

		private static bool TypeMatches(string path, string section, string key, string expectedType)
		{
			string text = string.Empty;
			string text2 = string.Empty;
			foreach (string item in File.ReadLines(path))
			{
				string text3 = item.Trim();
				if (text3.StartsWith("[", StringComparison.Ordinal) && text3.EndsWith("]", StringComparison.Ordinal))
				{
					text = text3.Substring(1, text3.Length - 2);
					text2 = string.Empty;
					continue;
				}
				if (text3.StartsWith("# Setting type:", StringComparison.Ordinal))
				{
					text2 = text3.Substring("# Setting type:".Length).Trim();
					continue;
				}
				int num = text3.IndexOf('=');
				if (num >= 0 && !text3.StartsWith("#", StringComparison.Ordinal))
				{
					string text4 = text3.Substring(0, num).Trim();
					if (text == section && text4 == key)
					{
						string value = text3.Substring(num + 1).Trim();
						return text2 == expectedType && ValueMatches(value, expectedType);
					}
					text2 = string.Empty;
				}
			}
			return true;
		}

		private static bool SchemaMatches(string path)
		{
			if (!File.Exists(path))
			{
				return true;
			}
			string section = string.Empty;
			foreach (string item in File.ReadLines(path))
			{
				string text = item.Trim();
				if (text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal))
				{
					section = text.Substring(1, text.Length - 2);
					continue;
				}
				int num = text.IndexOf('=');
				if (num >= 0 && !text.StartsWith("#", StringComparison.Ordinal))
				{
					string key = text.Substring(0, num).Trim();
					if (!IsKnown(section, key))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static bool IsKnown(string section, string key)
		{
			if (!(section == "Version") || !(key == "LibraryVersion"))
			{
				if (section == "Map")
				{
					switch (key)
					{
					case "LayoutOrder":
					case "DoOrder":
					case "InfiniteMap":
						goto IL_0179;
					}
				}
				if (section == "Fields")
				{
					switch (key)
					{
					case "InfiniteMap: Repeatable":
					case "InfiniteMap: Chances":
					case "InfiniteMap: Scale":
					case "InfiniteMap: Begin Index":
					case "InfiniteMap: Remove Old":
						goto IL_0179;
					}
				}
				if (section == "Behaviors")
				{
					switch (key)
					{
					case "Winnable":
					case "Peak at end":
					case "Water follows Beach":
						goto IL_0179;
					}
				}
				if (!(section == "Prerequisites") || (!(key == "Relocate Plane") && !(key == "Relocate Start")))
				{
					if (section == "Optimizations")
					{
						switch (key)
						{
						default:
							return key == "Remove Old";
						case "Lazy Generation":
						case "Lazy Features":
						case "Fogless":
						case "No Water":
						case "No Plane":
							return true;
						}
					}
					return false;
				}
			}
			goto IL_0179;
			IL_0179:
			return true;
		}

		private static bool ValueMatches(string value, string expectedType)
		{
			if (!(expectedType == typeof(string).Name) && (!(expectedType == typeof(bool).Name) || !bool.TryParse(value, out var _)))
			{
				int result2;
				if (expectedType == typeof(int).Name)
				{
					return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result2);
				}
				return false;
			}
			return true;
		}
	}
	internal static class TerrainRandomizer
	{
		[HarmonyPatch(typeof(PropGrouperHelpers), "RunRootPropGrouper")]
		private static class GenerationPatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				Map.SuppressOriginals();
			}
		}

		[HarmonyPatch(typeof(LightMapBaker), "RunBake")]
		private static class LightMapPatch
		{
			[HarmonyPrefix]
			private static bool Prefix()
			{
				return featureGenerationDepth == 0;
			}
		}

		[HarmonyPatch]
		private static class LightSamplePatch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.DeclaredMethod(GameLightVolume, "SamplePosition", new Type[1] { typeof(Vector3) }, (Type[])null) ?? throw new MissingMethodException("LightVolume.SamplePosition was not found.");
			}

			[HarmonyPrefix]
			private static void Prefix(ref Vector3 worldPos)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				if (featureGenerationDepth != 0)
				{
					worldPos -= featureOffset;
				}
			}
		}

		[HarmonyPatch(typeof(PropSpawnerHelpers), "AssignMasterClientViewID")]
		private static class ViewIdPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(GameObject go, ref int __result)
			{
				if (roomViewIdDepth == 0 || PhotonNetwork.CurrentRoom == null || !PhotonNetwork.IsMasterClient)
				{
					return true;
				}
				PhotonView component = go.GetComponent<PhotonView>();
				if (!Object.op_Implicit((Object)(object)component) || !PhotonNetwork.AllocateRoomViewID(component) || component.ViewID <= 0)
				{
					throw new InvalidOperationException("A TerrainRandomiser PhotonView could not receive a room ViewID.");
				}
				__result = component.ViewID;
				return false;
			}
		}

		internal const string PluginGuid = "com.snosz.terrainrandomiser";

		internal const string PluginVersion = "1.1.7";

		internal const string ViewProperty = "propViews";

		private static int featureGenerationDepth;

		private static int roomViewIdDepth;

		private static Vector3 featureOffset;

		private static readonly Type GameLightVolume = typeof(MapHandler).Assembly.GetType("LightVolume") ?? throw new TypeLoadException("PEAK's LightVolume type was not found.");

		internal static Action<PropGrouper> GenerateSegmentFeatures { get; } = (Action<PropGrouper>)Delegate.CreateDelegate(typeof(Action<PropGrouper>), AccessTools.DeclaredMethod(typeof(PropGrouperHelpers), "RunRootPropGrouper", new Type[1] { typeof(PropGrouper) }, (Type[])null) ?? throw new MissingMethodException("TerrainRandomiser feature generation method was not found."));

		internal static void RunSegmentFeatures(PropGrouper grouper, Vector3 offset)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = featureOffset;
			featureOffset = offset;
			featureGenerationDepth++;
			roomViewIdDepth++;
			try
			{
				GenerateSegmentFeatures(grouper);
			}
			finally
			{
				PropGrouperHelpers.deferredSteps.Clear();
				roomViewIdDepth--;
				featureGenerationDepth--;
				featureOffset = val;
			}
		}

		internal static List<int> GetAndAssignAllUnassignedViews()
		{
			roomViewIdDepth++;
			try
			{
				return MapHandlerHelpers.GetAndAssignAllUnassignedViews();
			}
			finally
			{
				roomViewIdDepth--;
			}
		}
	}
	internal static class ConfigSync
	{
		[HarmonyPatch(typeof(AirportCheckInKiosk), "LoadIslandMaster")]
		private static class PublishPatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				if (NetCode.Session.IsHost && !LoadingScreenHandler.loading)
				{
					Publish();
				}
			}
		}

		private const string PropertyKey = "af.pll.library/c";

		internal const string StatePrefix = "af.pll.library/state/";

		private static object? publishedRoom;

		private static string? publishedPayload;

		private static string? publishedPreviousPayload;

		internal static string LayoutOrder { get; private set; } = string.Empty;

		internal static bool DoOrder { get; private set; }

		internal static bool InfiniteMap { get; private set; }

		internal static string Repeatable { get; private set; } = string.Empty;

		internal static string Chances { get; private set; } = string.Empty;

		internal static int Scale { get; private set; }

		internal static int BeginIndex { get; private set; }

		internal static bool RemoveOld { get; private set; }

		internal static bool Winnable { get; private set; }

		internal static bool PeakAtEnd { get; private set; }

		internal static bool WaterFollowsBeach { get; private set; }

		internal static bool RelocatePlane { get; private set; }

		internal static bool RelocateStart { get; private set; }

		internal static bool LazyGeneration { get; private set; }

		internal static bool LazyFeatures { get; private set; }

		internal static bool Fogless { get; private set; }

		internal static bool NoWater { get; private set; }

		internal static bool NoPlane { get; private set; }

		internal static bool RemoveOldZones { get; private set; }

		internal static string GenerationEpoch { get; private set; } = string.Empty;

		internal static void Publish()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (PhotonNetwork.OfflineMode || currentRoom == null || !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			LoadLocal();
			GenerationEpoch = Guid.NewGuid().ToString("N");
			string text = Serialize();
			publishedRoom = currentRoom;
			publishedPayload = text;
			publishedPreviousPayload = ((RoomInfo)currentRoom).CustomProperties[(object)"af.pll.library/c"] as string;
			Hashtable val = new Hashtable
			{
				[(object)"af.pll.library/c"] = text,
				[(object)"propViews"] = Array.Empty<int>()
			};
			foreach (object key in ((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).Keys)
			{
				if (key is string text2 && text2.StartsWith("af.pll.library/state/", StringComparison.Ordinal))
				{
					val[key] = Array.Empty<object>();
				}
			}
			if (currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null))
			{
				return;
			}
			publishedRoom = null;
			publishedPayload = null;
			publishedPreviousPayload = null;
			throw new InvalidOperationException("PLL Library could not publish the room configuration.");
		}

		internal static void Resolve()
		{
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (PhotonNetwork.OfflineMode || currentRoom == null)
			{
				LoadLocal();
				return;
			}
			if (PhotonNetwork.IsMasterClient && publishedRoom == currentRoom && publishedPayload != null)
			{
				string text = ((RoomInfo)currentRoom).CustomProperties[(object)"af.pll.library/c"] as string;
				if (text == publishedPayload || text == publishedPreviousPayload)
				{
					return;
				}
				publishedRoom = null;
				publishedPayload = null;
				publishedPreviousPayload = null;
			}
			if (!((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).TryGetValue((object)"af.pll.library/c", out object value) || !(value is string text2))
			{
				if (PhotonNetwork.IsMasterClient)
				{
					Publish();
					return;
				}
				throw Reject("The host did not publish a PLL Library room configuration.");
			}
			int offset = 0;
			if (!Read(text2, ref offset, out string value2) || !Read(text2, ref offset, out string value3) || !Read(text2, ref offset, out string value4) || !Read(text2, ref offset, out string value5) || !Read(text2, ref offset, out string value6) || !Read(text2, ref offset, out string value7) || !Read(text2, ref offset, out string value8) || !Read(text2, ref offset, out string value9) || !Read(text2, ref offset, out string value10) || !Read(text2, ref offset, out string value11) || !Read(text2, ref offset, out string value12) || !Read(text2, ref offset, out string value13) || !Read(text2, ref offset, out string value14) || !Read(text2, ref offset, out string value15) || !Read(text2, ref offset, out string value16) || !Read(text2, ref offset, out string value17) || !Read(text2, ref offset, out string value18) || !Read(text2, ref offset, out string value19) || !Read(text2, ref offset, out string value20) || !Read(text2, ref offset, out string value21) || !Read(text2, ref offset, out string value22) || offset != text2.Length || (value5 != "0" && value5 != "1") || (value6 != "0" && value6 != "1") || (value11 != "0" && value11 != "1") || (value12 != "0" && value12 != "1") || (value13 != "0" && value13 != "1") || (value14 != "0" && value14 != "1") || (value15 != "0" && value15 != "1") || (value16 != "0" && value16 != "1") || (value17 != "0" && value17 != "1") || (value18 != "0" && value18 != "1") || (value19 != "0" && value19 != "1") || (value20 != "0" && value20 != "1") || (value21 != "0" && value21 != "1") || (value22 != "0" && value22 != "1") || !Guid.TryParseExact(value3, "N", out var _) || !int.TryParse(value9, NumberStyles.None, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(value10, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) || result2 < 1 || result2 > 255)
			{
				throw Reject("The host published a malformed PLL Library room configuration.");
			}
			if (!string.Equals(value2, "1.2.0", StringComparison.Ordinal))
			{
				throw Reject("PLL Library version mismatch: host " + value2 + ", client 1.2.0.");
			}
			GenerationEpoch = value3;
			LayoutOrder = value4;
			DoOrder = value5 == "1";
			InfiniteMap = value6 == "1";
			Repeatable = value7;
			Chances = value8;
			Scale = result2;
			BeginIndex = result3;
			RemoveOld = value11 == "1";
			Winnable = value12 == "1";
			PeakAtEnd = value13 == "1";
			WaterFollowsBeach = value14 == "1";
			RelocatePlane = value15 == "1";
			RelocateStart = value16 == "1";
			LazyGeneration = value17 == "1";
			LazyFeatures = value18 == "1";
			Fogless = value19 == "1";
			NoWater = value20 == "1";
			NoPlane = value21 == "1";
			RemoveOldZones = value22 == "1";
		}

		private static string Serialize()
		{
			StringBuilder stringBuilder = new StringBuilder();
			Append(stringBuilder, "1.2.0");
			Append(stringBuilder, GenerationEpoch);
			Append(stringBuilder, LayoutOrder);
			Append(stringBuilder, DoOrder ? "1" : "0");
			Append(stringBuilder, InfiniteMap ? "1" : "0");
			Append(stringBuilder, Repeatable);
			Append(stringBuilder, Chances);
			Append(stringBuilder, Scale.ToString(CultureInfo.InvariantCulture));
			Append(stringBuilder, BeginIndex.ToString(CultureInfo.InvariantCulture));
			Append(stringBuilder, RemoveOld ? "1" : "0");
			Append(stringBuilder, Winnable ? "1" : "0");
			Append(stringBuilder, PeakAtEnd ? "1" : "0");
			Append(stringBuilder, WaterFollowsBeach ? "1" : "0");
			Append(stringBuilder, RelocatePlane ? "1" : "0");
			Append(stringBuilder, RelocateStart ? "1" : "0");
			Append(stringBuilder, LazyGeneration ? "1" : "0");
			Append(stringBuilder, LazyFeatures ? "1" : "0");
			Append(stringBuilder, Fogless ? "1" : "0");
			Append(stringBuilder, NoWater ? "1" : "0");
			Append(stringBuilder, NoPlane ? "1" : "0");
			Append(stringBuilder, RemoveOldZones ? "1" : "0");
			return stringBuilder.ToString();
		}

		private static void LoadLocal()
		{
			LayoutOrder = FileManager.LayoutOrder.Value;
			DoOrder = FileManager.DoOrder.Value;
			InfiniteMap = FileManager.InfiniteMap.Value;
			Repeatable = FileManager.InfiniteMapRepeatable.Value;
			Chances = FileManager.InfiniteMapChances.Value;
			Scale = FileManager.InfiniteMapScale.Value;
			BeginIndex = FileManager.InfiniteMapBeginIndex.Value;
			RemoveOld = FileManager.InfiniteMapRemoveOld.Value;
			Winnable = FileManager.Winnable.Value;
			PeakAtEnd = FileManager.PeakAtEnd.Value;
			WaterFollowsBeach = FileManager.WaterFollowsBeach.Value;
			RelocatePlane = FileManager.RelocatePlane.Value;
			RelocateStart = FileManager.RelocateStart.Value;
			LazyGeneration = FileManager.LazyGeneration.Value;
			LazyFeatures = FileManager.LazyFeatures.Value;
			Fogless = FileManager.Fogless.Value;
			NoWater = FileManager.NoWater.Value;
			NoPlane = FileManager.NoPlane.Value;
			RemoveOldZones = FileManager.RemoveOld.Value;
		}

		private static void Append(StringBuilder result, string value)
		{
			result.Append(value.Length.ToString(CultureInfo.InvariantCulture)).Append(':').Append(value);
		}

		private static bool Read(string data, ref int offset, out string value)
		{
			value = string.Empty;
			int num = data.IndexOf(':', offset);
			if (num <= offset || !int.TryParse(data.AsSpan(offset, num - offset), NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 0 || result > data.Length - num - 1)
			{
				return false;
			}
			offset = num + 1;
			value = data.Substring(offset, result);
			offset += result;
			return true;
		}

		private static Exception Reject(string message)
		{
			PhotonNetwork.Disconnect();
			return new InvalidOperationException(message);
		}

		internal static void OnMasterClientSwitched()
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				publishedRoom = null;
				publishedPayload = null;
				publishedPreviousPayload = null;
			}
		}
	}
	internal static class InfiniteMap
	{
		private sealed class Choice
		{
			internal LayoutOrder.Source Source { get; }

			internal double Weight { get; }

			internal Choice(LayoutOrder.Source source, double weight)
			{
				Source = source;
				Weight = weight;
			}
		}

		private sealed class FastRandom
		{
			private uint state;

			internal FastRandom(uint seed)
			{
				state = seed;
			}

			internal double NextDouble()
			{
				uint num = state;
				num ^= num << 13;
				num ^= num >> 17;
				return (double)((state = num ^ (num << 5)) >> 8) * 5.960464477539063E-08;
			}
		}

		internal static List<LayoutOrder.Source> Apply(Dictionary<string, LayoutOrder.Source> catalog, List<LayoutOrder.Source> layout)
		{
			if (!ConfigSync.InfiniteMap)
			{
				if (ConfigSync.PeakAtEnd)
				{
					LayoutOrder.EnsureTerminalPeak(catalog, layout);
				}
				return layout;
			}
			List<Choice> list = CreateChoices(catalog, ConfigSync.Repeatable, ConfigSync.Chances);
			if (list.Count == 0)
			{
				Plugin.PLLLog.LogWarning((object)"InfiniteMap: Repeatable had no valid segments; the default repeatable segments were used.");
				list = CreateChoices(catalog, "Tropics > Roots > Alpine > Mesa > Caldera", "1 > 1 > 1 > 1 > 1");
			}
			if (list.Count == 0 && !ConfigSync.PeakAtEnd)
			{
				return layout;
			}
			int num = Math.Max((!ConfigSync.PeakAtEnd) ? 1 : 2, Math.Min(ConfigSync.Scale, 255));
			List<LayoutOrder.Source> list2 = (ConfigSync.RemoveOld ? new List<LayoutOrder.Source>(num + 1) : new List<LayoutOrder.Source>(layout));
			if (ConfigSync.PeakAtEnd)
			{
				LayoutOrder.EnsureTerminalPeak(catalog, list2, num);
			}
			else
			{
				Trim(list2, num);
			}
			if (list.Count == 0)
			{
				return list2;
			}
			int num2 = InsertionIndex(list2, ConfigSync.BeginIndex, ConfigSync.PeakAtEnd);
			FastRandom random = new FastRandom(CreateSeed(list));
			for (int i = SegmentCount(list2); i < num; i++)
			{
				list2.Insert(num2++, Select(list, random));
			}
			return list2;
		}

		private static int InsertionIndex(IReadOnlyList<LayoutOrder.Source> layout, int requested, bool terminalPeak)
		{
			int num = (terminalPeak ? TerminalGroupStart(layout) : (-1));
			if (num < 0)
			{
				num = layout.Count;
			}
			if (num > 0 && layout[num - 1].Name == "Volcano")
			{
				num--;
			}
			if (requested == -1)
			{
				return num;
			}
			requested = Math.Max(0, requested);
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				if (num2 >= requested)
				{
					return i;
				}
				if (IsGroup(layout, i))
				{
					num2 += 2;
					i += 2;
					if (num2 >= requested)
					{
						return i + 1;
					}
				}
				else if (!layout[i].IsAttachment)
				{
					num2++;
				}
			}
			return num;
		}

		private static List<Choice> CreateChoices(Dictionary<string, LayoutOrder.Source> catalog, string repeatable, string chances)
		{
			string[] array = LayoutOrder.Split(repeatable);
			string[] array2 = LayoutOrder.Split(chances);
			double[] array3 = new double[array.Length];
			bool flag = array.Length != 0 && array.Length == array2.Length;
			double num = 0.0;
			if (flag)
			{
				for (int i = 0; i < array2.Length && double.TryParse(array2[i].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out array3[i]) && array3[i] >= 0.0 && !double.IsInfinity(array3[i]); i++)
				{
					num = Math.Max(num, array3[i]);
				}
				flag = num > 0.0;
			}
			if (!flag)
			{
				Plugin.PLLLog.LogWarning((object)"InfiniteMap: Chances must contain one finite non-negative weight per repeatable segment, with at least one positive value; equal weights were used.");
			}
			List<Choice> list = new List<Choice>(array.Length);
			for (int j = 0; j < array.Length; j++)
			{
				if (LayoutOrder.TryGet(catalog, array[j], out LayoutOrder.Source source))
				{
					if (source.IsAttachment)
					{
						Plugin.PLLLog.LogWarning((object)("Attachment '" + source.Name + "' cannot be repeated and was ignored."));
						continue;
					}
					if (source.Name.Equals("Volcano", StringComparison.OrdinalIgnoreCase))
					{
						Plugin.PLLLog.LogWarning((object)"Volcano cannot be repeated without its singleton Peak attachment and was ignored.");
						continue;
					}
					if (!Object.op_Implicit((Object)(object)source.SegmentCampfire))
					{
						Plugin.PLLLog.LogWarning((object)("Terminal segment '" + source.Name + "' cannot be repeated and was ignored."));
						continue;
					}
					double num2 = (flag ? (array3[j] / num) : 1.0);
					if (num2 > 0.0)
					{
						list.Add(new Choice(source, num2));
					}
				}
				else
				{
					Plugin.PLLLog.LogWarning((object)("Unknown repeatable segment '" + array[j].Trim() + "' was ignored."));
				}
			}
			return list;
		}

		private static void Trim(List<LayoutOrder.Source> layout, int target)
		{
			if (SegmentCount(layout) <= target)
			{
				return;
			}
			int num = TerminalGroupStart(layout);
			if (num >= 0 && target >= 2)
			{
				List<LayoutOrder.Source> list = new List<LayoutOrder.Source>(target + 1);
				int num2 = target - 2;
				for (int i = 0; i < num; i++)
				{
					if (num2 <= 0)
					{
						break;
					}
					if (IsGroup(layout, i))
					{
						if (num2 < 2)
						{
							break;
						}
						list.Add(layout[i]);
						list.Add(layout[i + 1]);
						list.Add(layout[i + 2]);
						num2 -= 2;
						i += 2;
					}
					else
					{
						LayoutOrder.Source source = layout[i];
						if (!source.IsAttachment)
						{
							list.Add(source);
							num2--;
						}
					}
				}
				list.Add(layout[num]);
				list.Add(layout[num + 1]);
				list.Add(layout[num + 2]);
				layout.Clear();
				layout.AddRange(list);
				NormalizeAttachments(layout);
				return;
			}
			int num3 = 0;
			int j;
			for (j = 0; j < layout.Count; j++)
			{
				if (num3 >= target)
				{
					break;
				}
				if (!layout[j].IsAttachment)
				{
					num3++;
				}
			}
			if (j > 0 && IsGroup(layout, j - 1))
			{
				j--;
			}
			if (j < layout.Count && layout[j].IsAttachment && IsGroup(layout, j - 2))
			{
				j++;
			}
			if (j < layout.Count)
			{
				layout.RemoveRange(j, layout.Count - j);
			}
			NormalizeAttachments(layout);
		}

		private static int SegmentCount(IEnumerable<LayoutOrder.Source> layout)
		{
			int num = 0;
			foreach (LayoutOrder.Source item in layout)
			{
				if (!item.IsAttachment)
				{
					num++;
				}
			}
			return num;
		}

		private static int TerminalGroupStart(IReadOnlyList<LayoutOrder.Source> layout)
		{
			if (layout.Count < 3 || !layout[layout.Count - 1].IsAttachment || !IsGroup(layout, layout.Count - 3))
			{
				return -1;
			}
			return layout.Count - 3;
		}

		private static bool IsGroup(IReadOnlyList<LayoutOrder.Source> layout, int index)
		{
			if (index >= 0 && index + 2 < layout.Count && layout[index].Name == "Caldera" && layout[index + 1].Name == "Volcano")
			{
				return layout[index + 2].IsAttachment;
			}
			return false;
		}

		private static void NormalizeAttachments(List<LayoutOrder.Source> layout)
		{
			for (int i = 0; i < layout.Count; i++)
			{
				if (layout[i].IsAttachment && !IsGroup(layout, i - 2))
				{
					layout.RemoveAt(i--);
				}
			}
		}

		private static LayoutOrder.Source Select(List<Choice> choices, FastRandom random)
		{
			double num = 0.0;
			foreach (Choice choice in choices)
			{
				num += choice.Weight;
			}
			double num2 = random.NextDouble() * num;
			foreach (Choice choice2 in choices)
			{
				num2 -= choice2.Weight;
				if (num2 < 0.0)
				{
					return choice2.Source;
				}
			}
			return choices[choices.Count - 1].Source;
		}

		private static uint CreateSeed(IEnumerable<Choice> choices)
		{
			LevelGeneration val = Object.FindAnyObjectByType<LevelGeneration>();
			int num = Plugin.Instance?.roomMapSettings?.seed ?? (Object.op_Implicit((Object)(object)val) ? val.seed : 0);
			uint num2 = (uint)(-2128831035 ^ num);
			foreach (Choice choice in choices)
			{
				num2 = Hash(num2, choice.Source.Name.ToUpperInvariant());
				num2 = Hash(num2, choice.Weight.ToString("R", CultureInfo.InvariantCulture));
			}
			num2 = (num2 ^ (uint)ConfigSync.Scale) * 16777619;
			if (num2 != 0)
			{
				return num2;
			}
			return 2654435769u;
		}

		private static uint Hash(uint hash, string value)
		{
			foreach (char c in value)
			{
				hash = (hash ^ c) * 16777619;
			}
			return hash;
		}
	}
	internal static class LayoutOrder
	{
		internal sealed class Source
		{
			private readonly Vector3? fixedEnd;

			internal string Name { get; }

			internal Segment Role { get; }

			internal BiomeType Biome { get; }

			internal GameObject SegmentParent { get; }

			internal GameObject? SegmentCampfire { get; }

			internal GameObject? WallNext { get; }

			internal GameObject? WallPrevious { get; }

			internal Transform? ReconnectSpawnPos { get; }

			internal DayNightProfile? DayNightProfile { get; }

			internal Transform Container { get; }

			internal bool IsAttachment { get; }

			internal Vector3 Start { get; set; }

			internal Vector3? BoundaryEnd { get; set; }

			internal Vector3 End
			{
				get
				{
					//IL_0072: Unknown result type (might be due to invalid IL or missing references)
					//IL_006a: Unknown result type (might be due to invalid IL or missing references)
					//IL_0062: Unknown result type (might be due to invalid IL or missing references)
					//IL_0051: Unknown result type (might be due to invalid IL or missing references)
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					Vector3? val = fixedEnd;
					if (!val.HasValue)
					{
						Vector3? boundaryEnd = BoundaryEnd;
						if (!boundaryEnd.HasValue)
						{
							if (!Object.op_Implicit((Object)(object)SegmentCampfire))
							{
								if (!Object.op_Implicit((Object)(object)ReconnectSpawnPos))
								{
									return SegmentParent.transform.position;
								}
								return ReconnectSpawnPos.position;
							}
							return SegmentCampfire.transform.position;
						}
						return boundaryEnd.GetValueOrDefault();
					}
					return val.GetValueOrDefault();
				}
			}

			internal Source(string name, Segment role, MapSegment segment)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				Name = name;
				Role = role;
				Biome = RawBiome.Invoke(segment);
				SegmentParent = RawParent.Invoke(segment);
				SegmentCampfire = RawCampfire.Invoke(segment);
				WallNext = segment.wallNext;
				WallPrevious = segment.wallPrevious;
				ReconnectSpawnPos = segment.reconnectSpawnPos;
				DayNightProfile = RawDayNight.Invoke(segment);
				Container = SegmentParent.transform.parent ?? SegmentParent.transform;
			}

			internal Source(Source volcano, Transform peak, Transform reconnect)
			{
				//IL_0013: 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_001f: 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)
				Name = "Peak";
				Role = (Segment)5;
				Biome = volcano.Biome;
				SegmentParent = ((Component)peak).gameObject;
				SegmentCampfire = null;
				WallNext = null;
				WallPrevious = null;
				ReconnectSpawnPos = reconnect;
				DayNightProfile = volcano.DayNightProfile;
				Container = volcano.Container;
				IsAttachment = true;
				fixedEnd = peak.position;
			}
		}

		private const string DefaultOrder = "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak";

		private static readonly string[] BaseNames = new string[5] { "Beach", "Tropics", "Alpine", "Caldera", "Volcano" };

		internal static readonly FieldRef<MapSegment, BiomeType> RawBiome = AccessTools.FieldRefAccess<MapSegment, BiomeType>("_biome");

		internal static readonly FieldRef<MapSegment, GameObject> RawParent = AccessTools.FieldRefAccess<MapSegment, GameObject>("_segmentParent");

		internal static readonly FieldRef<MapSegment, GameObject> RawCampfire = AccessTools.FieldRefAccess<MapSegment, GameObject>("_segmentCampfire");

		internal static readonly FieldRef<MapSegment, DayNightProfile> RawDayNight = AccessTools.FieldRefAccess<MapSegment, DayNightProfile>("_dayNightProfile");

		internal unsafe static Dictionary<string, Source> CreateCatalog(MapHandler handler)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Expected I4, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Source> dictionary = new Dictionary<string, Source>(StringComparer.OrdinalIgnoreCase);
			Source[] array = new Source[BaseNames.Length];
			for (int i = 0; i < Math.Min(handler.segments.Length, BaseNames.Length); i++)
			{
				Source source = new Source(BaseNames[i], (Segment)(byte)i, handler.segments[i]);
				dictionary.Add(source.Name, source);
				array[i] = source;
			}
			MapSegment[] variantSegments = handler.variantSegments;
			foreach (MapSegment val in variantSegments)
			{
				BiomeType val2 = RawBiome.Invoke(val);
				int num = -1;
				for (int k = 0; k < handler.segments.Length; k++)
				{
					if (handler.segments[k].hasVariant && handler.segments[k].variantBiome == val2)
					{
						num = k;
						break;
					}
				}
				if (num >= 0 && num <= 255)
				{
					string text = ((object)(*(BiomeType*)(&val2))/*cast due to .constrained prefix*/).ToString();
					if (!dictionary.ContainsKey(text))
					{
						dictionary.Add(text, new Source(text, (Segment)(byte)num, val));
					}
				}
			}
			if (!dictionary.TryGetValue("Volcano", out var value) || !Object.op_Implicit((Object)(object)handler.respawnThePeak))
			{
				throw new InvalidOperationException("PEAK's Volcano or Peak attachment was not found.");
			}
			dictionary["Peak"] = new Source(value, FindPeak(value.Container), handler.respawnThePeak);
			Vector3 val3 = ((handler.segments.Length != 0 && Object.op_Implicit((Object)(object)handler.segments[0].reconnectSpawnPos)) ? handler.segments[0].reconnectSpawnPos.position : (Object.op_Implicit((Object)(object)handler.globalParent) ? handler.globalParent.position : ((Component)handler).transform.position));
			foreach (Source value2 in dictionary.Values)
			{
				int num2 = (int)value2.Role;
				Source source2 = ((num2 >= 0 && num2 < array.Length) ? array[num2] : null);
				value2.Start = (Object.op_Implicit((Object)(object)source2?.ReconnectSpawnPos) ? source2.ReconnectSpawnPos.position : val3);
				Source source3 = ((num2 + 1 < array.Length) ? array[num2 + 1] : null);
				value2.BoundaryEnd = (Object.op_Implicit((Object)(object)source3?.ReconnectSpawnPos) ? new Vector3?(source3.ReconnectSpawnPos.position) : ((Vector3?)null));
			}
			return dictionary;
		}

		internal static List<Source> Resolve(Dictionary<string, Source> catalog, string value)
		{
			List<Source> list = ResolveCore(catalog, value);
			if (!HasSegments(list))
			{
				list = ResolveCore(catalog, "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak");
			}
			Limit(list);
			return list;
		}

		internal static string[] Split(string value)
		{
			return value.Split(new char[1] { '>' }, StringSplitOptions.RemoveEmptyEntries);
		}

		internal static bool TryGet(Dictionary<string, Source> catalog, string value, out Source source)
		{
			string text = value.Trim();
			if (text.Equals("Shore", StringComparison.OrdinalIgnoreCase))
			{
				text = "Beach";
			}
			else if (text.Equals("Kiln", StringComparison.OrdinalIgnoreCase) || text.Equals("The Kiln", StringComparison.OrdinalIgnoreCase) || text.Equals("TheKiln", StringComparison.OrdinalIgnoreCase))
			{
				text = "Volcano";
			}
			return catalog.TryGetValue(text, out source);
		}

		internal static void EnsureTerminalPeak(Dictionary<string, Source> catalog, List<Source> layout, int segmentLimit = 255)
		{
			if (!catalog.TryGetValue("Caldera", out Source value) || !catalog.TryGetValue("Volcano", out Source value2) || !catalog.TryGetValue("Peak", out Source value3))
			{
				throw new InvalidOperationException("PEAK's Caldera > Volcano > Peak group was not found.");
			}
			for (int num = layout.Count - 1; num >= 0; num--)
			{
				Source source = layout[num];
				if (source.IsAttachment || source.Name.Equals("Caldera", StringComparison.OrdinalIgnoreCase) || source.Name.Equals("Volcano", StringComparison.OrdinalIgnoreCase))
				{
					layout.RemoveAt(num);
				}
			}
			segmentLimit = Math.Max(2, Math.Min(segmentLimit, 255));
			int num2 = segmentLimit - 2;
			for (int i = 0; i < layout.Count; i++)
			{
				if (!layout[i].IsAttachment && num2-- <= 0)
				{
					layout.RemoveRange(i, layout.Count - i);
					break;
				}
			}
			layout.Add(value);
			layout.Add(value2);
			layout.Add(value3);
		}

		private static List<Source> ResolveCore(Dictionary<string, Source> catalog, string value)
		{
			List<Source> list = new List<Source>();
			Source source = null;
			Source source2 = null;
			string[] array = Split(value);
			foreach (string text in array)
			{
				if (!TryGet(catalog, text, out Source source3))
				{
					Plugin.PLLLog.LogWarning((object)("Unknown map segment '" + text.Trim() + "' was ignored."));
					source = (source2 = null);
				}
				else if (source3.IsAttachment)
				{
					if (source?.Name == "Caldera" && source2?.Name == "Volcano")
					{
						list.Add(source3);
					}
					else
					{
						Plugin.PLLLog.LogWarning((object)"Peak was ignored because it must directly follow Caldera > Volcano.");
					}
					source = (source2 = null);
				}
				else
				{
					list.Add(source3);
					source = source2;
					source2 = source3;
				}
			}
			return list;
		}

		private static Transform FindPeak(Transform container)
		{
			Transform val = null;
			for (int i = 0; i < container.childCount; i++)
			{
				Transform child = container.GetChild(i);
				if (!(((Object)child).name != "Peak"))
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						throw new InvalidOperationException("PEAK's Volcano contains more than one Peak attachment.");
					}
					val = child;
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("PEAK's Volcano Peak attachment was not found.");
			}
			return val;
		}

		private static bool HasSegments(IEnumerable<Source> layout)
		{
			foreach (Source item in layout)
			{
				if (!item.IsAttachment)
				{
					return true;
				}
			}
			return false;
		}

		private static void Limit(List<Source> layout)
		{
			int num = 0;
			for (int i = 0; i < layout.Count; i++)
			{
				if (!layout[i].IsAttachment && ++num > 255)
				{
					layout.RemoveRange(i, layout.Count - i);
					break;
				}
			}
		}
	}
	internal static class Campfire
	{
		[HarmonyPatch(typeof(Campfire), "IsMiniRunEndingCampfire")]
		private static class MiniRunPatch
		{
			[HarmonyPostfix]
			private static void Postfix(Campfire __instance, ref bool __result)
			{
				if (Map.Active && TryGetSlot(__instance, out var _))
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(Campfire), "Light_Rpc")]
		private static class LightPatch
		{
			[HarmonyPrefix]
			private static void Prefix(Campfire __instance, ref bool updateSegment, out int __state)
			{
				__state = -1;
				if (!updateSegment || !Map.Active)
				{
					return;
				}
				if (!TryGetSlot(__instance, out var index) || index != Map.Index)
				{
					updateSegment = false;
					return;
				}
				Bind(__instance, index);
				if (Map.IsPeakGate(index) || Map.IsRunTerminal(index))
				{
					updateSegment = false;
				}
				__state = index;
			}

			[HarmonyPostfix]
			private static void Postfix(int __state)
			{
				if (__state >= 0 && Map.Active)
				{
					if (Map.IsRunTerminal(__state))
					{
						Map.OnFinalCampfireLit(__state);
					}
					else if (Map.Index == __state + 1)
					{
						Map.OnCampfireTransition(__state);
						Map.ActivateWater(__state + 1);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Campfire_Set_Segment), "ModifyObject")]
		private static class GeneratedCampfirePatch
		{
			[HarmonyPostfix]
			private static void Postfix(GameObject spawned)
			{
				if (!Map.Active || !Object.op_Implicit((Object)(object)spawned))
				{
					return;
				}
				Campfire[] componentsInChildren = spawned.GetComponentsInChildren<Campfire>(true);
				foreach (Campfire campfire in componentsInChildren)
				{
					if (TryGetSlot(campfire, out var index))
					{
						Bind(campfire, index);
					}
				}
			}
		}

		private static readonly Dictionary<Campfire, int> Slots = new Dictionary<Campfire, int>();

		internal static void Bind()
		{
			Slots.Clear();
			for (int i = 0; i < Map.Slots.Length; i++)
			{
				if (!Map.Slots[i].Released)
				{
					GameObject segmentCampfire = Map.Slots[i].Segment.segmentCampfire;
					if (Object.op_Implicit((Object)(object)segmentCampfire))
					{
						Bind(segmentCampfire, i);
					}
				}
			}
			for (int j = 0; j < Map.Slots.Length; j++)
			{
				if (!Map.Slots[j].Released)
				{
					GameObject segmentParent = Map.Slots[j].Segment.segmentParent;
					if (Object.op_Implicit((Object)(object)segmentParent))
					{
						Bind(segmentParent, j);
					}
				}
			}
		}

		internal static void Bind(int index)
		{
			if (index >= 0 && index < Map.Slots.Length && !Map.Slots[index].Released)
			{
				MapSegment segment = Map.Slots[index].Segment;
				if (Object.op_Implicit((Object)(object)segment.segmentCampfire))
				{
					Bind(segment.segmentCampfire, index);
				}
				if (Object.op_Implicit((Object)(object)segment.segmentParent))
				{
					Bind(segment.segmentParent, index);
				}
			}
		}

		private static void Bind(GameObject root, int index)
		{
			Campfire[] componentsInChildren = root.GetComponentsInChildren<Campfire>(true);
			foreach (Campfire campfire in componentsInChildren)
			{
				Bind(campfire, index);
			}
		}

		private static void Bind(Campfire campfire, int index)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (!Slots.ContainsKey(campfire))
			{
				Slots.Add(campfire, index);
				campfire.advanceToSegment = ((index + 1 < Map.Slots.Length) ? Map.Slots[index + 1].Role : Map.Slots[index].Role);
			}
		}

		private static bool TryGetSlot(Campfire campfire, out int index)
		{
			if (Slots.TryGetValue(campfire, out index))
			{
				return true;
			}
			if (!Map.TryGetSlot(campfire, out index))
			{
				return false;
			}
			Bind(campfire, index);
			return true;
		}
	}
	internal static class Effects
	{
		private readonly struct BoundsState
		{
			internal Bounds Inner { get; }

			internal Bounds Outer { get; }

			internal BoundsState(Bounds inner, Bounds outer)
			{
				//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)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				Inner = inner;
				Outer = outer;
			}
		}

		[HarmonyPatch(typeof(MapHandler), "InitializeMap")]
		private static class MapPatch
		{
			[HarmonyPrefix]
			[HarmonyPriority(801)]
			private static void Prefix()
			{
				CaptureManagers();
			}

			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix()
			{
				BindManagers();
			}
		}

		[HarmonyPatch(typeof(FogConfig), "SetFog")]
		private static class WeatherPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(FogConfig __instance)
			{
				if (!Map.Active)
				{
					ownedFog = null;
					return true;
				}
				FogConfig val = FogFor(SelectStorm());
				if ((Object)(object)val != (Object)(object)__instance)
				{
					return false;
				}
				ownedFog = __instance;
				return true;
			}
		}

		[HarmonyPatch(typeof(TerrainSplat), "Start")]
		private static class TerrainStartPatch
		{
			[HarmonyPostfix]
			private static void Postfix(TerrainSplat __instance)
			{
				terrainOwner = __instance;
				terrainStarted = true;
				terrainBound = Map.Active;
				terrainSlots = (Map.Active ? Map.Slots : Array.Empty<Map.Slot>());
			}
		}

		[HarmonyPatch(typeof(FogConfig), "Update")]
		private static class WeatherRestorePatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				if (!Map.Active && ownedFog != null)
				{
					RestoreWeather();
				}
			}
		}

		[HarmonyPatch(typeof(StormVisual), "OnDisable")]
		private static class WeatherDisablePatch
		{
			[HarmonyPostfix]
			private static void Postfix(StormVisual __instance)
			{
				if (Map.Active && !((Object)(object)FogConfig.currentFog != (Object)(object)FogFor(__instance)))
				{
					FogConfig.currentFog = null;
					ownedFog = null;
					Shader.SetGlobalFloat(WeatherBlend, 0f);
				}
			}
		}

		[HarmonyPatch(typeof(FogCutoutHandler), "OnEnable")]
		private static class CutoutEnablePatch
		{
			[HarmonyPostfix]
			private static void Postfix(FogCutoutHandler __instance)
			{
				if ((Object)(object)cutoutOwner != (Object)(object)__instance)
				{
					CaptureCutouts(__instance);
				}
				else if (!Map.Active && !Object.op_Implicit((Object)(object)cutoutRoot))
				{
					capturedCurrentCutout = CurrentCutout.Invoke(__instance);
					capturedCutoutIndex = __instance.index;
				}
				if (Map.Active)
				{
					BindCutouts(__instance, force: true);
				}
			}
		}

		[HarmonyPatch(typeof(FogCutoutHandler), "Update")]
		private static class CutoutUpdatePatch
		{
			[HarmonyPrefix]
			private static void Prefix(FogCutoutHandler __instance)
			{
				BindCutouts(__instance);
			}
		}

		[HarmonyPatch(typeof(SpecialDayManager), "Start")]
		private static class SpecialStartPatch
		{
			[HarmonyPostfix]
			private static void Postfix(SpecialDayManager __instance)
			{
				if ((Object)(object)specialOwner != (Object)(object)__instance)
				{
					CaptureSpecialDays(__instance);
				}
				if (Map.Active)
				{
					BindSpecialDays(__instance, force: true);
				}
			}
		}

		[HarmonyPatch(typeof(SpecialDayManager), "Update")]
		private static class SpecialUpdatePatch
		{
			[HarmonyPrefix]
			private static void Prefix(SpecialDayManager __instance)
			{
				BindSpecialDays(__instance);
			}
		}

		private static readonly FieldRef<StormVisual, FogConfig> StormFog = AccessTools.FieldRefAccess<StormVisual, FogConfig>("fogConfig");

		private static readonly FieldRef<FogCutoutHandler, FogCutoutZone> CurrentCutout = AccessTools.FieldRefAccess<FogCutoutHandler, FogCutoutZone>("currentCutoutZone");

		private static readonly Func<StormVisual?> SelectStorm = (Func<StormVisual>)Delegate.CreateDelegate(typeof(Func<StormVisual>), AccessTools.DeclaredMethod(typeof(Map), "SelectStorm", (Type[])null, (Type[])null) ?? throw new MissingMethodException("Map.SelectStorm was not found."));

		private static readonly int WeatherBlend = Shader.PropertyToID("_WeatherBlend");

		private static FogConfig? ownedFog;

		private static FogCutoutHandler? cutoutOwner;

		private static FogCutoutZone[] capturedCutouts = Array.Empty<FogCutoutZone>();

		private static FogCutoutZone? capturedCurrentCutout;

		private static int capturedCutoutIndex;

		private static int cutoutRevision = int.MinValue;

		private static GameObject? cutoutRoot;

		private static SpecialDayManager? specialOwner;

		private static SpecialDayZone[] capturedSpecialDays = Array.Empty<SpecialDayZone>();

		private static SpecialDayZone[] boundSpecialDays = Array.Empty<SpecialDayZone>();

		private static readonly Dictionary<SpecialDayZone, BoundsState> specialBounds = new Dictionary<SpecialDayZone, BoundsState>();

		private static int specialRevision = int.MinValue;

		private static TerrainSplat? terrainOwner;

		private static Map.Slot[] terrainSlots = Array.Empty<Map.Slot>();

		private static bool terrainStarted;

		private static bool terrainBound;

		private static FogConfig? FogFor(StormVisual? visual)
		{
			if (!Object.op_Implicit((Object)(object)visual))
			{
				return null;
			}
			FogConfig val = StormFog.Invoke(visual);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return ((Component)visual).GetComponentInParent<FogConfig>(true);
			}
			return val;
		}

		private static int Revision()
		{
			if (!Map.Active)
			{
				return 0;
			}
			int num = Map.Slots.Length;
			Map.Slot[] slots = Map.Slots;
			foreach (Map.Slot slot in slots)
			{
				num = (num * 397) ^ (Object.op_Implicit((Object)(object)slot.Container) ? ((Object)slot.Container).GetInstanceID() : 0);
				num = (num * 397) ^ (slot.Released ? 1 : 0);
				num = (num * 397) ^ ((Object.op_Implicit((Object)(object)slot.Container) && ((Component)slot.Container).gameObject.activeInHierarchy) ? 1 : 0);
				num = (num * 397) ^ (slot.FeaturesActivated ? 1 : 0);
				num = (num * 397) ^ (slot.Segment.segmentParent.activeInHierarchy ? 1 : 0);
				num = (num * 397) ^ ((Object.op_Implicit((Object)(object)slot.PeakAttachment) && ((Component)slot.PeakAttachment).gameObject.activeInHierarchy) ? 1 : 0);
			}
			return num;
		}

		private static void CaptureCutouts(FogCutoutHandler instance)
		{
			if (!((Object)(object)cutoutOwner == (Object)(object)instance) || capturedCutouts.Length == 0)
			{
				RestoreCutouts();
				cutoutOwner = instance;
				FogCutoutZone[] cutoutZones = instance.cutoutZones;
				capturedCutouts = ((cutoutZones != null && cutoutZones.Length > 0) ? ((FogCutoutZone[])instance.cutoutZones.Clone()) : Array.Empty<FogCutoutZone>());
				capturedCurrentCutout = CurrentCutout.Invoke(instance);
				capturedCutoutIndex = instance.index;
				cutoutRevision = int.MinValue;
			}
		}

		private static void BindCutouts(FogCutoutHandler instance, bool force = false)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected I4, but got Unknown
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cutoutOwner != (Object)(object)instance)
			{
				CaptureCutouts(instance);
			}
			if (!Map.Active)
			{
				RestoreCutouts();
				return;
			}
			int num = Revision();
			if ((!force && Object.op_Implicit((Object)(object)cutoutRoot) && cutoutRevision == num) || capturedCutouts.Length == 0)
			{
				return;
			}
			((MonoBehaviour)instance).StopAllCoroutines();
			if (Object.op_Implicit((Object)(object)cutoutRoot))
			{
				Object.DestroyImmediate((Object)(object)cutoutRoot);
			}
			cutoutRoot = new GameObject("PLL_FogCutouts");
			cutoutRoot.transform.SetParent(((Component)instance).transform, false);
			List<FogCutoutZone> list = new List<FogCutoutZone>(Map.Slots.Length);
			try
			{
				for (int i = 0; i < Map.Slots.Length; i++)
				{
					Map.Slot slot = Map.Slots[i];
					if (!slot.Released)
					{
						int num2 = (int)slot.Role;
						if (num2 < 0 || num2 >= capturedCutouts.Length || !Object.op_Implicit((Object)(object)capturedCutouts[num2]))
						{
							throw new InvalidOperationException("The " + slot.Source.Name + " fog cutout template was not found.");
						}
						GameObject val = Object.Instantiate<GameObject>(((Component)capturedCutouts[num2]).gameObject, cutoutRoot.transform, true);
						((Object)val).name = $"PLL_FogCutout_{i:D3}_{slot.Source.Name}";
						val.transform.position = ((Component)capturedCutouts[num2]).transform.position + slot.Offset;
						val.SetActive(true);
						list.Add(val.GetComponent<FogCutoutZone>());
					}
				}
				instance.cutoutZones = list.ToArray();
				if (list.Count != 0)
				{
					int j = 0;
					Character localCharacter = Character.localCharacter;
					if (Object.op_Implicit((Object)(object)localCharacter))
					{
						for (float z = localCharacter.Center.z; j + 1 < list.Count && z > ((Component)list[j]).transform.position.z + list[j].transitionPoint; j++)
						{
						}
					}
					instance.setFogCutoutZone(j);
					instance.index = Math.Min(j + 1, list.Count);
				}
				else
				{
					CurrentCutout.Invoke(instance) = null;
				}
				cutoutRevision = num;
			}
			catch
			{
				if (Object.op_Implicit((Object)(object)cutoutRoot))
				{
					Object.DestroyImmediate((Object)(object)cutoutRoot);
				}
				cutoutRoot = null;
				instance.cutoutZones = capturedCutouts;
				CurrentCutout.Invoke(instance) = capturedCurrentCutout;
				instance.index = capturedCutoutIndex;
				cutoutRevision = int.MinValue;
				throw;
			}
		}

		private static void RestoreCutouts()
		{
			FogCutoutHandler val = cutoutOwner;
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)cutoutRoot))
			{
				((MonoBehaviour)val).StopAllCoroutines();
				Object.DestroyImmediate((Object)(object)cutoutRoot);
				val.cutoutZones = capturedCutouts;
				CurrentCutout.Invoke(val) = capturedCurrentCutout;
				val.index = capturedCutoutIndex;
				if (((Behaviour)val).isActiveAndEnabled && Object.op_Implicit((Object)(object)capturedCurrentCutout))
				{
					int num = Array.IndexOf(capturedCutouts, capturedCurrentCutout);
					if (num >= 0)
					{
						val.setFogCutoutZone(num);
					}
					val.index = capturedCutoutIndex;
				}
			}
			else if (Object.op_Implicit((Object)(object)cutoutRoot))
			{
				Object.DestroyImmediate((Object)(object)cutoutRoot);
			}
			cutoutRoot = null;
			cutoutRevision = int.MinValue;
		}

		private static void CaptureSpecialDays(SpecialDayManager instance)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)specialOwner == (Object)(object)instance && capturedSpecialDays.Length != 0)
			{
				return;
			}
			SpecialDayZone[] zones = instance.zones;
			SpecialDayZone[] array = ((zones != null && zones.Length > 0) ? ((SpecialDayZone[])instance.zones.Clone()) : Object.FindObjectsByType<SpecialDayZone>((FindObjectsInactive)0, (FindObjectsSortMode)0));
			RestoreSpecialDays();
			specialOwner = instance;
			capturedSpecialDays = array;
			SpecialDayZone[] array2 = capturedSpecialDays;
			foreach (SpecialDayZone val in array2)
			{
				if (Object.op_Implicit((Object)(object)val) && !specialBounds.ContainsKey(val))
				{
					specialBounds.Add(val, new BoundsState(val.bounds, val.outerBounds));
				}
			}
			specialRevision = int.MinValue;
		}

		private static void BindSpecialDays(SpecialDayManager instance, bool force = false)
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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)
			if ((Object)(object)specialOwner != (Object)(object)instance)
			{
				CaptureSpecialDays(instance);
			}
			if (!Map.Active)
			{
				RestoreSpecialDays();
				return;
			}
			int num = Revision();
			if (!force && specialRevision == num)
			{
				return;
			}
			List<SpecialDayZone> list = new List<SpecialDayZone>();
			HashSet<int> hashSet = new HashSet<int>();
			HashSet<int> hashSet2 = new HashSet<int>();
			Map.Slot[] slots = Map.Slots;
			foreach (Map.Slot slot in slots)
			{
				Transform container = slot.Container;
				if (slot.Released || !Object.op_Implicit((Object)(object)container) || !hashSet.Add(((Object)container).GetInstanceID()))
				{
					continue;
				}
				SpecialDayZone[] componentsInChildren = ((Component)container).GetComponentsInChildren<SpecialDayZone>(true);
				foreach (SpecialDayZone val in componentsInChildren)
				{
					if (Object.op_Implicit((Object)(object)val) && ((Behaviour)val).isActiveAndEnabled && hashSet2.Add(((Object)val).GetInstanceID()))
					{
						if (!specialBounds.ContainsKey(val))
						{
							specialBounds.Add(val, new BoundsState(val.bounds, val.outerBounds));
						}
						Bounds bounds = val.bounds;
						((Bounds)(ref bounds)).center = ((Component)val).transform.position;
						val.bounds = bounds;
						Bounds outerBounds = val.outerBounds;
						((Bounds)(ref outerBounds)).center = ((Component)val).transform.position;
						((Bounds)(ref outerBounds)).size = ((Bounds)(ref bounds)).size + Vector3.one * val.blendSize;
						val.outerBounds = outerBounds;
						list.Add(val);
					}
				}
			}
			HashSet<int> hashSet3 = new HashSet<int>();
			foreach (SpecialDayZone item in list)
			{
				hashSet3.Add(((Object)item).GetInstanceID());
			}
			SpecialDayZone[] array = boundSpecialDays;
			foreach (SpecialDayZone val2 in array)
			{
				if (Object.op_Implicit((Object)(object)val2) && !hashSet3.Contains(((Object)val2).GetInstanceID()) && Object.op_Implicit((Object)(object)val2.specialLight))
				{
					((Behaviour)val2.specialLight).enabled = false;
				}
			}
			boundSpecialDays = list.ToArray();
			instance.zones = boundSpecialDays;
			specialRevision = num;
		}

		private static void RestoreSpecialDays()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			SpecialDayZone[] array = boundSpecialDays;
			foreach (SpecialDayZone val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.specialLight))
				{
					((Behaviour)val.specialLight).enabled = false;
				}
			}
			foreach (KeyValuePair<SpecialDayZone, BoundsState> specialBound in specialBounds)
			{
				if (Object.op_Implicit((Object)(object)specialBound.Key))
				{
					specialBound.Key.bounds = specialBound.Value.Inner;
					specialBound.Key.outerBounds = specialBound.Value.Outer;
				}
			}
			if (Object.op_Implicit((Object)(object)specialOwner))
			{
				specialOwner.zones = capturedSpecialDays;
			}
			boundSpecialDays = Array.Empty<SpecialDayZone>();
			specialBounds.Clear();
			specialRevision = int.MinValue;
		}

		private static void CaptureManagers()
		{
			FogCutoutHandler val = Object.FindAnyObjectByType<FogCutoutHandler>();
			if (Object.op_Implicit((Object)(object)val))
			{
				CaptureCutouts(val);
			}
			SpecialDayManager val2 = Object.FindAnyObjectByType<SpecialDayManager>();
			if (Object.op_Implicit((Object)(object)val2))
			{
				CaptureSpecialDays(val2);
			}
			CaptureTerrain();
		}

		private static void CaptureTerrain()
		{
			TerrainSplat val = Object.FindAnyObjectByType<TerrainSplat>();
			if (Object.op_Implicit((Object)(object)val) && !((Object)(object)terrainOwner == (Object)(object)val))
			{
				terrainOwner = val;
				terrainSlots = Array.Empty<Map.Slot>();
				terrainStarted = false;
				terrainBound = false;
			}
		}

		private static void BindTerrain()
		{
			if (!Map.Active)
			{
				RestoreTerrain();
				return;
			}
			CaptureTerrain();
			if (Object.op_Implicit((Object)(object)terrainOwner) && terrainStarted && terrainSlots != Map.Slots)
			{
				terrainOwner.Generate((BrushType)2);
				terrainSlots = Map.Slots;
				terrainBound = true;
			}
		}

		internal static void RefreshTerrain()
		{
			terrainSlots = Array.Empty<Map.Slot>();
			BindTerrain();
		}

		private static void RestoreTerrain()
		{
			if (Object.op_Implicit((Object)(object)terrainOwner) && terrainStarted && terrainBound)
			{
				terrainOwner.Generate((BrushType)2);
			}
			terrainSlots = Array.Empty<Map.Slot>();
			terrainBound = false;
		}

		private static void RestoreWeather()
		{
			if (ownedFog != null)
			{
				if ((Object)(object)FogConfig.currentFog == (Object)(object)ownedFog || !Object.op_Implicit((Object)(object)FogConfig.currentFog))
				{
					FogConfig.currentFog = null;
					Shader.SetGlobalFloat(WeatherBlend, 0f);
				}
				ownedFog = null;
			}
		}

		private static void BindManagers()
		{
			if (!Map.Active)
			{
				RestoreWeather();
			}
			BindTerrain();
			FogCutoutHandler val = (FogCutoutHandler)(Object.op_Implicit((Object)(object)cutoutOwner) ? ((object)cutoutOwner) : ((object)Object.FindAnyObjectByType<FogCutoutHandler>()));
			if (Object.op_Implicit((Object)(object)val))
			{
				BindCutouts(val, force: true);
			}
			SpecialDayManager val2 = (SpecialDayManager)(Object.op_Implicit((Object)(object)specialOwner) ? ((object)specialOwner) : ((object)Object.FindAnyObjectByType<SpecialDayManager>()));
			if (Object.op_Implicit((Object)(object)val2))
			{
				BindSpecialDays(val2, force: true);
			}
		}
	}
	internal static class Fog
	{
		[HarmonyPatch(typeof(OrbFogHandler), "Start")]
		private static class StartPatch
		{
			[HarmonyPostfix]
			private static void Postfix(OrbFogHandler __instance)
			{
				Apply(__instance);
			}
		}

		[HarmonyPatch(typeof(OrbFogHandler), "SetFogOrigin")]
		private static class OriginPatch
		{
			[HarmonyPrefix]
			private static void Prefix(OrbFogHandler __instance)
			{
				if ((Object)(object)owner == (Object)(object)__instance && Map.Active)
				{
					Origins.Invoke(__instance) = current;
				}
			}

			[HarmonyPostfix]
			private static void Postfix(OrbFogHandler __instance)
			{
				if ((Object)(object)owner == (Object)(object)__instance && Map.Active && ConfigSync.Fogless)
				{
					DisableSpheres(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(OrbFogHandler), "WaitForReveal")]
		private static class RevealPatch
		{
			[HarmonyPostfix]
			private static void Postfix(OrbFogHandler __instance, ref IEnumerator __result)
			{
				__result = FollowReveal(__instance, __result);
			}
		}

		private static readonly FieldRef<OrbFogHandler, FogSphereOrigin[]> Origins = AccessTools.FieldRefAccess<OrbFogHandler, FogSphereOrigin[]>("origins");

		private static readonly FieldRef<OrbFogHandler, FogSphere> Sphere = AccessTools.FieldRefAccess<OrbFogHandler, FogSphere>("sphere");

		private static OrbFogHandler? owner;

		private static FogSphereOrigin[] captured = Array.Empty<FogSphereOrigin>();

		private static FogSphereOrigin[] current = Array.Empty<FogSphereOrigin>();

		private static GameObject[] spheres = Array.Empty<GameObject>();

		private static bool[] sphereStates = Array.Empty<bool>();

		private static GameObject? root;

		internal static void Capture()
		{
			OrbFogHandler val = Object.FindAnyObjectByType<OrbFogHandler>();
			if (Object.op_Implicit((Object)(object)val))
			{
				owner = val;
				FogSphereOrigin[] array = Origins.Invoke(val);
				captured = ((array != null && array.Length > 0) ? ((FogSphereOrigin[])array.Clone()) : ((Component)((Component)val).transform.root).GetComponentsInChildren<FogSphereOrigin>());
				FogSphere[] componentsInChildren = ((Component)val).GetComponentsInChildren<FogSphere>(true);
				spheres = Array.ConvertAll(componentsInChildren, (FogSphere component) => ((Component)component).gameObject);
				sphereStates = Array.ConvertAll(spheres, (GameObject sphere) => sphere.activeSelf);
			}
		}

		internal static void Bind(MapHandler _, Map.Slot[] slots)
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			OrbFogHandler val = (OrbFogHandler)(Object.op_Implicit((Object)(object)owner) ? ((object)owner) : ((object)Object.FindAnyObjectByType<OrbFogHandler>()));
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			owner = val;
			if (captured.Length == 0)
			{
				Capture();
			}
			if (Object.op_Implicit((Object)(object)root))
			{
				Object.DestroyImmediate((Object)(object)root);
			}
			RestoreSpheres();
			if (ConfigSync.Fogless)
			{
				root = new GameObject("PLL_FoglessWall");
				root.transform.SetParent(((Component)val).transform.root, false);
				root.SetActive(false);
				current = Array.Empty<FogSphereOrigin>();
				Origins.Invoke(val) = current;
				foreach (Map.Slot slot in slots)
				{
					slot.Segment.wallNext = root;
					slot.Segment.wallPrevious = root;
				}
				if (Object.op_Implicit((Object)(object)Sphere.Invoke(val)))
				{
					val.SetFogOrigin(Map.Index);
					DisableSpheres(val);
				}
				return;
			}
			root = new GameObject("PLL_FogOrigins");
			root.transform.SetParent(((Component)val).transform.root, false);
			current = (FogSphereOrigin[])(object)new FogSphereOrigin[Math.Max(0, slots.Length - 1)];
			if (slots.Length == 1)
			{
				GameObject val2 = new GameObject("PLL_WallNext_000");
				val2.transform.SetParent(root.transform, false);
				val2.SetActive(false);
				slots[0].Segment.wallNext = val2;
			}
			GameObject[] array = (GameObject[])(object)new GameObject[current.Length];
			GameObject[] array2 = (GameObject[])(object)new GameObject[current.Length];
			try
			{
				for (int j = 0; j < current.Length; j++)
				{
					bool placed;
					FogSphereOrigin val3 = Template(slots[j], out placed);
					if (((Component)val3).gameObject.GetComponents<FogSphereOrigin>().Length != 1)
					{
						throw new InvalidOperationException("The " + slots[j].Source.Name + " fog origin is ambiguous.");
					}
					GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, root.transform, true);
					((Object)val4).name = $"PLL_FogOrigin_{j:D3}";
					if (!placed)
					{
						Transform transform = val4.transform;
						transform.position += slots[j].Offset;
					}
					val4.SetActive(true);
					current[j] = val4.GetComponent<FogSphereOrigin>();
					array[j] = Unique(val4.transform, "Fogwall_Next");
					array2[j] = Unique(val4.transform, "Fogwall_Prev");
				}
				for (int k = 0; k < current.Length; k++)
				{
					slots[k].Segment.wallNext = array[k];
					slots[k + 1].Segment.wallPrevious = array2[k];
				}
				Origins.Invoke(val) = current;
				if (Object.op_Implicit((Object)(object)Sphere.Invoke(val)))
				{
					val.SetFogOrigin(Map.Index);
				}
			}
			catch
			{
				if (Object.op_Implicit((Object)(object)root))
				{
					Object.DestroyImmediate((Object)(object)root);
				}
				Origins.Invoke(val) = captured;
				current = Array.Empty<FogSphereOrigin>();
				root = null;
				throw;
			}
		}

		private static FogSphereOrigin Template(Map.Slot slot, out bool placed)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected I4, but got Unknown
			FogSphereOrigin val = Ancestor(slot.Segment.wallNext);
			if (Object.op_Implicit((Object)(object)val))
			{
				placed = true;
				return val;
			}
			int num = (int)slot.Role;
			if (num >= 0 && num < captured.Length && Object.op_Implicit((Object)(object)captured[num]))
			{
				placed = false;
				return captured[num];
			}
			if (Object.op_Implicit((Object)(object)slot.PeakAttachment) && captured.Length != 0 && Object.op_Implicit((Object)(object)captured[captured.Length - 1]))
			{
				placed = false;
				return captured[captured.Length - 1];
			}
			throw new InvalidOperationException("The " + slot.Source.Name + " fog origin was not found.");
		}

		private static FogSphereOrigin? Ancestor(GameObject? wall)
		{
			if (!Object.op_Implicit((Object)(object)wall))
			{
				return null;
			}
			FogSphereOrigin val = null;
			Transform val2 = wall.transform;
			while (Object.op_Implicit((Object)(object)val2))
			{
				FogSphereOrigin[] components = ((Component)val2).GetComponents<FogSphereOrigin>();
				if (components.Length > 1 || (components.Length == 1 && Object.op_Implicit((Object)(object)val)))
				{
					throw new InvalidOperationException("The fog origin above " + ((Object)wall).name + " is ambiguous.");
				}
				if (components.Length == 1)
				{
					val = components[0];
				}
				val2 = val2.parent;
			}
			return val;
		}

		private static GameObject Unique(Transform hierarchy, string name)
		{
			Transform val = null;
			Transform[] componentsInChildren = ((Component)hierarchy).GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren)
			{
				if (!(((Object)val2).name != name))
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						throw new InvalidOperationException("The fog hierarchy contains more than one " + name + ".");
					}
					val = val2;
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("The fog hierarchy contains no " + name + ".");
			}
			return ((Component)val).gameObject;
		}

		internal static void Restore()
		{
			if (Object.op_Implicit((Object)(object)root))
			{
				Object.DestroyImmediate((Object)(object)root);
			}
			if (Object.op_Implicit((Object)(object)owner))
			{
				Origins.Invoke(owner) = captured;
			}
			RestoreSpheres();
			current = Array.Empty<FogSphereOrigin>();
			root = null;
		}

		private static void DisableSpheres(OrbFogHandler instance)
		{
			GameObject[] array = spheres;
			foreach (GameObject val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)((Component)instance).gameObject)
				{
					val.SetActive(false);
				}
			}
		}

		private static void RestoreSpheres()
		{
			for (int i = 0; i < spheres.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)spheres[i]))
				{
					spheres[i].SetActive(sphereStates[i]);
				}
			}
		}

		private static void Apply(OrbFogHandler instance)
		{
			if ((Object)(object)owner != (Object)(object)instance || !Map.Active)
			{
				return;
			}
			Origins.Invoke(instance) = current;
			if (ConfigSync.Fogless)
			{
				if (Object.op_Implicit((Object)(object)Sphere.Invoke(instance)))
				{
					instance.SetFogOrigin(Map.Index);
				}
				DisableSpheres(instance);
			}
			else if (Object.op_Implicit((Object)(object)Sphere.Invoke(instance)))
			{
				instance.SetFogOrigin(Map.Index);
			}
		}

		private static IEnumerator FollowReveal(OrbFogHandler instance, IEnumerator routine)
		{
			while (routine.MoveNext())
			{
				yield return routine.Current;
			}
			if ((Object)(object)owner == (Object)(object)instance && Map.Active && (int)Map.RoleAt(Map.Index) == 4 && Object.op_Implicit((Object)(object)Sphere.Invoke(instance)))
			{
				instance.SetFogOrigin(Map.Index);
			}
		}
	}
	internal static class Map
	{
		private enum ViewBatchState
		{
			Absent,
			Applied,
			Invalid
		}

		private readonly struct StormEntry
		{
			internal StormVisual Visual { get; }

			internal WindChillZone Zone { get; }

			internal StormEntry(StormVisual visual, WindChillZone zone)
			{
				Visual = visual;
				Zone = zone;
			}
		}

		internal sealed class Slot
		{
			internal LayoutOrder.Source Source { get; }

			internal MapSegment Segment { get; }

			internal Transform Container { get; }

			internal Vector3 Offset { get; }

			internal bool IsClone { get; }

			internal bool TerrainReady { get; set; }

			internal bool CampfireReady { get; set; }

			internal Transform? PeakAttachment { get; set; }

			internal Transform? PeakRespawn { get; set; }

			internal bool ViewBatchReady { get; set; } = true;

			internal bool FeaturesActivated { get; set; }

			internal bool Released { get; set; }

			internal Segment Role => Source.Role;

			internal bool FeaturesReady
			{
				get
				{
					if (TerrainReady)
					{
						return CampfireReady;
					}
					return false;
				}
			}

			internal Slot(LayoutOrder.Source source, MapSegment segment, Transform container, Vector3 offset, bool isClone, bool terrainReady, bool campfireReady)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				Source = source;
				Segment = segment;
				Container = container;
				Offset = offset;
				IsClone = isClone;
				TerrainReady = terrainReady;
				CampfireReady = campfireReady;
			}
		}

		private sealed class ViewBatch
		{
			internal PhotonView[] Views { get; }

			internal int PathHash { get; }

			internal FakeItem[] FakeItems { get; }

			internal int FakePathHash { get; }

			internal int Seed { get; }

			internal ViewBatch(PhotonView[] views, int pathHash, FakeItem[] fakeItems, int fakePathHash, int seed)
			{
				Views = views;
				PathHash = pathHash;
				FakeItems = fakeItems;
				FakePathHash = fakePathHash;
				Seed = seed;
			}
		}

		private sealed class QueuedJump
		{
			internal Segment Segment { get; }

			internal HashSet<int> Players { get; }

			internal bool SendToEveryone { get; private set; }

			internal bool UpdateFog { get; private set; }

			internal QueuedJump(Segment segment, HashSet<int> players, bool sendToEveryone, bool updateFog)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				Segment = segment;
				Players = new HashSet<int>(players);
				SendToEveryone = sendToEveryone;
				UpdateFog = updateFog;
			}

			internal void Merge(HashSet<int> players, bool sendToEveryone, bool updateFog)
			{
				Players.UnionWith(players);
				SendToEveryone |= sendToEveryone;
				UpdateFog |= updateFog;
			}
		}

		private sealed class Placement
		{
			internal LayoutOrder.Source[] Sources { get; }

			internal Transform Container { get; }

			internal Vector3 Offset { get; }

			internal int Index { get; }

			internal bool Reuse { get; set; }

			internal Slot[] Slots { get; set; } = Array.Empty<Slot>();

			internal Transform? AttachmentRespawn { get; set; }

			internal Placement(LayoutOrder.Source[] sources, Transform container, Vector3 offset, int index)
			{
				//IL_0020: 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)
				Sources = sources;
				Container = container;
				Offset = offset;
				Index = index;
			}
		}

		private sealed class DetachedPlane
		{
			internal Transform Value { get; }

			private Transform? Parent { get; }

			private int Sibling { get; }

			private Vector3 Position { get; }

			private Quaternion Rotation { get; }

			private Vector3 LocalScale { get; }

			private bool Active { get; }

			internal DetachedPlane(Transform value)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_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)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				Value = value;
				Parent = value.parent;
				Sibling = value.GetSiblingIndex();
				Position = value.position;
				Rotation = value.rotation;
				LocalScale = value.localScale;
				Active = ((Component)value).gameObject.activeSelf;
			}

			internal void Restore()
			{
				//IL_0057: 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_006e: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)Value))
				{
					Value.SetParent(Parent, true);
					if (Object.op_Implicit((Object)(object)Parent))
					{
						Value.SetSiblingIndex(Math.Min(Sibling, Parent.childCount - 1));
					}
					Value.SetPositionAndRotation(Position, Rotation);
					Value.localScale = LocalScale;
					((Component)Value).gameObject.SetActive(Active);
				}
			}
		}

		private sealed class EnvironmentState
		{
			private readonly Dictionary<WaterZone, Bounds> water = new Dictionary<WaterZone, Bounds>();

			private readonly Dictionary<WindChillZone, Bounds> wind = new Dictionary<WindChillZone, Bounds>();

			private readonly Dictionary<PlayerTrackParticles, Bounds> tracks = new Dictionary<PlayerTrackParticles, Bounds>();

			private readonly Dictionary<PlayerMoveZone, Bounds> movement = new Dictionary<PlayerMoveZone, Bounds>();

			private readonly Dictionary<WindHeightEffect, (float From, float To)> heights = new Dictionary<WindHeightEffect, (float, float)>();

			internal void TranslateWater(IEnumerable<GameObject> roots, Vector3 offset, bool capture)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				foreach (GameObject root in roots)
				{
					if (Object.op_Implicit((Object)(object)root))
					{
						TranslateWater(root, offset, capture);
					}
				}
			}

			internal void Rebase(GameObject root, Vector3 offset, bool capture)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: 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_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_0161: Unknown result type (might be due to invalid IL or missing references)
				//IL_0166: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_0189: Unknown result type (might be due to invalid IL or missing references)
				//IL_014b: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_0213: Unknown result type (might be due to invalid IL or missing references)
				TranslateWater(root, offset, capture);
				WindChillZone[] componentsInChildren = root.GetComponentsInChildren<WindChillZone>(true);
				foreach (WindChillZone val in componentsInChildren)
				{
					if (capture && !wind.ContainsKey(val))
					{
						wind.Add(val, WindBounds.Invoke(val));
					}
					Bounds val2 = WindBounds.Invoke(val);
					((Bounds)(ref val2)).center = ((Component)val).transform.position;
					WindBounds.Invoke(val) = val2;
				}
				PlayerTrackParticles[] componentsInChildren2 = root.GetComponentsInChildren<PlayerTrackParticles>(true);
				foreach (PlayerTrackParticles val3 in componentsInChildren2)
				{
					if (capture && !tracks.ContainsKey(val3))
					{
						tracks.Add(val3, TrackBounds.Invoke(val3));
					}
					Bounds val4 = TrackBounds.Invoke(val3);
					((Bounds)(ref val4)).center = ((Component)val3).transform.position;
					TrackBounds.Invoke(val3) = val4;
				}
				PlayerMoveZone[] componentsInChildren3 = root.GetComponentsInChildren<PlayerMoveZone>(true);
				foreach (PlayerMoveZone val5 in componentsInChildren3)
				{
					if (capture && !movement.ContainsKey(val5))
					{
						movement.Add(val5, MoveBounds.Invoke(val5));
					}
					Bounds val6 = MoveBounds.Invoke(val5);
					((Bounds)(ref val6)).center = ((Component)val5).transform.position;
					MoveBounds.Invoke(val5) = val6;
				}
				WindHeightEffect[] componentsInChildren4 = root.GetComponentsInChildren<WindHeightEffect>(true);
				foreach (WindHeightEffect val7 in componentsInChildren4)
				{
					if (capture && !heights.ContainsKey(val7))
					{
						heights.Add(val7, (WindFromHeight.Invoke(val7), WindToHeight.Invoke(val7)));
					}
					WindFromHeight.Invoke(val7) += offset.y;
					WindToHeight.Invoke(val7) += offset.y;
				}
			}

			private void TranslateWater(GameObject root, Vector3 offset, bool capture)
			{
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: 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)
				WaterZone[] componentsInChildren = root.GetComponentsInChildren<WaterZone>(true);
				foreach (WaterZone val in componentsInChildren)
				{
					if (capture && !water.ContainsKey(val))
					{
						water.Add(val, WaterBounds.Invoke(val));
					}
					Bounds val2 = WaterBounds.Invoke(val);
					((Bounds)(ref val2)).center = ((Bounds)(ref val2)).center + offset;
					WaterBounds.Invoke(val) = val2;
				}
			}

			internal void Restore()
			{
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0149: Unknown result type (might be due to invalid IL or missing references)
				//IL_014e: Unknown result type (might be due to invalid IL or missing references)
				foreach (KeyValuePair<WaterZone, Bounds> item in water)
				{
					if (Object.op_Implicit((Object)(object)item.Key))
					{
						WaterBounds.Invoke(item.Key) = item.Value;
					}
				}
				foreach (KeyValuePair<WindChillZone, Bounds> item2 in wind)
				{
					if (Object.op_Implicit((Object)(object)item2.Key))
					{
						WindBounds.Invoke(item2.Key) = item2.Value;
					}
				}
				foreach (KeyValuePair<PlayerTrackParticles, Bounds> track in tracks)
				{
					if (Object.op_Implicit((Object)(object)track.Key))
					{
						TrackBounds.Invoke(track.Key) = track.Value;
					}
				}
				foreach (KeyValuePair<PlayerMoveZone, Bounds> item3 in movement)
				{
					if (Object.op_Implicit((Object)(object)item3.Key))
					{
						MoveBounds.Invoke(item3.Key) = item3.Value;
					}
				}
				foreach (KeyValuePair<WindHeightEffect, (float, float)> height in heights)
				{
					if (Object.op_Implicit((Object)(object)height.Key))
					{
						WindFromHeight.Invoke(height.Key) = height.Value.Item1;
						WindToHeight.Invoke(height.Key) = height.Value.Item2;
					}
				}
			}
		}

		private sealed class PreparedMap
		{
			internal MapHandler Handler { get; }

			internal Slot[] Slots { get; }

			internal Dictionary<GameObject, bool> Originals { get; }

			internal Dictionary<Transform, Vector3> Positions { get; }

			internal HashSet<Transform> Reused { get; }

			internal GameObject[] WaterObjects { get; }

			internal bool[] WaterStates { get; }

			internal Vector3[] WaterPositions { get; }

			internal EnvironmentState Environment { get; }

			internal Transform? TerminalRespawn { get; }

			internal DetachedPlane? Plane { get; }

			internal MapSegment[]? OriginalSegments { get; set; }

			internal List<BiomeType>? OriginalBiomes { get; set; }

			internal Transform? OriginalKilnRespawn { get; set; }

			internal Transform? OriginalPeakRespawn { get; set; }

			internal List<PropGrouper> GeneratedGroupers { get; } = new List<PropGrouper>();

			internal List<PropGrouper> AddedGroupers { get; } = new List<PropGrouper>();

			internal bool Committed { get; set; }

			internal PreparedMap(MapHandler handler, Slot[] slots, Dictionary<GameObject, bool> originals, Dictionary<Transform, Vector3> positions, HashSet<Transform> reused, GameObject[] waterObjects, bool[] waterStates, Vector3[] waterPositions, EnvironmentState environment, Transform? terminalRespawn, DetachedPlane? plane)
			{
				Handler = handler;
				Slots = slots;
				Originals = originals;
				Positions = positions;
				Reused = reused;
				WaterObjects = waterObjects;
				WaterStates = waterStates;
				WaterPositions = waterPositions;
				Environment = environment;
				TerminalRespawn = terminalRespawn;
				Plane = plane;
			}
		}

		[HarmonyPatch(typeof(StormVisual), "LateUpdate")]
		private static class StormVisualUpdatePatch
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				PublishStorm();
			}
		}

		[HarmonyPatch(typeof(StormVisual), "OnDisable")]
		private static class StormVisualDisablePatch
		{
			[HarmonyPostfix]
			private static void Postfix(StormVisual __instance)
			{
				if (Active)
				{
					__instance.observedPlayerInWindZone = false;
					stormFrame = -1;
					PublishStorm();
				}
			}
		}

		[HarmonyPatch(typeof(DisableIfWindActive), "FixedUpdate")]
		private static class DisableIfWindActivePatch
		{
			[HarmonyPrefix]
			private static void Prefix(DisableIfWindActive __instance, out RootsWind? __state)
			{
				__state = RootsWind.instance;
				if (Active && disabledWindOwners.TryGetValue(__instance, out RootsWind value) && Object.op_Implicit((Object)(object)value))
				{
					RootsWind.instance = value;
				}
			}

			[HarmonyFinalizer]
			private static Exception? Finalizer(Exception? __exception, RootsWind? __state)
			{
				RootsWind.instance = __state;
				return __exception;
			}
		}

		[HarmonyPatch(typeof(WindAffectedStatusEmitter), "FixedUpdate")]
		private static class WindAffectedStatusEmitterPatch
		{
			[HarmonyPrefix]
			private static void Prefix(WindAffectedStatusEmitter __instance, out RootsWind? __state)
			{
				__state = RootsWind.instance;
				if (Active && windEmitterOwners.TryGetValue(__instance, out RootsWind value) && Object.op_Implicit((Object)(object)value))
				{
					RootsWind.instance = value;
				}
			}

			[HarmonyFinalizer]
			private static Exception? Finalizer(Exception? __exception, RootsWind? __state)
			{
				RootsWind.instance = __state;
				return __exception;
			}
		}

		[HarmonyPatch(typeof(MapHandler), "InitializeMap")]
		[HarmonyBefore(new string[] { "com.snosz.terrainrandomiser" })]
		[HarmonyPriority(800)]
		private static class PreparePatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				Prepare();
			}

			[HarmonyFinalizer]
			private static Exception? Finalizer(Exception? __exception)
			{
				if (__exception != null && pending != null)
				{
					RollbackPending();
				}
				return __exception;
			}
		}

		[HarmonyPatch(typeof(MapHandler), "InitializeMap")]
		[HarmonyAfter(new string[] { "com.snosz.terrainrandomiser" })]
		[HarmonyPriority(0)]
		private static class CommitPatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{