Decompiled source of WaterWorks v1.0.0

WaterWorks.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using AskaShared.Game;
using AskaWaterWorks.Core;
using AwesomeTechnologies.Vegetation.Masks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using SSSGame;
using SSSGame.Controllers;
using SSSGame.Network;
using SSSGame.Pathfinding;
using SSSGame.UI;
using SSSGame.Water;
using SandSailorStudio;
using SandSailorStudio.Inventory;
using SandSailorStudio.Localization;
using SandSailorStudio.Storage;
using SandSailorStudio.UI;
using SandSailorStudio.WorldGen.Deterministic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("WaterWorks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+dccdc309df26848841df5b56403fc983a807d91a")]
[assembly: AssemblyProduct("Water Works")]
[assembly: AssemblyTitle("WaterWorks")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte flag)
		{
			Flag = flag;
		}
	}
}
namespace AskaWaterWorks
{
	internal static class Aim
	{
		private const float Reach = 1000f;

		private static Il2CppStructArray<RaycastHit> _hits = new Il2CppStructArray<RaycastHit>(64L);

		internal static bool TryAimAtTerrain(Transform character, out Vector3 point)
		{
			Collider nearestCollider;
			return Cast(character, out point, out nearestCollider) == null;
		}

		internal static bool TryAimAtTerrain(Transform character, out Vector3 point, out string refusal)
		{
			Collider nearestCollider;
			string text = Cast(character, out point, out nearestCollider);
			refusal = ((text == null) ? string.Empty : (((Object)(object)nearestCollider != (Object)null) ? (text + " (the aim hits " + ((Object)((Component)nearestCollider).gameObject).name + ")") : text));
			return text == null;
		}

		private static string Cast(Transform character, out Vector3 point, out Collider nearestCollider)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			point = Vector3.zero;
			nearestCollider = null;
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return "no camera to aim with";
			}
			Ray val = main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
			int num;
			for (num = Physics.RaycastNonAlloc(val, _hits, 1000f, -1, (QueryTriggerInteraction)1); num == ((Il2CppArrayBase<RaycastHit>)(object)_hits).Length; num = Physics.RaycastNonAlloc(val, _hits, 1000f, -1, (QueryTriggerInteraction)1))
			{
				_hits = new Il2CppStructArray<RaycastHit>((long)(((Il2CppArrayBase<RaycastHit>)(object)_hits).Length * 2));
			}
			RaycastHit val2 = default(RaycastHit);
			bool flag = false;
			for (int i = 0; i < num; i++)
			{
				RaycastHit val3 = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[i];
				if (!flag || !(((RaycastHit)(ref val3)).distance >= ((RaycastHit)(ref val2)).distance))
				{
					Collider collider = ((RaycastHit)(ref val3)).collider;
					if (!((Object)(object)collider == (Object)null) && (!((Object)(object)character != (Object)null) || !((Component)collider).transform.IsChildOf(character)))
					{
						val2 = val3;
						flag = true;
					}
				}
			}
			if (!flag)
			{
				return "the aim reaches no loaded ground";
			}
			nearestCollider = ((RaycastHit)(ref val2)).collider;
			if (!TerrainHeightSource.IsTerrainCollider(nearestCollider))
			{
				return "aim at open ground";
			}
			point = ((RaycastHit)(ref val2)).point;
			return null;
		}
	}
	internal static class Draughts
	{
		private const string WaterName = "Item_Elements_Water";

		private static readonly string[] SkinNames = new string[2] { "Item_WaterSkins_Simple", "Item_WaterSkins_Large" };

		private static ItemInfo _water;

		internal static int Count()
		{
			ItemInfo val = Water();
			int num = 0;
			foreach (ItemContainer item in Skins())
			{
				num += item.GetItemCount(val);
			}
			return num;
		}

		internal static int Take(int draughts)
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			int num = 0;
			try
			{
				ItemInfo val = Water();
				foreach (ItemContainer item in Skins())
				{
					List<Item> val2 = new List<Item>();
					item.GetItemsToList(val2);
					for (int i = 0; i < val2.Count; i++)
					{
						if (num >= draughts)
						{
							return num;
						}
						Item val3 = val2[i];
						if (val3 != null && !((Object)(object)val3.info == (Object)null) && val3.info.id == val.id)
						{
							int num2 = Math.Min(val3.count, draughts - num);
							if (num2 > 0 && item.RemoveItem(val3, num2, (ItemEventContext)0))
							{
								num += num2;
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(38, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Pool] Taking Draughts failed after ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex);
				}
				log.LogError(val4);
			}
			return num;
		}

		internal static int GiveBack(int draughts)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			int num = 0;
			try
			{
				ItemInfo val = Water();
				foreach (ItemContainer item in Skins())
				{
					int num2 = Math.Min(item.GetRemainingCapacity(val), draughts - num);
					if (num2 > 0)
					{
						num += item.AddItems(val, num2);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(43, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Pool] Giving Draughts back failed after ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log.LogError(val2);
			}
			return num;
		}

		private static List<ItemContainer> Skins()
		{
			List<ItemContainer> list = new List<ItemContainer>();
			ItemCollection val = Collection();
			if (val == null)
			{
				return list;
			}
			List<Item> allItems = val.GetAllItems();
			for (int i = 0; i < allItems.Count; i++)
			{
				Item val2 = allItems[i];
				if (val2 != null && !((Object)(object)val2.info == (Object)null) && Array.IndexOf(SkinNames, ((Object)val2.info).name) >= 0)
				{
					ContainerItem val3 = ((Il2CppObjectBase)val2).TryCast<ContainerItem>();
					ItemContainer val4 = ((val3 != null) ? val3.DynamicContainer : null);
					if (val4 != null)
					{
						list.Add(val4);
					}
				}
			}
			return list;
		}

		internal static ItemCollection Collection()
		{
			Character localCharacter = LocalPlayerTool.LocalCharacter;
			InventoryComponent val = (((Object)(object)localCharacter != (Object)null) ? localCharacter.Inventory : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetItemCollection();
		}

		internal static ItemInfo Water()
		{
			if ((Object)(object)_water != (Object)null)
			{
				return _water;
			}
			ItemDatabaseManager val2 = default(ItemDatabaseManager);
			ItemDatabaseManager val = (GameManagers.TryGet<ItemDatabaseManager>(ref val2) ? val2 : null);
			_water = (((Object)(object)val != (Object)null && (Object)(object)val.Database != (Object)null) ? val.Database.GetItemInfo("Item_Elements_Water") : null);
			return _water ?? throw new InvalidOperationException("Item_Elements_Water is not in the item database.");
		}
	}
	internal static class HostStatus
	{
		private static bool? _isHost;

		private static bool _readFaulted;

		internal static bool? IsHost => _isHost;

		internal static int DraughtCost
		{
			get
			{
				if (_isHost != true)
				{
					return 0;
				}
				return Math.Max(0, Plugin.DraughtCost.Value);
			}
		}

		internal static void ResetForWorld()
		{
			_isHost = null;
			_readFaulted = false;
			PoolEntry.RefreshDescription();
		}

		internal static void Tick()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			if (_isHost.HasValue)
			{
				return;
			}
			bool flag = default(bool);
			try
			{
				NetworkSession val = default(NetworkSession);
				if (!GameManagers.TryGet<NetworkSession>(ref val) || (Object)(object)val == (Object)null)
				{
					return;
				}
				_isHost = val.isMaster;
			}
			catch (Exception ex)
			{
				if (!_readFaulted)
				{
					_readFaulted = true;
					ManualLogSource log = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(38, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Pool] Host status could not be read: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
					}
					log.LogError(val2);
				}
				return;
			}
			ManualLogSource log2 = Plugin.Log;
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(54, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Pool] Host status read: ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((_isHost == true) ? "host" : "joined another player's game");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", a new Pool costs ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(DraughtCost);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" Draughts.");
			}
			log2.LogInfo(val3);
			PoolEntry.RefreshDescription();
		}
	}
	internal static class LevelInput
	{
		private static InputAction _blockedZoom;

		private static bool _warnedOneKey;

		internal static int Read(bool previewShows)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			KeyCode value = Plugin.LevelUpKey.Value;
			KeyCode value2 = Plugin.LevelDownKey.Value;
			bool flag = (int)value != 0 && (int)value2 > 0;
			if (!flag && ((int)value != 0 || (int)value2 != 0) && !_warnedOneKey)
			{
				_warnedOneKey = true;
				Plugin.Log.LogWarning((object)"[Pool] Only one of LevelUpKey and LevelDownKey is set, so the mouse wheel gives level steps. Set both to use keys.");
			}
			BlockZoom(previewShows && !flag);
			if (!previewShows)
			{
				return 0;
			}
			if (flag)
			{
				return (Input.GetKeyDown(value) ? 1 : 0) - (Input.GetKeyDown(value2) ? 1 : 0);
			}
			float y = Input.mouseScrollDelta.y;
			if (y == 0f)
			{
				return 0;
			}
			return Math.Sign(y) * Math.Max(1, (int)Math.Round(Math.Abs(y)));
		}

		internal static void Release()
		{
			BlockZoom(block: false);
		}

		private static void BlockZoom(bool block)
		{
			Controls controls = InputManager.controls;
			if (block)
			{
				InputAction val = ((controls != null) ? controls.m_Camera_CameraZoom : null);
				if (val != null && val.enabled)
				{
					val.Disable();
					_blockedZoom = val;
				}
			}
			else if (_blockedZoom != null)
			{
				InputAction val2 = ((controls != null) ? controls.m_Camera_Look : null);
				if (val2 != null && val2.enabled)
				{
					_blockedZoom.Enable();
				}
				_blockedZoom = null;
			}
		}
	}
	internal static class LoadedLake
	{
		private const string LakeMaterial = "SSSWater_Lake";

		private const float SearchAgainAfter = 10f;

		private static BiomeLakeStampMask _lake;

		private static WaterTile _outOfScene;

		private static float _searchedAt = float.NegativeInfinity;

		private static float _outOfSceneSearchedAt = float.NegativeInfinity;

		internal static void ResetForWorld()
		{
			_lake = null;
			_searchedAt = float.NegativeInfinity;
			_outOfSceneSearchedAt = float.NegativeInfinity;
		}

		internal static WaterTile Tile(out string name)
		{
			if (!HasTile(_lake) && Due(_searchedAt))
			{
				Search();
			}
			if (HasTile(_lake))
			{
				name = "loaded lake " + ((Object)((Component)_lake).gameObject).name;
				return _lake.waterTile;
			}
			if ((Object)(object)_outOfScene == (Object)null && Due(_outOfSceneSearchedAt))
			{
				_outOfSceneSearchedAt = Time.time;
				_outOfScene = OutOfSceneLakeTile();
			}
			name = (((Object)(object)_outOfScene != (Object)null) ? "the out-of-scene lake tile" : string.Empty);
			return _outOfScene;
		}

		private static bool Due(float searchedAt)
		{
			return Time.time - searchedAt >= 10f;
		}

		private static void Search()
		{
			_searchedAt = Time.time;
			foreach (BiomeLakeStampMask item in Object.FindObjectsOfType<BiomeLakeStampMask>())
			{
				if (!((Object)((Component)item).gameObject).name.StartsWith("AskaWaterWorks_Pool_", StringComparison.Ordinal) && (Object)(object)item.waterTile != (Object)null)
				{
					_lake = item;
					break;
				}
			}
		}

		private static bool HasTile(BiomeLakeStampMask lake)
		{
			if ((Object)(object)lake != (Object)null && ((Component)lake).gameObject.activeInHierarchy)
			{
				return (Object)(object)lake.waterTile != (Object)null;
			}
			return false;
		}

		private static WaterTile OutOfSceneLakeTile()
		{
			//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)
			foreach (WaterTile item in Resources.FindObjectsOfTypeAll<WaterTile>())
			{
				Scene scene = ((Component)item).gameObject.scene;
				if (!((Scene)(ref scene)).IsValid())
				{
					MeshRenderer highDetailWaterRenderer = item.highDetailWaterRenderer;
					Material val = (((Object)(object)highDetailWaterRenderer != (Object)null) ? ((Renderer)highDetailWaterRenderer).sharedMaterial : null);
					if ((Object)(object)val != (Object)null && ((Object)val).name == "SSSWater_Lake")
					{
						return item;
					}
				}
			}
			return null;
		}
	}
	[BepInPlugin("mugsy33.waterworks", "Water Works", "1.0.0")]
	public class Plugin : BasePlugin
	{
		public const string PluginGuid = "mugsy33.waterworks";

		public const string PluginName = "Water Works";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ConfigEnabled;

		internal static ConfigEntry<int> DraughtCost;

		internal static ConfigEntry<KeyCode> LevelUpKey;

		internal static ConfigEntry<KeyCode> LevelDownKey;

		private static void OnDraughtCostChanged(object sender, EventArgs e)
		{
			PoolEntry.RefreshDescription();
		}

		public override void Load()
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_00fc: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			ConfigEnabled = ((BasePlugin)this).Config.Bind<bool>("WaterWorks", "Enabled", true, "Master on/off switch for this tool.");
			DraughtCost = ((BasePlugin)this).Config.Bind<int>("WaterWorks", "DraughtCost", 5, "Draughts of water a new Pool takes from the host's waterskins. 0 switches the cost off; a value below 0 is read as 0. Raising and lowering a Pool cost nothing. Draining a Pool gives back this cost, as far as your waterskins have room. A player who joined another player's game never pays and gets nothing back.");
			DraughtCost.SettingChanged += OnDraughtCostChanged;
			LevelUpKey = ((BasePlugin)this).Config.Bind<KeyCode>("WaterWorks", "LevelUpKey", (KeyCode)0, "Raises a Pool tool preview 0.1 m. Set it and LevelDownKey to keep the mouse wheel for camera zoom. Pick a key that is free in build mode.");
			LevelDownKey = ((BasePlugin)this).Config.Bind<KeyCode>("WaterWorks", "LevelDownKey", (KeyCode)0, "Lowers a Pool tool preview 0.1 m. Set it and LevelUpKey to keep the mouse wheel for camera zoom. Pick a key that is free in build mode.");
			ClassInjector.RegisterTypeInIl2Cpp<PoolTool>();
			ClassInjector.RegisterTypeInIl2Cpp<PoolWorld>();
			LocalPlayerTool.Register(Log, "AskaWaterWorks_Tool", Vector3.zero, typeof(PoolTool));
			Harmony val = new Harmony("mugsy33.waterworks.tool");
			PoolEntry.Patch(val);
			PoolToolHost.Patch(val);
			PoolStore.Patch(val);
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(12, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("Water Works");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] v");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.0");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded.");
			}
			log.LogInfo(val2);
		}
	}
	internal static class PoolBuilder
	{
		internal static bool TryBuild(PlaceOutput place, double spacing, Character character, out int poolId, out string details)
		{
			poolId = 0;
			BasinResult result = place.Result;
			int nextId = PoolRegistry.NextId;
			PoolLake poolLake;
			try
			{
				poolLake = PoolLake.Build(nextId, result.Cells, spacing, result.WaterLevel, result.Depth);
			}
			catch (Exception ex)
			{
				details = ex.GetType().Name + ": " + ex.Message;
				return false;
			}
			List<PlacedPool> old = PoolRegistry.Find(place.Replaces);
			bool valueOrDefault = HostStatus.IsHost == true;
			PoolRegistry.Replace(old, new PlacedPool(nextId, result, spacing, poolLake, valueOrDefault), character);
			poolId = nextId;
			details = (poolLake.HasSurface ? $"Pool #{nextId}, {poolLake.SurfaceNote}" : $"{poolLake.SurfaceNote}, Pool #{nextId}");
			return true;
		}
	}
	internal static class PoolClimb
	{
		private const float RoomClearance = 0.1f;

		internal static void Tick(Character character)
		{
			//IL_005a: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			PlacedPool applied = PoolRegistry.Applied;
			if (applied == null || (Object)(object)character == (Object)null || !JumpPressed())
			{
				return;
			}
			CharacterMovement component = ((Component)character).GetComponent<CharacterMovement>();
			if ((Object)(object)component == (Object)null || !component.IsSwimming)
			{
				return;
			}
			MovementStats parameters = component.parameters;
			CapsuleCollider crouchingCollider = component.crouchingCollider;
			if ((Object)(object)parameters == (Object)null || (Object)(object)crouchingCollider == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)character).transform.position;
			if (RimClimb.TryFindLanding(applied.Basin.Cells, applied.Basin.WaterLevel, position.x, position.z, applied.Spacing, parameters.minSlideAgle, new TerrainHeightSource(applied.Spacing), out var landing, out var ground))
			{
				var (num, num2) = Grid.WorldPosition(landing, applied.Spacing);
				Vector3 ground2 = default(Vector3);
				((Vector3)(ref ground2))..ctor((float)num, (float)ground, (float)num2);
				if (!((Object)(object)Blocker(crouchingCollider, ground2, ((Component)character).transform) != (Object)null))
				{
					PlayerTeleport.TryTeleportAbove(character, ground2);
				}
			}
		}

		private static Collider Blocker(CapsuleCollider body, Vector3 ground, Transform self)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			Vector3 lossyScale = ((Component)body).transform.lossyScale;
			float num = body.radius * Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z));
			float num2 = Mathf.Max(body.height * Mathf.Abs(lossyScale.y), 2f * num);
			Vector3 val = new Vector3(ground.x, ground.y + 0.1f + num2 * 0.5f, ground.z);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(num, num2 * 0.5f, num);
			Il2CppReferenceArray<Collider> val3 = Physics.OverlapBox(val, val2, Quaternion.identity, -1, (QueryTriggerInteraction)1);
			for (int i = 0; i < ((Il2CppArrayBase<Collider>)(object)val3).Length; i++)
			{
				Collider val4 = ((Il2CppArrayBase<Collider>)(object)val3)[i];
				if ((Object)(object)val4 != (Object)null && !((Component)val4).transform.IsChildOf(self) && !TerrainHeightSource.IsTerrainCollider(val4))
				{
					return val4;
				}
			}
			return null;
		}

		private static bool JumpPressed()
		{
			return JumpInput.PressedThisFrame();
		}
	}
	internal static class PoolEntry
	{
		private const string FieldAssetName = "Item_Structures_TerrainLevelField";

		private const string RoadAssetName = "Item_Structures_TerrainSplineRoad";

		private const string WaterskinAssetName = "Item_WaterSkins_Simple";

		private const string WellAssetName = "Item_Structures_WaterWellL1";

		private const string CloneAssetName = "Pool_Entry";

		private const int CloneId = 919191400;

		private const string EntryName = "Pool";

		private const string BaseDescription = "Fill the hollow you aim at with water.";

		private const float GrantWindowSeconds = 5f;

		private static DynamicDimensionTemplate _clone;

		private static IntPtr _clonePointer;

		private static int _roadId;

		private static float _grantWindowUntil;

		private static BuildItemsTabPage _lastPage;

		private static PlayerBuilder _builder;

		private static bool _granted;

		private static bool _granting;

		private static ItemCollection _heldBack;

		private static int _heldCount;

		private static int _serializeDepth;

		private static string EntryDescription
		{
			get
			{
				int draughtCost = HostStatus.DraughtCost;
				string text = ((draughtCost == 1) ? "1 Draught" : $"{draughtCost} Draughts");
				if (draughtCost <= 0)
				{
					return "Fill the hollow you aim at with water.";
				}
				return "Fill the hollow you aim at with water. A new Pool costs " + text + " from your waterskins.";
			}
		}

		internal static void RefreshDescription()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			try
			{
				if ((Object)(object)_clone != (Object)null)
				{
					((ItemInfo)_clone).localizedDescription = EntryDescription;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(47, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The entry description failed to update: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		internal static void ResetForWorld()
		{
			_builder = null;
			_lastPage = null;
			_granted = false;
		}

		internal static void Patch(Harmony harmony)
		{
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ItemInfoDatabase), "Initialize", Type.EmptyTypes, (Type[])null), Hook("BeforeDatabaseInitialize"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(BuildItemsTabPage), "Init", new Type[1] { typeof(TabButton) }, (Type[])null), Hook("BeforeTabInit"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(BuildItemsTabPage), "Show", new Type[2]
			{
				typeof(bool),
				typeof(TabButton)
			}, (Type[])null), (HarmonyMethod)null, Hook("AfterTabShow"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(InventoryComponent), "GetItemCollection", Type.EmptyTypes, (Type[])null), (HarmonyMethod)null, Hook("AfterGetItemCollection"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(LocalizationManager), "Loc", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, (Type[])null), (HarmonyMethod)null, Hook("AfterLoc"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(PlayerInventory), "Serialize", new Type[1] { typeof(DataObject) }, (Type[])null), Hook("BeforeSerialize"), (HarmonyMethod)null, (HarmonyMethod)null, Hook("AfterSerialize"), (HarmonyMethod)null);
		}

		public static void BeforeSerialize(PlayerInventory __instance)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			_serializeDepth++;
			if (_heldBack != null)
			{
				return;
			}
			try
			{
				ItemCollection val = (((Object)(object)_clone != (Object)null) ? ((InventoryComponent)__instance).GetItemCollection() : null);
				int num = ((val != null) ? val.GetItemQuantity((ItemInfo)(object)_clone) : 0);
				int num2 = ((num > 0) ? val.RemoveItems((ItemInfo)(object)_clone, num) : 0);
				if (num2 > 0)
				{
					_heldBack = val;
					_heldCount = num2;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(63, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Pool] The build menu entry could not be kept out of the save: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log.LogError(val2);
			}
		}

		public static void AfterSerialize()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			_serializeDepth--;
			if (_serializeDepth > 0 || _heldBack == null)
			{
				return;
			}
			bool flag = default(bool);
			try
			{
				int num = _heldBack.AddItems((ItemInfo)(object)_clone, _heldCount);
				if (num < _heldCount)
				{
					_granted = false;
					ManualLogSource log = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(63, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The build menu entry was granted back ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" of ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_heldCount);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" after a save.");
					}
					log.LogWarning(val);
				}
			}
			catch (Exception ex)
			{
				_granted = false;
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(69, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Pool] The build menu entry could not be granted again after a save: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val2);
			}
			finally
			{
				_heldBack = null;
				_heldCount = 0;
			}
		}

		private static List<BlueprintConditionsRule> UnlockRules(NodeTemplate well)
		{
			List<BlueprintConditionsRule> val = new List<BlueprintConditionsRule>();
			List<BlueprintConditionsRule> blueprintConditionsRules = well.blueprintConditionsRules;
			int num = 0;
			while (blueprintConditionsRules != null && num < blueprintConditionsRules.Count)
			{
				val.Add(blueprintConditionsRules[num]);
				num++;
			}
			return val;
		}

		internal static bool IsEntry(StructureTemplate template)
		{
			if ((Object)(object)template != (Object)null && _clonePointer != IntPtr.Zero)
			{
				return ((Il2CppObjectBase)template).Pointer == _clonePointer;
			}
			return false;
		}

		public static void BeforeDatabaseInitialize(ItemInfoDatabase __instance)
		{
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Expected O, but got Unknown
			bool flag2 = default(bool);
			try
			{
				ItemInfoList val = (((Object)(object)__instance != (Object)null) ? __instance.CompleteItemInfoList : null);
				List<ItemInfo> val2 = (((Object)(object)val != (Object)null) ? val.itemInfoList : null);
				if (val2 == null || IndexOfId(val2, 919191400) >= 0)
				{
					return;
				}
				DynamicDimensionTemplate val3 = null;
				ItemInfo val4 = null;
				NodeTemplate val5 = null;
				for (int i = 0; i < val2.Count; i++)
				{
					ItemInfo val6 = val2[i];
					if (!((Object)(object)val6 == (Object)null))
					{
						if (((Object)val6).name == "Item_Structures_TerrainLevelField")
						{
							val3 = ((Il2CppObjectBase)val6).TryCast<DynamicDimensionTemplate>();
						}
						else if (((Object)val6).name == "Item_Structures_TerrainSplineRoad")
						{
							_roadId = val6.id;
						}
						else if (((Object)val6).name == "Item_WaterSkins_Simple")
						{
							val4 = val6;
						}
						else if (((Object)val6).name == "Item_Structures_WaterWellL1")
						{
							val5 = ((Il2CppObjectBase)val6).TryCast<NodeTemplate>();
						}
					}
				}
				bool flag = true;
				if ((Object)(object)val3 == (Object)null || _roadId == 0 || (flag && (Object)(object)val5 == (Object)null))
				{
					ManualLogSource log = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val7 = new BepInExWarningLogInterpolatedStringHandler(73, 3, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val7).AppendLiteral("[Pool] The build menu entry was not added: found field=");
						((BepInExLogInterpolatedStringHandler)val7).AppendFormatted<bool>((Object)(object)val3 != (Object)null);
						((BepInExLogInterpolatedStringHandler)val7).AppendLiteral(", road id=");
						((BepInExLogInterpolatedStringHandler)val7).AppendFormatted<int>(_roadId);
						((BepInExLogInterpolatedStringHandler)val7).AppendLiteral(", well=");
						((BepInExLogInterpolatedStringHandler)val7).AppendFormatted<bool>((Object)(object)val5 != (Object)null);
						((BepInExLogInterpolatedStringHandler)val7).AppendLiteral(".");
					}
					log.LogWarning(val7);
					return;
				}
				DynamicDimensionTemplate val8 = new DynamicDimensionTemplate(((Il2CppObjectBase)Object.Instantiate<DynamicDimensionTemplate>(val3)).Pointer);
				((Object)val8).name = "Pool_Entry";
				((ItemInfo)val8).id = 919191400;
				((ItemInfo)val8).databaseIndex = (ushort)val2.Count;
				((ItemInfo)val8).Localized = false;
				((ItemInfo)val8).localizedName = "Pool";
				((ItemInfo)val8).localizedDescription = EntryDescription;
				((NodeTemplate)val8).showUnlockNotification = false;
				((NodeTemplate)val8).blueprintConditionsRules = UnlockRules(val5);
				Sprite val9 = PoolIcon.Load();
				if ((Object)(object)val9 != (Object)null)
				{
					((ItemInfo)val8).icon = val9;
				}
				if ((Object)(object)val4 != (Object)null)
				{
					PoolGhost.SetSource(val4.spawnObject);
				}
				else
				{
					ManualLogSource log2 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val7 = new BepInExWarningLogInterpolatedStringHandler(62, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val7).AppendLiteral("[Pool] The waterskin ");
						((BepInExLogInterpolatedStringHandler)val7).AppendFormatted<string>("Item_WaterSkins_Simple");
						((BepInExLogInterpolatedStringHandler)val7).AppendLiteral(" was not found; the entry shows no ghost.");
					}
					log2.LogWarning(val7);
				}
				val2.Add((ItemInfo)(object)val8);
				_clone = val8;
				_clonePointer = ((Il2CppObjectBase)val8).Pointer;
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val10 = new BepInExErrorLogInterpolatedStringHandler(36, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val10).AppendLiteral("[Pool] The build menu entry failed: ");
					((BepInExLogInterpolatedStringHandler)val10).AppendFormatted<Exception>(ex);
				}
				log3.LogError(val10);
			}
		}

		public static void BeforeTabInit(BuildItemsTabPage __instance, TabButton button)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			try
			{
				_lastPage = __instance;
				_grantWindowUntil = Time.realtimeSinceStartup + 5f;
				if (!_granted)
				{
					Grant(ResolveItemCollection());
				}
				AppendToTab(button);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(48, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The build menu entry failed on tab init: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		public static void AfterTabShow(BuildItemsTabPage __instance, bool value, TabButton button)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			try
			{
				_lastPage = __instance;
				if (value)
				{
					AppendToTab(button);
					if (!_granted)
					{
						Grant(ResolveItemCollection());
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(48, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The build menu entry failed on tab show: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		public static void AfterGetItemCollection(InventoryComponent __instance, ItemCollection __result)
		{
			if (!_granted && __result != null && Time.realtimeSinceStartup <= _grantWindowUntil && IsLocalPlayerInventory(__instance))
			{
				Grant(__result);
			}
		}

		private static bool IsLocalPlayerInventory(InventoryComponent inventory)
		{
			PlayerInventory val = (((Object)(object)inventory != (Object)null) ? ((Il2CppObjectBase)inventory).TryCast<PlayerInventory>() : null);
			Character localCharacter = LocalPlayerTool.LocalCharacter;
			Character val2 = (((Object)(object)val != (Object)null) ? ((CharacterInventory)val).character : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)localCharacter != (Object)null)
			{
				return ((Il2CppObjectBase)val2).Pointer == ((Il2CppObjectBase)localCharacter).Pointer;
			}
			return false;
		}

		private static void AppendToTab(TabButton button)
		{
			if (!Plugin.ConfigEnabled.Value)
			{
				return;
			}
			TabButtonCategory val = (((Object)(object)button != (Object)null) ? ((Il2CppObjectBase)button).TryCast<TabButtonCategory>() : null);
			List<ItemInfo> val2 = (((Object)(object)val != (Object)null) ? val.additionalInfos : null);
			if (val2 != null && !((Object)(object)_clone == (Object)null) && IndexOfId(val2, _roadId) >= 0)
			{
				int num = IndexOfId(val2, 919191400);
				if (num < 0)
				{
					val2.Add((ItemInfo)(object)_clone);
				}
				else if ((Object)(object)val2[num] == (Object)null || ((Il2CppObjectBase)val2[num]).Pointer != _clonePointer)
				{
					val2[num] = (ItemInfo)(object)_clone;
				}
			}
		}

		private static void Grant(ItemCollection collection)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			if (_granted || _granting || _heldBack != null || collection == null || (Object)(object)_clone == (Object)null || !Plugin.ConfigEnabled.Value)
			{
				return;
			}
			_granting = true;
			try
			{
				if ((Object)(object)_builder == (Object)null)
				{
					_builder = LocalBuilder();
				}
				ItemInfoList val = (((Object)(object)_builder != (Object)null) ? _builder.knownBlueprints : null);
				List<ItemInfo> val2 = (((Object)(object)val != (Object)null) ? val.itemInfoList : null);
				if (val2 != null)
				{
					if (collection.GetFirstItem((ItemInfo)(object)_clone) == null)
					{
						collection.AddItems((ItemInfo)(object)_clone, 1);
					}
					if (!val.Check((ItemInfo)(object)_clone))
					{
						val2.Add((ItemInfo)(object)_clone);
					}
					ItemCollection val3 = ResolveItemCollection();
					_granted = val3 != null && val3.GetFirstItem((ItemInfo)(object)_clone) != null && val.Check((ItemInfo)(object)_clone);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(45, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Pool] The build menu entry failed to grant: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex);
				}
				log.LogError(val4);
			}
			finally
			{
				_granting = false;
			}
		}

		public static void AfterLoc(string key, ref string __result)
		{
			if (key != null && key.IndexOf("Pool_Entry", StringComparison.Ordinal) >= 0)
			{
				if (key.EndsWith("_name", StringComparison.OrdinalIgnoreCase))
				{
					__result = "Pool";
				}
				else if (key.EndsWith("_description", StringComparison.OrdinalIgnoreCase) || key.EndsWith("_desc", StringComparison.OrdinalIgnoreCase))
				{
					__result = EntryDescription;
				}
				else if (key.EndsWith("_lore", StringComparison.OrdinalIgnoreCase))
				{
					__result = string.Empty;
				}
			}
		}

		private static PlayerBuilder LocalBuilder()
		{
			Character localCharacter = LocalPlayerTool.LocalCharacter;
			PlayerBuilder val = (((Object)(object)localCharacter != (Object)null) ? ((Component)localCharacter).GetComponentInChildren<PlayerBuilder>(true) : null);
			if ((Object)(object)val == (Object)null && (Object)(object)localCharacter != (Object)null)
			{
				val = ((Component)localCharacter).GetComponentInParent<PlayerBuilder>();
			}
			if (!((Object)(object)val != (Object)null))
			{
				return Object.FindObjectOfType<PlayerBuilder>();
			}
			return val;
		}

		private static ItemCollection ResolveItemCollection()
		{
			PlayerInventory val = (((Object)(object)_lastPage != (Object)null) ? _lastPage._pi : null);
			if (!((Object)(object)val != (Object)null))
			{
				return Draughts.Collection();
			}
			return ((InventoryComponent)val).GetItemCollection();
		}

		private static int IndexOfId(List<ItemInfo> list, int id)
		{
			for (int i = 0; i < list.Count; i++)
			{
				ItemInfo val = list[i];
				if ((Object)(object)val != (Object)null && val.id == id)
				{
					return i;
				}
			}
			return -1;
		}

		private static HarmonyMethod Hook(string name)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return new HarmonyMethod(AccessTools.DeclaredMethod(typeof(PoolEntry), name, (Type[])null, (Type[])null));
		}
	}
	internal static class PoolGhost
	{
		private const float Scale = 3f;

		private static GameObject _ghost;

		private static GameObject _source;

		private static bool _failed;

		internal static void SetSource(GameObject source)
		{
			if (!((Object)(object)source == (Object)(object)_source))
			{
				_source = source;
				_failed = false;
				Destroy();
			}
		}

		internal static void Show(Vector3 ground)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (Ensure())
			{
				_ghost.transform.position = ground;
				if (!_ghost.activeSelf)
				{
					_ghost.SetActive(true);
				}
			}
		}

		internal static void Hide()
		{
			if ((Object)(object)_ghost != (Object)null && _ghost.activeSelf)
			{
				_ghost.SetActive(false);
			}
		}

		private static bool Ensure()
		{
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_ghost != (Object)null)
			{
				return true;
			}
			if (_failed || (Object)(object)_source == (Object)null)
			{
				return false;
			}
			try
			{
				GameObject val = new GameObject("AskaWaterWorks_WaterskinGhost");
				val.transform.localScale = Vector3.one * 3f;
				float num = float.MaxValue;
				foreach (MeshFilter componentsInChild in _source.GetComponentsInChildren<MeshFilter>(true))
				{
					MeshRenderer component = ((Component)componentsInChild).GetComponent<MeshRenderer>();
					if (!((Object)(object)componentsInChild.sharedMesh == (Object)null) && !((Object)(object)component == (Object)null))
					{
						GameObject val2 = new GameObject("Part");
						val2.transform.SetParent(val.transform, false);
						val2.transform.localPosition = _source.transform.InverseTransformPoint(((Component)componentsInChild).transform.position);
						val2.transform.localRotation = Quaternion.Inverse(_source.transform.rotation) * ((Component)componentsInChild).transform.rotation;
						val2.transform.localScale = ((Component)componentsInChild).transform.lossyScale;
						val2.AddComponent<MeshFilter>().sharedMesh = componentsInChild.sharedMesh;
						((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)component).sharedMaterials;
						float val3 = num;
						float y = val2.transform.localPosition.y;
						Bounds bounds = componentsInChild.sharedMesh.bounds;
						num = Math.Min(val3, y + ((Bounds)(ref bounds)).min.y * val2.transform.localScale.y);
					}
				}
				if (val.transform.childCount == 0)
				{
					Object.Destroy((Object)(object)val);
					_failed = true;
					Plugin.Log.LogWarning((object)"[Pool] The waterskin ghost has no mesh to copy.");
					return false;
				}
				IEnumerator enumerator2 = val.transform.GetEnumerator();
				try
				{
					while (enumerator2.MoveNext())
					{
						Transform val4 = (Transform)enumerator2.Current;
						val4.localPosition -= new Vector3(0f, num, 0f);
					}
				}
				finally
				{
					if (enumerator2 is IDisposable disposable)
					{
						disposable.Dispose();
					}
				}
				val.SetActive(false);
				_ghost = val;
				return true;
			}
			catch (Exception ex)
			{
				_failed = true;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val5 = new BepInExErrorLogInterpolatedStringHandler(44, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[Pool] The waterskin ghost failed to build: ");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<Exception>(ex);
				}
				log.LogError(val5);
				return false;
			}
		}

		private static void Destroy()
		{
			if ((Object)(object)_ghost != (Object)null)
			{
				Object.Destroy((Object)(object)_ghost);
			}
			_ghost = null;
		}
	}
	internal static class PoolIcon
	{
		internal static Sprite Load()
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text = executingAssembly.GetName().Name + ".PoolIcon.png";
			bool flag = default(bool);
			try
			{
				using Stream stream = executingAssembly.GetManifestResourceStream(text);
				if (stream == null)
				{
					ManualLogSource log = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(71, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The embedded icon ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is missing; the entry keeps the field's icon.");
					}
					log.LogWarning(val);
					return null;
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val2, Il2CppStructArray<byte>.op_Implicit(memoryStream.ToArray())))
				{
					Object.Destroy((Object)(object)val2);
					ManualLogSource log2 = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(82, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The embedded icon ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is not a readable PNG; the entry keeps the field's icon.");
					}
					log2.LogWarning(val);
					return null;
				}
				((Object)val2).hideFlags = (HideFlags)61;
				Sprite obj = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f));
				((Object)obj).hideFlags = (HideFlags)61;
				return obj;
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(75, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The embedded icon failed to load; the entry keeps the field's icon: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log3.LogWarning(val);
				return null;
			}
		}
	}
	internal sealed class PoolLake
	{
		internal const string ObjectPrefix = "AskaWaterWorks_Pool_";

		private const long LakeThreshold = 9011L;

		private readonly GameObject _object;

		private readonly LakeWorldContext _context;

		private readonly GameObject _tile;

		private readonly SurfaceAssets _surface;

		internal long Threshold { get; }

		internal bool Exists => (Object)(object)_object != (Object)null;

		internal LakeWorldContext Context => _context;

		internal bool HasSurface => (Object)(object)_tile != (Object)null;

		internal string SurfaceNote { get; }

		private PoolLake(GameObject gameObject, LakeWorldContext context, GameObject tile, SurfaceAssets surface, string surfaceNote, long threshold)
		{
			_object = gameObject;
			_context = context;
			_tile = tile;
			_surface = surface;
			SurfaceNote = surfaceNote;
			Threshold = threshold;
		}

		internal static PoolLake Build(int id, IReadOnlySet<Cell> cells, double spacing, double level, double depth, long? threshold = null)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			LakeMask lakeMask = LakeMask.For(cells, spacing);
			Rect textureRect = default(Rect);
			((Rect)(ref textureRect))..ctor((float)lakeMask.WorldXMin, (float)lakeMask.WorldZMin, (float)lakeMask.WorldWidth, (float)lakeMask.WorldDepth);
			GameObject val = new GameObject("AskaWaterWorks_Pool_" + id.ToString(CultureInfo.InvariantCulture));
			val.transform.position = new Vector3(((Rect)(ref textureRect)).center.x, 0f, ((Rect)(ref textureRect)).center.y);
			try
			{
				BiomeLakeStampMask val2 = val.AddComponent<BiomeLakeStampMask>();
				LakeWorldContextSource val3 = val.AddComponent<LakeWorldContextSource>();
				float num = (val2._waterLevel = PoolWater.SurfaceLevel(level));
				val2._bounds = new Vector4(((Rect)(ref textureRect)).xMin, ((Rect)(ref textureRect)).yMin, ((Rect)(ref textureRect)).xMax, ((Rect)(ref textureRect)).yMax);
				Texture2D maskTexture = BuildTexture(lakeMask);
				val2._landmask = new TextureMask
				{
					TextureRect = textureRect,
					MaskTexture = maskTexture
				};
				MaskStampOperation val4 = new MaskStampOperation();
				StampMaskFixedParams maskParams = val4.maskParams;
				long threshold2 = (maskParams.threshold = threshold ?? 9011);
				val4.maskParams = maskParams;
				((BiomeStampMask)val2)._stampOperation = val4;
				LakeWorldContext val5 = new LakeWorldContext(IL2CPP.il2cpp_object_new(Il2CppClassPointerStore<LakeWorldContext>.NativeClassPtr));
				val5._lakeStampMask = val2;
				val5._source = (BiomeWorldContextSource)(object)val3;
				val3._context = val5;
				SurfaceAssets assets;
				string note;
				GameObject val6 = PoolPreview.HandOverWater(cells, num, val.transform, id, out assets, out note);
				if ((Object)(object)val6 == (Object)null)
				{
					val6 = PoolSurface.Build(val.transform, id, LakeMask.SurfaceFor(cells, spacing), num, out assets, out note);
				}
				BuildWaterArea(val.transform, id, cells, spacing, num, (float)(level - depth));
				return new PoolLake(val, val5, val6, assets, note, threshold2);
			}
			catch
			{
				Object.Destroy((Object)(object)val);
				throw;
			}
		}

		private static void BuildWaterArea(Transform lake, int id, IReadOnlySet<Cell> cells, double spacing, float stampLevel, float lowestGround)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			try
			{
				PoolWaterArea.Build(lake, cells, spacing, stampLevel, lowestGround);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(65, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] Pool #");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(id);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" has no Water area, so Animals walk on its floor: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.GetType().Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}

		internal void Destroy()
		{
			if ((Object)(object)_object != (Object)null)
			{
				Object.Destroy((Object)(object)_object);
			}
			_surface?.Destroy();
		}

		internal void SetWaterVisible(bool visible)
		{
			if ((Object)(object)_tile != (Object)null)
			{
				_tile.SetActive(visible);
			}
		}

		internal static Texture2D BuildTexture(LakeMask mask)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0058: 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)
			Texture2D val = new Texture2D(mask.Width, mask.Depth, (TextureFormat)4, false, true);
			Color32[] array = (Color32[])(object)new Color32[mask.Width * mask.Depth];
			for (int i = 0; i < mask.Depth; i++)
			{
				for (int j = 0; j < mask.Width; j++)
				{
					byte b = (byte)((!mask.IsWater(j, i)) ? byte.MaxValue : 0);
					array[i * mask.Width + j] = new Color32(b, (byte)0, (byte)0, byte.MaxValue);
				}
			}
			val.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(array));
			((Texture)val).filterMode = (FilterMode)0;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			val.Apply(false, false);
			return val;
		}
	}
	internal static class PoolPreview
	{
		private const string ObjectName = "AskaWaterWorks_Preview";

		private const float OutlineLift = 0.05f;

		private const float OutlineWidth = 0.12f;

		private const int OutlineSortingOrder = 5000;

		private static readonly Color OutlineColour = new Color(0.75f, 0.95f, 1f, 1f);

		private static readonly List<PlacedPool> Hidden = new List<PlacedPool>();

		private static GameObject _root;

		private static GameObject _water;

		private static string _waterNote;

		private static IReadOnlySet<Cell> _cells;

		private static float _level;

		private static SurfaceAssets _surface;

		private static Material _lineMaterial;

		internal static bool Showing => (Object)(object)_root != (Object)null;

		internal static GameObject HandOverWater(IReadOnlySet<Cell> cells, float level, Transform pool, int id, out SurfaceAssets assets, out string note)
		{
			assets = null;
			note = null;
			if ((Object)(object)_water == (Object)null || cells != _cells || level != _level)
			{
				return null;
			}
			GameObject water = _water;
			((Object)water).name = "AskaWaterWorks_Tile_" + id.ToString(CultureInfo.InvariantCulture);
			water.transform.SetParent(pool, true);
			assets = _surface;
			note = _waterNote;
			_water = null;
			_surface = null;
			return water;
		}

		internal static void Show(ShowPreviewOutput preview, double spacing)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			End();
			try
			{
				BasinResult result = preview.Result;
				_root = new GameObject("AskaWaterWorks_Preview");
				float num = PoolWater.SurfaceLevel(result.WaterLevel);
				string surfaceNote;
				GameObject obj = (_water = PoolSurface.Build(_root.transform, 0, LakeMask.SurfaceFor(result.Cells, spacing), num, out _surface, out surfaceNote));
				_waterNote = surfaceNote;
				_cells = result.Cells;
				_level = num;
				DrawOutline(preview.Outline, num + 0.05f);
				if ((Object)(object)obj == (Object)null)
				{
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(48, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The Preview has an outline and no water: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(surfaceNote);
					}
					log.LogWarning(val);
				}
				foreach (PlacedPool item in PoolRegistry.Find(preview.Replaces))
				{
					item.Lake.SetWaterVisible(visible: false);
					Hidden.Add(item);
				}
			}
			catch
			{
				End();
				throw;
			}
		}

		internal static void End()
		{
			foreach (PlacedPool item in Hidden)
			{
				if (item.Lake.Exists)
				{
					item.Lake.SetWaterVisible(visible: true);
				}
			}
			Hidden.Clear();
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_surface?.Destroy();
			_root = null;
			_water = null;
			_cells = null;
			_surface = null;
		}

		private static int DrawOutline(IReadOnlyList<Segment> outline, float height)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_0106: Unknown result type (might be due to invalid IL or missing references)
			IReadOnlyList<IReadOnlyList<(double, double)>> readOnlyList = Outline.Chain(outline);
			for (int i = 0; i < readOnlyList.Count; i++)
			{
				IReadOnlyList<(double, double)> readOnlyList2 = readOnlyList[i];
				GameObject val = new GameObject($"Outline_{i}");
				val.transform.SetParent(_root.transform, false);
				LineRenderer val2 = val.AddComponent<LineRenderer>();
				val2.useWorldSpace = true;
				val2.alignment = (LineAlignment)0;
				val2.numCapVertices = 4;
				val2.numCornerVertices = 2;
				((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val2).receiveShadows = false;
				((Renderer)val2).sortingOrder = 5000;
				val2.startWidth = 0.12f;
				val2.endWidth = 0.12f;
				val2.startColor = OutlineColour;
				val2.endColor = OutlineColour;
				Material val3 = LineMaterial();
				if ((Object)(object)val3 != (Object)null)
				{
					((Renderer)val2).material = val3;
				}
				val2.positionCount = readOnlyList2.Count;
				for (int j = 0; j < readOnlyList2.Count; j++)
				{
					val2.SetPosition(j, new Vector3((float)readOnlyList2[j].Item1, height, (float)readOnlyList2[j].Item2));
				}
			}
			return readOnlyList.Count;
		}

		private static Material LineMaterial()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			if ((Object)(object)_lineMaterial != (Object)null)
			{
				return _lineMaterial;
			}
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Unlit/Color");
			}
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidOperationException("no line shader: Sprites/Default and Unlit/Color are both missing");
			}
			_lineMaterial = new Material(val);
			return _lineMaterial;
		}
	}
	internal sealed class PlacedPool
	{
		internal int Id { get; }

		internal bool Saved { get; }

		internal BasinResult Basin { get; }

		internal double Spacing { get; }

		internal PoolLake Lake { get; }

		internal PlacedPool(int id, BasinResult basin, double spacing, PoolLake lake, bool saved)
		{
			Id = id;
			Basin = basin;
			Spacing = spacing;
			Lake = lake;
			Saved = saved;
		}

		internal bool Covers(Vector3 world)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return Basin.Cells.Contains(Grid.NearestCell(world.x, world.z, Spacing));
		}
	}
	internal static class PoolRegistry
	{
		private static readonly List<PlacedPool> Pools = new List<PlacedPool>();

		private static int _nextId = 1;

		private static PlacedPool _applied;

		internal static int NextId => _nextId;

		internal static PlacedPool Applied => _applied;

		internal static List<PlacedPool> FindOverlapping(IReadOnlySet<Cell> cells)
		{
			List<PlacedPool> list = new List<PlacedPool>();
			foreach (PlacedPool pool in Pools)
			{
				if (pool.Lake.Exists && pool.Basin.Cells.Overlaps(cells))
				{
					list.Add(pool);
				}
			}
			return list;
		}

		internal static List<PlacedPool> Find(IReadOnlyList<int> ids)
		{
			return Pools.FindAll((PlacedPool p) => p.Lake.Exists && ids.Contains(p.Id));
		}

		internal static IReadOnlyList<PlacedPoolInfo> Snapshot()
		{
			List<PlacedPoolInfo> list = new List<PlacedPoolInfo>();
			foreach (PlacedPool pool in Pools)
			{
				if (pool.Lake.Exists)
				{
					list.Add(new PlacedPoolInfo(pool.Id, pool.Basin.Cells, pool.Basin.WaterLevel));
				}
			}
			return list;
		}

		internal static void Replace(List<PlacedPool> old, PlacedPool replacement, Character character)
		{
			foreach (PlacedPool item in old)
			{
				Remove(item, character);
			}
			Pools.Add(replacement);
			_nextId = replacement.Id + 1;
		}

		internal static void Add(PlacedPool pool)
		{
			Pools.Add(pool);
			_nextId = pool.Id + 1;
		}

		internal static List<PoolRecord> SavedRecords()
		{
			List<PoolRecord> list = new List<PoolRecord>();
			foreach (PlacedPool pool in Pools)
			{
				if (pool.Lake.Exists && pool.Saved)
				{
					list.Add(PoolRecord.From(pool.Basin, pool.Spacing, pool.Lake.Threshold));
				}
			}
			return list;
		}

		internal static void Drain(int id, Character character)
		{
			PlacedPool placedPool = Pools.Find((PlacedPool p) => p.Id == id);
			if (placedPool != null)
			{
				Remove(placedPool, character);
			}
		}

		private static void Remove(PlacedPool pool, Character character)
		{
			if (pool == _applied)
			{
				PlayerManager val = (((Object)(object)character != (Object)null) ? character._playerManager : null);
				if ((Object)(object)val != (Object)null)
				{
					val.RemoveWorldContext((PlayerWorldContext)(object)pool.Lake.Context);
				}
				_applied = null;
			}
			pool.Lake.Destroy();
			Pools.Remove(pool);
		}

		internal static PlacedPool FindCovering(Vector3 world)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlacedPool pool in Pools)
			{
				if (pool.Lake.Exists && pool.Covers(world))
				{
					return pool;
				}
			}
			return null;
		}

		internal static void ResetForWorld()
		{
			foreach (PlacedPool pool in Pools)
			{
				pool.Lake.Destroy();
			}
			Pools.Clear();
			_applied = null;
		}

		internal static int RemoveVanished()
		{
			if (_applied != null && !_applied.Lake.Exists)
			{
				_applied = null;
			}
			foreach (PlacedPool pool in Pools)
			{
				if (!pool.Lake.Exists)
				{
					pool.Lake.Destroy();
				}
			}
			return Pools.RemoveAll((PlacedPool p) => !p.Lake.Exists);
		}

		internal static void Tick(Character character)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			PoolStore.CheckVanished();
			if ((Object)(object)character == (Object)null)
			{
				return;
			}
			PlacedPool placedPool = ((Pools.Count == 0) ? null : FindCovering(((Component)character).transform.position));
			if (placedPool == _applied)
			{
				return;
			}
			PlayerManager playerManager = character._playerManager;
			if (!((Object)(object)playerManager == (Object)null))
			{
				if (_applied != null)
				{
					playerManager.RemoveWorldContext((PlayerWorldContext)(object)_applied.Lake.Context);
				}
				if (placedPool != null)
				{
					playerManager.ApplyWorldContext((PlayerWorldContext)(object)placedPool.Lake.Context);
				}
				_applied = placedPool;
			}
		}
	}
	internal static class PoolStore
	{
		private const string FileName = "pool";

		private const float LoadAfter = 3f;

		private static readonly PoolSaves Saves = new PoolSaves();

		private static float _startedAt;

		internal static bool Loaded => Saves.Loaded;

		internal static void Patch(Harmony harmony)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(StorageManager), "SaveCurrentSession", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(PoolStore), "BeforeSave", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(StorageManager), "_NotifyClientsOfSuccessfulSave", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(PoolStore), "AfterSave", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		internal static void ResetForWorld()
		{
			_startedAt = Time.time;
			Saves.StartWorld();
		}

		internal static void EndWorld(string why)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if (!Saves.Ended)
			{
				Saves.EndWorld();
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(62, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The world ended (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(why);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); a save from now on writes no Pools.");
				}
				log.LogInfo(val);
			}
		}

		internal static void CheckVanished()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			int num = PoolRegistry.RemoveVanished();
			if (num != 0)
			{
				Saves.LosePools();
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(92, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" Pool(s) lost their water without a drain; no later save this world writes the Pools.");
				}
				log.LogWarning(val);
			}
		}

		internal static void Tick()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			if (!Saves.ReadDue || !HostStatus.IsHost.HasValue || Time.time - _startedAt < 3f)
			{
				return;
			}
			if (HostStatus.IsHost != true)
			{
				Saves.Read(null);
				Plugin.Log.LogInfo((object)"[Pool] Saved Pools not read: this player joined another player's game.");
				return;
			}
			try
			{
				Load();
			}
			catch (Exception ex)
			{
				Saves.Read(null);
				Saves.Keep("reading the saved Pools failed");
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(69, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] Reading the saved Pools failed, so the file is kept as it is: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		private static void Load()
		{
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Expected O, but got Unknown
			if (!TryGetSessionFolder(out string session, out string folder))
			{
				Saves.Read(null);
				Saves.Keep("the save folder could not be found");
				Plugin.Log.LogWarning((object)"[Pool] Saved Pools not read: the save folder could not be found.");
				return;
			}
			Saves.Read(session);
			string text = Path.Combine(folder, "pool");
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (!File.Exists(text))
			{
				ManualLogSource log = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] No saved Pools in session ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(session);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
				return;
			}
			PoolRecords.ReadResult readResult = PoolRecords.Read(File.ReadAllText(text));
			if (readResult.Problem != null)
			{
				Saves.Keep(readResult.Problem);
				ManualLogSource log2 = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(63, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Pool] Saved Pools not read from ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(readResult.Problem);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(". The file is kept as it is.");
				}
				log2.LogWarning(val2);
				return;
			}
			int num = 0;
			foreach (PoolRecord record in readResult.Records)
			{
				int nextId = PoolRegistry.NextId;
				try
				{
					PoolLake poolLake = PoolLake.Build(nextId, record.Cells, record.Spacing, record.WaterLevel, record.Depth, record.Threshold);
					PoolRegistry.Add(new PlacedPool(nextId, record.ToBasin(), record.Spacing, poolLake, saved: true));
					num++;
					ManualLogSource log3 = Plugin.Log;
					val = new BepInExInfoLogInterpolatedStringHandler(62, 6, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] Rebuilt Pool #");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(nextId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(record.Cells.Count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" cells, level ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(record.WaterLevel, "F3");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", depth ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(record.Depth, "F2");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" m, threshold ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(record.Threshold);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(poolLake.SurfaceNote);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log3.LogInfo(val);
				}
				catch (Exception ex)
				{
					Saves.AddUnbuilt(record);
					ManualLogSource log4 = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(84, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Pool] A saved Pool of ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(record.Cells.Count);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" cells at level ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<double>(record.WaterLevel, "F3");
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" could not be rebuilt; it stays in the file: ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
					}
					log4.LogError(val3);
				}
			}
			ManualLogSource log5 = Plugin.Log;
			val = new BepInExInfoLogInterpolatedStringHandler(46, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] Rebuilt ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" of ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(readResult.Records.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" saved Pools from session ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(session);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
			}
			log5.LogInfo(val);
		}

		public static void BeforeSave()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				CheckVanished();
				TryGetSessionFolder(out string session, out string folder);
				string text = Saves.BeginSave(HostStatus.IsHost, session, folder, PoolRegistry.SavedRecords());
				if (text != null)
				{
					ManualLogSource log = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] Pools not saved: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(45, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Pool] Taking the Pools for the save failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val2);
			}
		}

		public static void AfterSave()
		{
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				PendingSave pendingSave = Saves.FinishSave();
				if (pendingSave == null)
				{
					return;
				}
				if (pendingSave.LeftOut > 0)
				{
					ManualLogSource log = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(76, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(pendingSave.LeftOut);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" Pool(s) not saved: the mask rectangle covers more than ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(4000000L);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" grid points.");
					}
					log.LogError(val);
				}
				string text = Path.Combine(pendingSave.Folder, "pool");
				if (pendingSave.Records.Count != 0 || File.Exists(text))
				{
					string text2 = text + ".tmp";
					File.WriteAllText(text2, PoolRecords.Write(pendingSave.Records));
					File.Move(text2, text, overwrite: true);
					ManualLogSource log2 = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(58, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Pool] Saved ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(pendingSave.Records.Count);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" Pools to session ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(pendingSave.Session);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(pendingSave.Unbuilt);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" not rebuilt this world).");
					}
					log2.LogInfo(val2);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] Saving the Pools failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log3.LogError(val);
			}
		}

		private static bool TryGetSessionFolder(out string session, out string folder)
		{
			session = null;
			folder = null;
			StorageManager val = default(StorageManager);
			if (!GameManagers.TryGet<StorageManager>(ref val) || (Object)(object)val == (Object)null)
			{
				return false;
			}
			session = val.ActiveSessionID;
			if (!string.IsNullOrEmpty(session) && val.TryGetSessionStoragePath(session, ref folder))
			{
				return !string.IsNullOrEmpty(folder);
			}
			return false;
		}
	}
	internal static class PoolSurface
	{
		internal const string ObjectPrefix = "AskaWaterWorks_Tile_";

		internal static GameObject Build(Transform pool, int id, LakeMask surfaceMask, float level, out SurfaceAssets assets, out string surfaceNote)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: 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_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			assets = null;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor((float)surfaceMask.WorldXMin, (float)surfaceMask.WorldZMin, (float)surfaceMask.WorldWidth, (float)surfaceMask.WorldDepth);
			string name;
			WaterTile val2 = LoadedLake.Tile(out name);
			if ((Object)(object)val2 == (Object)null)
			{
				surfaceNote = "no surface: no lake water tile in memory";
				return null;
			}
			GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject);
			((Object)val3).name = "AskaWaterWorks_Tile_" + id.ToString(CultureInfo.InvariantCulture);
			val3.transform.SetParent(pool, true);
			val3.transform.position = new Vector3(((Rect)(ref val)).center.x, level, ((Rect)(ref val)).center.y);
			WaterTile component = val3.GetComponent<WaterTile>();
			MeshRenderer highDetailWaterRenderer = component.highDetailWaterRenderer;
			Vector3 val4;
			if (!((Object)(object)highDetailWaterRenderer != (Object)null))
			{
				val4 = Vector3.zero;
			}
			else
			{
				Bounds bounds = ((Renderer)highDetailWaterRenderer).bounds;
				val4 = ((Bounds)(ref bounds)).size;
			}
			Vector3 val5 = val4;
			if (val5.x <= 0.01f || val5.z <= 0.01f)
			{
				Object.Destroy((Object)(object)val3);
				surfaceNote = "no surface: " + name + " gave a tile with no size";
				return null;
			}
			Vector3 localScale = val3.transform.localScale;
			val3.transform.localScale = new Vector3(localScale.x * ((Rect)(ref val)).width / val5.x, localScale.y, localScale.z * ((Rect)(ref val)).height / val5.z);
			Texture2D val6 = PoolLake.BuildTexture(surfaceMask);
			component.AssignLandMask((Texture)(object)val6, 0f, new Vector4(((Rect)(ref val)).xMin, ((Rect)(ref val)).yMin, ((Rect)(ref val)).xMax, ((Rect)(ref val)).yMax));
			assets = new SurfaceAssets(val6, CopiedMaterials(((Component)val2).gameObject, val3));
			surfaceNote = "surface from " + name;
			return val3;
		}

		private static List<Material> CopiedMaterials(GameObject source, GameObject copy)
		{
			HashSet<IntPtr> hashSet = new HashSet<IntPtr>();
			foreach (Renderer componentsInChild in source.GetComponentsInChildren<Renderer>(true))
			{
				foreach (Material item in (Il2CppArrayBase<Material>)(object)componentsInChild.sharedMaterials)
				{
					if ((Object)(object)item != (Object)null)
					{
						hashSet.Add(((Il2CppObjectBase)item).Pointer);
					}
				}
			}
			List<Material> list = new List<Material>();
			foreach (Renderer componentsInChild2 in copy.GetComponentsInChildren<Renderer>(true))
			{
				foreach (Material item2 in (Il2CppArrayBase<Material>)(object)componentsInChild2.sharedMaterials)
				{
					if ((Object)(object)item2 != (Object)null && hashSet.Add(((Il2CppObjectBase)item2).Pointer))
					{
						list.Add(item2);
					}
				}
			}
			return list;
		}
	}
	internal sealed class SurfaceAssets
	{
		private readonly Texture2D _mask;

		private readonly List<Material> _materials;

		internal SurfaceAssets(Texture2D mask, List<Material> materials)
		{
			_mask = mask;
			_materials = materials;
		}

		internal void Destroy()
		{
			if ((Object)(object)_mask != (Object)null)
			{
				Object.Destroy((Object)(object)_mask);
			}
			foreach (Material material in _materials)
			{
				if ((Object)(object)material != (Object)null)
				{
					Object.Destroy((Object)(object)material);
				}
			}
		}
	}
	public class PoolTool : MonoBehaviour
	{
		private void OnDisable()
		{
			LevelInput.Release();
		}

		private void Start()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (PoolWorld.Enter(((Component)this).gameObject.scene))
			{
				PoolRegistry.ResetForWorld();
				PoolStore.ResetForWorld();
			}
			PoolEntry.ResetForWorld();
			LoadedLake.ResetForWorld();
			TerrainHeightSource.ResetForWorld();
			JumpInput.ResetForWorld();
			PoolToolHost.ResetForWorld();
			HostStatus.ResetForWorld();
		}

		private void Update()
		{
			if (!Plugin.ConfigEnabled.Value)
			{
				PoolToolHost.WhileDisabled();
				return;
			}
			PoolRegistry.Tick(LocalPlayerTool.LocalCharacter);
			PoolClimb.Tick(LocalPlayerTool.LocalCharacter);
			HostStatus.Tick();
			PoolStore.Tick();
			PoolToolHost.Tick();
		}
	}
	internal static class PoolToolHost
	{
		private sealed class RealClock : IClock
		{
			public TimeSpan Now => TimeSpan.FromSeconds((double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency);
		}

		private static IntPtr _liveTool;

		private static DynamicDimensionsPlacementTool _toolObject;

		private static IntPtr _markerPointer;

		private static Renderer[] _markerRenderers = Array.Empty<Renderer>();

		private static ToolSession _session;

		private static double _spacing;

		private static bool _inert;

		private static bool _frameFaulted;

		private static bool _endToolAsked;

		internal static void ResetForWorld()
		{
			_inert = false;
			_frameFaulted = false;
			_liveTool = IntPtr.Zero;
			_session = null;
			_toolObject = null;
			_markerPointer = IntPtr.Zero;
			_markerRenderers = Array.Empty<Renderer>();
			PoolGhost.Hide();
			PoolPreview.End();
			LevelInput.Release();
		}

		internal static void Patch(Harmony harmony)
		{
			Type typeFromHandle = typeof(DynamicDimensionsPlacementTool);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeFromHandle, "Begin", new Type[1] { typeof(StructurePreviewData) }, (Type[])null), Hook("BeforeBegin"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeFromHandle, "Begin", new Type[1] { typeof(StructurePreviewData) }, (Type[])null), (HarmonyMethod)null, Hook("AfterBegin"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeFromHandle, "End", Type.EmptyTypes, (Type[])null), (HarmonyMethod)null, Hook("AfterEnd"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeFromHandle, "RefreshWidgetData", new Type[1] { typeof(IInteractionWidgetProvider) }, (Type[])null), Hook("BeforeRefreshWidget"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeFromHandle, "_OnSelect", Type.EmptyTypes, (Type[])null), Hook("BeforeSelect"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeFromHandle, "_OnSnap", Type.EmptyTypes, (Type[])null), Hook("BeforeSnap"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static void BeforeBegin(DynamicDimensionsPlacementTool __instance)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			try
			{
				PlayerBuilder builder = ((PlacementTool)__instance).Builder;
				if (!((Object)(object)builder == (Object)null) && PoolEntry.IsEntry(((StructureBuilder)builder).StructureTemplate))
				{
					_liveTool = ((Il2CppObjectBase)__instance).Pointer;
					_session = null;
					_frameFaulted = false;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(38, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The Pool tool failed to start: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		public static void AfterBegin(DynamicDimensionsPlacementTool __instance)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			if (_liveTool == IntPtr.Zero || ((Il2CppObjectBase)__instance).Pointer != _liveTool)
			{
				return;
			}
			try
			{
				_toolObject = __instance;
				_markerPointer = IntPtr.Zero;
				HideMarker();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(56, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The Pool tool failed to hide the field's marker: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		public static bool BeforeRefreshWidget(DynamicDimensionsPlacementTool __instance)
		{
			if (!(_liveTool == IntPtr.Zero))
			{
				return ((Il2CppObjectBase)__instance).Pointer != _liveTool;
			}
			return true;
		}

		public static void AfterEnd(DynamicDimensionsPlacementTool __instance)
		{
			if (!(_liveTool == IntPtr.Zero) && !(((Il2CppObjectBase)__instance).Pointer != _liveTool))
			{
				EndSession();
			}
		}

		private static void EndSession()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			try
			{
				LeaveBuildMode();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(36, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The Pool tool failed to end: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
			finally
			{
				_liveTool = IntPtr.Zero;
				_session = null;
				_toolObject = null;
				_markerRenderers = Array.Empty<Renderer>();
				PoolGhost.Hide();
				PoolPreview.End();
				LevelInput.Release();
			}
		}

		public static bool BeforeSelect(DynamicDimensionsPlacementTool __instance)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (!IsLive(__instance))
			{
				return true;
			}
			_endToolAsked = false;
			try
			{
				LeftClick();
				if (_endToolAsked)
				{
					EndTool(__instance);
				}
			}
			catch (Exception ex)
			{
				DropSession();
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The Pool tool failed on a click: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
			return false;
		}

		private static void EndTool(DynamicDimensionsPlacementTool tool)
		{
			PlayerBuilder builder = ((PlacementTool)tool).Builder;
			if (!((Object)(object)builder == (Object)null))
			{
				((StructureBuilder)builder).StructureTemplate = null;
			}
		}

		public static bool BeforeSnap(DynamicDimensionsPlacementTool __instance)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			if (!IsLive(__instance))
			{
				return true;
			}
			try
			{
				if (_session != null && !_inert && Plugin.ConfigEnabled.Value)
				{
					Apply(_session.RightClick());
				}
			}
			catch (Exception ex)
			{
				DropSession();
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(46, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The Pool tool failed on a right click: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
			return false;
		}

		internal static void Tick()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			if (_liveTool == IntPtr.Zero)
			{
				return;
			}
			try
			{
				HideMarker();
				if (_inert)
				{
					PoolGhost.Hide();
					LevelInput.Release();
					return;
				}
				ShowGhost();
				if (_session == null)
				{
					LevelInput.Release();
					return;
				}
				int num = LevelInput.Read(PoolPreview.Showing);
				bool searching = _session.Searching;
				if (num != 0)
				{
					Apply(_session.LevelStep(num));
				}
				if (num == 0 || searching)
				{
					Apply(_session.Tick());
				}
			}
			catch (Exception ex)
			{
				DropSession();
				if (!_frameFaulted)
				{
					_frameFaulted = true;
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(72, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Pool] The Pool tool failed on a frame, and the next frames stay quiet: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}

		internal static void WhileDisabled()
		{
			_inert = true;
			PoolGhost.Hide();
			LevelInput.Release();
			if (_session == null)
			{
				return;
			}
			try
			{
				LeaveBuildMode();
			}
			finally
			{
				_session = null;
				PoolPreview.End();
			}
		}

		private static void HideMarker()
		{
			GameObject val = (((Object)(object)_toolObject != (Object)null) ? _toolObject._marker : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (((Il2CppObjectBase)val).Pointer != _markerPointer)
			{
				_markerPointer = ((Il2CppObjectBase)val).Pointer;
				_markerRenderers = Il2CppArrayBase<Renderer>.op_Implicit(val.GetComponentsInChildren<Renderer>(true));
			}
			Renderer[] markerRenderers = _markerRenderers;
			foreach (Renderer val2 in markerRenderers)
			{
				if ((Object)(object)val2 != (Object)null && val2.enabled)
				{
					val2.enabled = false;
				}
			}
		}

		private static void ShowGhost()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ConfigEnabled.Value)
			{
				PoolGhost.Hide();
				return;
			}
			Character localCharacter = LocalPlayerTool.LocalCharacter;
			if (Aim.TryAimAtTerrain(((Object)(object)localCharacter != (Object)null) ? ((Component)localCharacter).transform : null, out var point))
			{
				PoolGhost.Show(point);
			}
			else
			{
				PoolGhost.Hide();
			}
		}

		private static bool IsLive(DynamicDimensionsPlacementTool tool)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missin