Decompiled source of TunnelheimCompanion v0.8.3

plugins/TunnelheimBuildingFix.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("TunnelheimBuildingFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.8.3.0")]
[assembly: AssemblyInformationalVersion("0.8.3")]
[assembly: AssemblyProduct("TunnelheimBuildingFix")]
[assembly: AssemblyTitle("TunnelheimBuildingFix")]
[assembly: AssemblyVersion("0.8.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TunnelheimBuildingFix
{
	internal static class AcceptedLoweringPlan
	{
		internal struct Step
		{
			internal float Reference;

			internal float Target;

			internal Step(float r, float t)
			{
				Reference = r;
				Target = t;
			}
		}

		internal static List<Step> Create(float top, float accepted)
		{
			if (float.IsNaN(top) || float.IsInfinity(top) || float.IsNaN(accepted) || float.IsInfinity(accepted) || top - accepted > 128f)
			{
				throw new ArgumentException("Unsupported surface heights");
			}
			List<Step> list = new List<Step>();
			float num = top;
			while (num > accepted + 0.0001f)
			{
				float num2 = Math.Max(accepted, num - 7.5f);
				list.Add(new Step(num, num2));
				num = num2;
			}
			return list;
		}
	}
	internal static class AcceptedSurfacePlan
	{
		internal struct Step
		{
			internal float Reference;

			internal float Target;

			internal Step(float r, float t)
			{
				Reference = r;
				Target = t;
			}
		}

		internal static List<Step> Create(float before, float accepted, float top, bool allowRaise)
		{
			if (!Finite(before) || !Finite(accepted) || !Finite(top) || Math.Abs(accepted - top) > 128f)
			{
				throw new ArgumentException("Unsupported accepted surface height");
			}
			List<Step> list = new List<Step>();
			if (Math.Abs(accepted - before) < 0.0001f)
			{
				return list;
			}
			bool flag = accepted < before;
			if (flag && accepted >= top - 0.0001f)
			{
				return list;
			}
			if (!flag && (!allowRaise || accepted <= top + 0.0001f))
			{
				return list;
			}
			float num = top;
			while (Math.Abs(accepted - num) > 0.0001f)
			{
				float num2 = (flag ? Math.Max(accepted, num - 7.5f) : Math.Min(accepted, num + 7.5f));
				list.Add(new Step(num, num2));
				num = num2;
			}
			return list;
		}

		internal static bool Exterior(float hit, float top)
		{
			if (Finite(hit) && Finite(top))
			{
				return hit >= top - 0.75f;
			}
			return false;
		}

		internal static bool Finite(float x)
		{
			if (!float.IsNaN(x))
			{
				return !float.IsInfinity(x);
			}
			return false;
		}

		internal static bool NativeOnlyAction(string name)
		{
			if (name != "LevelWall" && name != "LevelCeiling")
			{
				return name != "CarveStairs";
			}
			return false;
		}
	}
	public static class CanalCutLimits
	{
		public const double Minimum = 0.25;

		public const double Maximum = 3.0;

		public const double Default = 0.75;

		public static void Validate(double size)
		{
			if (!RouteMath.Finite(size) || size < 0.25 || size > 3.0)
			{
				throw new ArgumentException("Canal cut size must be 0.25 to 3 metres.");
			}
		}

		public static IEnumerable<double> Radii(double size)
		{
			Validate(size);
			yield return size;
			double[] array = new double[8] { 2.5, 2.0, 1.5, 1.0, 0.75, 0.5, 0.35, 0.25 };
			foreach (double num in array)
			{
				if (num < size - 1E-08)
				{
					yield return num;
				}
			}
		}
	}
	internal sealed class CanalMode : MonoBehaviour
	{
		internal sealed class DigState
		{
			internal bool Value;
		}

		private static BaseUnityPlugin owner = null;

		private static BaseUnityPlugin upstream = null;

		private static Type world = null;

		private static Type opType = null;

		private static Type chunk = null;

		private static MethodInfo shaped = null;

		private static MethodInfo makeCarve = null;

		private static MethodInfo seed = null;

		private static MethodInfo known = null;

		private static MethodInfo column = null;

		private static MethodInfo primary = null;

		private static MethodInfo typing = null;

		private static MethodInfo modifier = null;

		private static FieldInfo registry = null;

		private static FieldInfo square = null;

		private static FieldInfo straight = null;

		private static FieldInfo key = null;

		private static FieldInfo undoKey = null;

		private static FieldInfo straightKey = null;

		private static ConfigEntry<bool> featureEnabled = null;

		private static ConfigEntry<float> cutSize = null;

		private static FieldInfo locations = null;

		private static readonly ManualLogSource Log = Logger.CreateLogSource("Centerline Canal");

		private static bool selected;

		private static float nextMessage;

		private static int lastFrame = -1;

		[ThreadStatic]
		private static object? plannedOp;

		internal static float CutSize
		{
			get
			{
				float value = cutSize.Value;
				if (!float.IsNaN(value) && !float.IsInfinity(value))
				{
					return Mathf.Clamp(value, 0.25f, 3f);
				}
				return 0.75f;
			}
			set
			{
				CanalCutLimits.Validate(value);
				cutSize.Value = value;
			}
		}

		internal static bool Selected => selected;

		internal static void Install(BaseUnityPlugin plugin, BaseUnityPlugin tunnel, Harmony h)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Expected O, but got Unknown
			//IL_03aa: Expected O, but got Unknown
			//IL_0412: Unknown result type (might be due to invalid IL or missing references)
			//IL_0417: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Expected O, but got Unknown
			//IL_044f: Expected O, but got Unknown
			//IL_044f: Expected O, but got Unknown
			owner = plugin;
			upstream = tunnel;
			Assembly assembly = ((object)tunnel).GetType().Assembly;
			world = assembly.GetType("ValheimTunneling.VoxelWorld", throwOnError: true);
			opType = assembly.GetType("ValheimTunneling.VoxelOp", throwOnError: true);
			chunk = assembly.GetType("ValheimTunneling.VoxelChunk", throwOnError: true);
			featureEnabled = plugin.Config.Bind<bool>("Canal", "Enabled", true, "Experimental local centerline planner. Confirm a guide, then excavate with ordinary pickaxe strikes.");
			cutSize = plugin.Config.Bind<float>("Canal", "CutSize", 0.75f, new ConfigDescription("Canal-only maximum sphere radius and depth per accepted dig, 0.25-3 m. Larger cuts retain normal per-swing costs and per-dig stone drops. Smaller cutters are used near banks/bed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), Array.Empty<object>()));
			locations = AccessTools.Field(typeof(Location), "s_allLocations") ?? throw new Exception("Missing protected location registry");
			if (!typeof(IEnumerable<Location>).IsAssignableFrom(locations.FieldType))
			{
				throw new Exception("Changed protected location registry");
			}
			registry = AccessTools.Field(world, "s_syncs") ?? throw new Exception("Missing Canal sync registry");
			if (!typeof(IDictionary).IsAssignableFrom(registry.FieldType))
			{
				throw new Exception("Changed Canal sync registry contract");
			}
			square = NeedField(world, "SquareDig", typeof(bool));
			straight = NeedField(world, "DigStraight", typeof(bool));
			Type type = ((object)tunnel).GetType();
			key = NeedField(type, "_squareDigKey", typeof(ConfigEntry<KeyCode>));
			undoKey = NeedField(type, "_undoKey", typeof(ConfigEntry<KeyCode>));
			straightKey = NeedField(type, "_digStraightKey", typeof(ConfigEntry<KeyCode>));
			typing = Need(type, "IsTyping", Type.EmptyTypes);
			modifier = Need(type, "ModifierHeld", Type.EmptyTypes);
			shaped = Need(world, "ShapedDig", new Type[4]
			{
				typeof(Character),
				typeof(Vector3),
				typeof(Vector3),
				typeof(float)
			});
			makeCarve = Need(opType, "MakeCarve", new Type[2]
			{
				typeof(Vector3),
				typeof(float)
			});
			seed = Need(world, "SeedHeight", new Type[2]
			{
				typeof(float),
				typeof(float)
			});
			known = Need(world, "HasSavedTunnel", new Type[1] { typeof(Vector3) });
			column = Need(world, "IsVoxelColumnAt", new Type[2]
			{
				typeof(float),
				typeof(float)
			});
			primary = Need(world, "PrimarySync", new Type[1] { typeof(Vector2Int) });
			if (shaped.ReturnType != opType || makeCarve.ReturnType != opType)
			{
				throw new Exception("Changed Canal operation contract");
			}
			h.Patch((MethodBase)Need(type, "Update", Type.EmptyTypes), new HarmonyMethod(typeof(CanalMode), "ShapeBefore", (Type[])null), new HarmonyMethod(typeof(CanalMode), "ShapeAfter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			h.Patch((MethodBase)Need(world, "Dig", new Type[5]
			{
				typeof(Character),
				typeof(Vector3),
				typeof(Vector3),
				typeof(TerrainOp),
				typeof(ItemData)
			}), new HarmonyMethod(typeof(CanalMode), "BeforeDig", (Type[])null)
			{
				priority = 0
			}, (HarmonyMethod)null, new HarmonyMethod(typeof(CanalMode), "ReplaceShape", (Type[])null), new HarmonyMethod(typeof(CanalMode), "AfterDig", (Type[])null), (HarmonyMethod)null);
			RoutePlanner.Install(plugin, h);
			((Component)plugin).gameObject.AddComponent<CanalMode>();
			selected = false;
			Log.LogInfo((object)"Centerline Canal: native sphere save/undo/network format retained; local guides are not shared plans.");
		}

		private static MethodInfo Need(Type t, string n, Type[] a)
		{
			return AccessTools.Method(t, n, a, (Type[])null) ?? throw new Exception("Missing Canal contract " + n);
		}

		private static FieldInfo NeedField(Type t, string n, Type value)
		{
			FieldInfo fieldInfo = AccessTools.Field(t, n);
			if (fieldInfo == null || fieldInfo.FieldType != value)
			{
				throw new Exception("Changed Canal field " + n);
			}
			return fieldInfo;
		}

		private static KeyCode Key(FieldInfo f)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return ((ConfigEntry<KeyCode>)f.GetValue(upstream)).Value;
		}

		private static void ShapeBefore(out int __state)
		{
			//IL_0048: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			__state = -1;
			if (featureEnabled.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && !(bool)typing.Invoke(null, null) && !(bool)modifier.Invoke(null, null) && (int)Key(key) != 0 && ZInput.GetKeyDown(Key(key), false) && !ZInput.GetKeyDown(Key(undoKey), false) && !ZInput.GetKeyDown(Key(straightKey), false))
			{
				KeyboardShortcut value = owner.Config.Bind<KeyboardShortcut>("Excavation", "ToggleKey", new KeyboardShortcut((KeyCode)285, Array.Empty<KeyCode>()), (ConfigDescription)null).Value;
				if (((KeyboardShortcut)(ref value)).MainKey == Key(key))
				{
					selected = false;
					RoutePlanner.Close();
					Warn("Canal shape key conflicts with excavation toggle.");
				}
				else
				{
					__state = (selected ? 2 : (((bool)square.GetValue(null)) ? 1 : 0));
				}
			}
		}

		private static void ShapeAfter(int __state)
		{
			if (__state >= 0)
			{
				Choose((__state + 1) % 3);
			}
		}

		internal static void Choose(int mode)
		{
			selected = mode == 2;
			square.SetValue(null, mode == 1);
			plannedOp = null;
			if (selected)
			{
				RoutePlanner.Open();
			}
			else
			{
				RoutePlanner.Close();
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, selected ? "Canal: plot and confirm a centerline." : ((mode == 1) ? "Pickaxe: square digs" : "Pickaxe: round digs"), 0, (Sprite)null, false);
			}
		}

		private static bool LocalCanal(Character a)
		{
			if (featureEnabled.Value && selected && ExcavationMode.Enabled && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				return (Object)(object)a == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		internal static bool TerrainCollider(Collider c)
		{
			if (!((Object)(object)((Component)c).GetComponent<Heightmap>() != (Object)null))
			{
				return (Object)(object)((Component)c).GetComponentInParent(chunk) != (Object)null;
			}
			return true;
		}

		internal static float Surface(Vector3 at)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			float num = float.NegativeInfinity;
			RaycastHit[] array = Physics.RaycastAll(new Vector3(at.x, 200f, at.z), Vector3.down, 400f, LayerMask.GetMask(new string[2] { "terrain", "static_solid" }), (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if (TerrainCollider(((RaycastHit)(ref val)).collider))
				{
					num = Mathf.Max(num, ((RaycastHit)(ref val)).point.y);
				}
			}
			if (float.IsNegativeInfinity(num))
			{
				throw new Exception("Terrain not loaded; move closer or shorten route.");
			}
			return num;
		}

		internal static void Ready(Vector3 at)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			bool loaded = (bool)column.Invoke(null, new object[2] { at.x, at.z });
			bool saved = (bool)known.Invoke(null, new object[1] { at });
			Vector2Int val = default(Vector2Int);
			((Vector2Int)(ref val))..ctor(Mathf.FloorToInt(at.x / 16f), Mathf.FloorToInt(at.z / 16f));
			bool registered = ((IDictionary)registry.GetValue(null)).Contains(val);
			object obj = primary.Invoke(null, new object[1] { val });
			bool valid = false;
			bool built = false;
			bool pending = false;
			bool unreadable = false;
			if (obj != null)
			{
				valid = (bool)AccessTools.Property(obj.GetType(), "IsValid").GetValue(obj, null);
				built = (bool)AccessTools.Property(obj.GetType(), "Built").GetValue(obj, null);
				pending = (bool)AccessTools.Property(obj.GetType(), "IsPending").GetValue(obj, null);
				unreadable = (bool)AccessTools.Property(obj.GetType(), "Unreadable").GetValue(obj, null);
			}
			if (!CanalReadiness.CanEdit(saved, registered, loaded, obj != null, valid, built, pending, unreadable))
			{
				throw new Exception("Terrain is still loading or synchronizing.");
			}
		}

		private unsafe static bool BeforeDig(Character attacker, Vector3 point, TerrainOp op, ItemData weapon, out DigState? __state)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: 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_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			plannedOp = null;
			if (!LocalCanal(attacker))
			{
				return true;
			}
			if (lastFrame == Time.frameCount)
			{
				return false;
			}
			lastFrame = Time.frameCount;
			try
			{
				if (RoutePlanner.AttackBlocking)
				{
					throw new Exception("Confirm guide and close planner before excavating.");
				}
				RouteSurface routeSurface = RoutePlanner.Guide ?? throw new Exception("No confirmed guide. Cycle back to Canal to plot or load one.");
				if (weapon == null || (Object)(object)op == (Object)null || weapon.m_shared.m_damages.m_pickaxe <= 0f)
				{
					throw new Exception("Canal requires a pickaxe terrain strike.");
				}
				Ready(point);
				float num = Surface(point);
				if (Mathf.Abs(num - point.y) > 1.1f)
				{
					throw new Exception("Canal cuts start at the upper surface; use Round or Square underground.");
				}
				if (!routeSurface.TryCut(point.x, point.z, num, CutSize, out var centerY, out var radius))
				{
					throw new Exception("Bank target reached, or outside confirmed guide.");
				}
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(point.x, (float)centerY, point.z);
				float num2 = (float)radius;
				float num3 = num2 + 1f;
				foreach (Location item in (IEnumerable<Location>)locations.GetValue(null))
				{
					if ((Object)(object)item != (Object)null && item.m_noBuild && item.IsInside(val, num3, true))
					{
						throw new Exception("Canal cut overlaps a protected location.");
					}
				}
				for (float num4 = val.x - num3; num4 <= val.x + num3 + 0.01f; num4 += 0.5f)
				{
					for (float num5 = val.z - num3; num5 <= val.z + num3 + 0.01f; num5 += 0.5f)
					{
						Vector3 val2 = new Vector3(num4, val.y, num5);
						Ready(val2);
						if (Location.IsInsideNoBuildLocation(val2))
						{
							throw new Exception("Protected location.");
						}
						if ((float)seed.Invoke(null, new object[2] { num4, num5 }) - (val.y - num2) > 63f)
						{
							throw new Exception("Tunnelheim depth limit.");
						}
					}
				}
				if (!PrivateArea.CheckAccess(val, num3, true, false))
				{
					throw new Exception("Protected Canal cut.");
				}
				plannedOp = makeCarve.Invoke(null, new object[2] { val, num2 });
				__state = new DigState
				{
					Value = (bool)straight.GetValue(null)
				};
				straight.SetValue(null, false);
				ManualLogSource log = Log;
				string[] obj = new string[9]
				{
					"CENTERLINE CUT guide=",
					routeSurface.Revision.ToString(),
					" center=",
					null,
					null,
					null,
					null,
					null,
					null
				};
				Vector3 val3 = val;
				obj[3] = ((object)(*(Vector3*)(&val3))/*cast due to .constrained prefix*/).ToString();
				obj[4] = " radius=";
				obj[5] = num2.ToString();
				obj[6] = " requestedSize=";
				obj[7] = CutSize.ToString();
				obj[8] = " one native sphere/cost/drop/save/undo";
				log.LogInfo((object)string.Concat(obj));
				return true;
			}
			catch (Exception ex)
			{
				Warn(ex.GetBaseException().Message);
				return false;
			}
		}

		private static Exception? AfterDig(Exception? __exception, DigState? __state)
		{
			if (__state != null)
			{
				straight.SetValue(null, __state.Value);
			}
			plannedOp = null;
			return __exception;
		}

		public static object Shape(Character a, Vector3 p, Vector3 d, float size)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (LocalCanal(a))
			{
				if (plannedOp == null)
				{
					throw new Exception("Missing Canal operation");
				}
				return plannedOp;
			}
			return shaped.Invoke(null, new object[4] { a, p, d, size });
		}

		private static IEnumerable<CodeInstruction> ReplaceShape(IEnumerable<CodeInstruction> source)
		{
			List<CodeInstruction> list = source.ToList();
			CodeInstruction[] array = list.Where((CodeInstruction x) => CodeInstructionExtensions.Calls(x, shaped)).ToArray();
			if (array.Length != 1)
			{
				throw new Exception("Expected one ShapedDig call");
			}
			DynamicMethod dynamicMethod = new DynamicMethod("CompanionCanalShape", opType, new Type[4]
			{
				typeof(Character),
				typeof(Vector3),
				typeof(Vector3),
				typeof(float)
			}, typeof(CanalMode), skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			for (int num = 0; num < 4; num++)
			{
				iLGenerator.Emit(OpCodes.Ldarg, num);
			}
			iLGenerator.Emit(OpCodes.Call, AccessTools.Method(typeof(CanalMode), "Shape", (Type[])null, (Type[])null));
			iLGenerator.Emit(OpCodes.Unbox_Any, opType);
			iLGenerator.Emit(OpCodes.Ret);
			array[0].operand = dynamicMethod;
			return list;
		}

		private static void Warn(string message)
		{
			if (!(Time.realtimeSinceStartup < nextMessage))
			{
				nextMessage = Time.realtimeSinceStartup + 1f;
				Log.LogWarning((object)message);
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
				}
			}
		}
	}
	public static class CanalPlanMath
	{
		public static double CutBottom(double exposedSurface, double targetFloor)
		{
			if (double.IsNaN(exposedSurface) || double.IsInfinity(exposedSurface) || double.IsNaN(targetFloor) || double.IsInfinity(targetFloor))
			{
				throw new ArgumentException("Invalid Canal surface");
			}
			return Math.Max(targetFloor, Math.Ceiling(exposedSurface - 0.001) - 2.0);
		}

		public static double BankFloor(double lateral, double width, double bed, double slope)
		{
			return bed + Math.Max(Math.Abs(lateral) - width / 2.0, 0.0) / slope;
		}

		public static bool Cell(double x, double z, double size, double width, double length, double bed, double slope, out double cx, out double cz, out double floor)
		{
			cx = (Math.Floor(x / size) + 0.5) * size;
			cz = (0.0 - length) / 2.0 + (Math.Floor((z + length / 2.0) / size) + 0.5) * size;
			floor = BankFloor(Math.Abs(cx) + size / 2.0, width, bed, slope);
			return Math.Abs(cz) + size / 2.0 <= length / 2.0 + 0.0001;
		}

		public static double Resolve(double width, double length, double bed, double slope, double maxWidth, Func<double, double, double> height)
		{
			double num = Math.Max(bed + 2.0, Math.Ceiling(height(0.0, 0.0) + 2.0));
			for (int i = 0; i < 8; i++)
			{
				double num2 = width / 2.0 + (num - bed) * slope;
				if (num2 * 2.0 > maxWidth)
				{
					throw new InvalidOperationException("Surrounding hillside exceeds the configured Canal opening width; choose a lower route.");
				}
				double num3 = bed;
				for (double num4 = 0.0 - Math.Ceiling(num2); num4 <= Math.Ceiling(num2); num4 += 1.0)
				{
					for (double num5 = (0.0 - length) / 2.0; num5 <= length / 2.0; num5 += 1.0)
					{
						double num6 = height(num4, num5);
						if (double.IsNaN(num6) || double.IsInfinity(num6))
						{
							throw new InvalidOperationException("Canal terrain is not loaded; move closer and retry.");
						}
						num3 = Math.Max(num3, num6);
					}
				}
				double num7 = Math.Ceiling(num3 + 2.0);
				if (num7 <= num)
				{
					return num;
				}
				num = num7;
			}
			throw new InvalidOperationException("Canal hillside bound did not converge; choose a lower route.");
		}
	}
	public static class CanalReadiness
	{
		public static bool CanEdit(bool saved, bool registered, bool loaded, bool primary, bool valid, bool built, bool pending, bool unreadable)
		{
			if (!saved && !registered && !primary)
			{
				return true;
			}
			if (loaded && primary && valid && built && !pending)
			{
				return !unreadable;
			}
			return false;
		}
	}
	internal static class CanalUi
	{
		internal sealed class Scope : IDisposable
		{
			private readonly GUISkin previous;

			private readonly Color color;

			private readonly Color background;

			private readonly Color content;

			internal Scope()
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: 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_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: 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_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				previous = GUI.skin;
				color = GUI.color;
				background = GUI.backgroundColor;
				content = GUI.contentColor;
				Ensure();
				GUI.skin = skin;
				GUI.color = (GUI.backgroundColor = (GUI.contentColor = Color.white));
			}

			public void Dispose()
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				GUI.skin = previous;
				GUI.color = color;
				GUI.backgroundColor = background;
				GUI.contentColor = content;
			}
		}

		private static GUISkin? skin;

		private static GUIStyle? section;

		private static GUIStyle? muted;

		private static GUIStyle? primary;

		private static GUIStyle? danger;

		private static GUIStyle? marker;

		private static readonly List<Texture2D> textures = new List<Texture2D>();

		private static readonly Color Gold = new Color(0.87f, 0.72f, 0.42f);

		private static readonly Color Text = new Color(0.91f, 0.87f, 0.76f);

		internal static string FontName
		{
			get
			{
				if (!((Object)(object)skin != (Object)null) || !((Object)(object)skin.font != (Object)null))
				{
					return "default";
				}
				return ((Object)skin.font).name;
			}
		}

		private static Texture2D Texture(Color fill, Color border)
		{
			//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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false)
			{
				name = "Companion UI",
				hideFlags = (HideFlags)61,
				filterMode = (FilterMode)0
			};
			for (int i = 0; i < 16; i++)
			{
				for (int j = 0; j < 16; j++)
				{
					bool flag = j < 1 || i < 1 || j > 14 || i > 14;
					float num = (float)((j * 7 + i * 3) % 5) * 0.002f;
					val.SetPixel(j, i, (Color)(flag ? border : new Color(fill.r + num, fill.g + num, fill.b + num, fill.a)));
				}
			}
			val.Apply();
			textures.Add(val);
			return val;
		}

		private static void Paint(GUIStyle s, Texture2D normal, Texture2D hover, Color color)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			GUIStyleState[] array = (GUIStyleState[])(object)new GUIStyleState[2] { s.normal, s.onNormal };
			foreach (GUIStyleState obj in array)
			{
				obj.background = normal;
				obj.textColor = color;
			}
			array = (GUIStyleState[])(object)new GUIStyleState[6] { s.hover, s.active, s.focused, s.onHover, s.onActive, s.onFocused };
			foreach (GUIStyleState obj2 in array)
			{
				obj2.background = hover;
				obj2.textColor = Color.white;
			}
		}

		private static void Ensure()
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: 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_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			//IL_01f8: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Expected O, but got Unknown
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Expected O, but got Unknown
			//IL_026b: Expected O, but got Unknown
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Expected O, but got Unknown
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Expected O, but got Unknown
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Expected O, but got Unknown
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Expected O, but got Unknown
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Expected O, but got Unknown
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Expected O, but got Unknown
			//IL_0348: Expected O, but got Unknown
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Expected O, but got Unknown
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Expected O, but got Unknown
			//IL_03f1: Expected O, but got Unknown
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Expected O, but got Unknown
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_0447: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Expected O, but got Unknown
			//IL_0456: Expected O, but got Unknown
			//IL_0463: Unknown result type (might be due to invalid IL or missing references)
			//IL_047c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_049b: Expected O, but got Unknown
			//IL_04a0: Expected O, but got Unknown
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e6: Expected O, but got Unknown
			//IL_04eb: Expected O, but got Unknown
			//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0510: Unknown result type (might be due to invalid IL or missing references)
			//IL_0518: Unknown result type (might be due to invalid IL or missing references)
			//IL_051f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_052f: Expected O, but got Unknown
			//IL_0534: Expected O, but got Unknown
			//IL_053e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Unknown result type (might be due to invalid IL or missing references)
			//IL_0557: Unknown result type (might be due to invalid IL or missing references)
			//IL_0564: Expected O, but got Unknown
			//IL_057d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0591: Unknown result type (might be due to invalid IL or missing references)
			//IL_0596: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a2: Expected O, but got Unknown
			//IL_05a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c7: Expected O, but got Unknown
			//IL_05df: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0608: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Unknown result type (might be due to invalid IL or missing references)
			//IL_061c: Expected O, but got Unknown
			//IL_0632: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)skin != (Object)null))
			{
				skin = Object.Instantiate<GUISkin>(GUI.skin);
				((Object)skin).hideFlags = (HideFlags)61;
				Font val = (from f in Resources.FindObjectsOfTypeAll<Font>()
					where ((Object)f).name.IndexOf("Averia", StringComparison.OrdinalIgnoreCase) >= 0
					orderby (((Object)f).name.IndexOf("Italic", StringComparison.OrdinalIgnoreCase) < 0) ? ((((Object)f).name.IndexOf("Bold", StringComparison.OrdinalIgnoreCase) >= 0) ? 2 : 0) : 3, (((Object)f).name.IndexOf("Regular", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0
					select f).FirstOrDefault();
				if ((Object)(object)val != (Object)null)
				{
					skin.font = val;
				}
				Texture2D val2 = Texture(new Color(0.075f, 0.067f, 0.052f, 0.98f), new Color(0.42f, 0.34f, 0.19f));
				Texture2D val3 = Texture(new Color(0.2f, 0.16f, 0.105f, 0.99f), new Color(0.43f, 0.35f, 0.2f));
				Texture2D val4 = Texture(new Color(0.34f, 0.26f, 0.13f), Gold);
				Texture2D normal = Texture(new Color(0.25f, 0.1f, 0.075f), new Color(0.58f, 0.29f, 0.2f));
				Texture2D hover = Texture(new Color(0.39f, 0.15f, 0.09f), new Color(0.85f, 0.44f, 0.25f));
				skin.window = new GUIStyle(skin.window)
				{
					font = skin.font,
					fontSize = 22,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)1,
					padding = new RectOffset(16, 16, 42, 14),
					border = new RectOffset(2, 2, 2, 2)
				};
				Paint(skin.window, val2, val2, Gold);
				skin.label = new GUIStyle(skin.label)
				{
					font = skin.font,
					fontSize = 15,
					wordWrap = true,
					richText = false,
					padding = new RectOffset(2, 2, 3, 3),
					margin = new RectOffset(2, 2, 2, 3)
				};
				skin.label.normal.textColor = Text;
				skin.button = new GUIStyle(skin.button)
				{
					font = skin.font,
					fontSize = 15,
					wordWrap = true,
					alignment = (TextAnchor)4,
					padding = new RectOffset(8, 8, 7, 7),
					margin = new RectOffset(3, 3, 4, 4),
					border = new RectOffset(2, 2, 2, 2),
					fixedHeight = 0f
				};
				Paint(skin.button, val3, val4, Text);
				skin.box = new GUIStyle(skin.box)
				{
					padding = new RectOffset(8, 8, 6, 6),
					border = new RectOffset(2, 2, 2, 2)
				};
				Paint(skin.box, val2, val2, Text);
				Texture2D val5 = Texture(new Color(0.12f, 0.1f, 0.07f), new Color(0.36f, 0.29f, 0.16f));
				Texture2D normal2 = Texture(Gold, new Color(0.95f, 0.84f, 0.57f));
				skin.horizontalSlider = new GUIStyle(skin.horizontalSlider)
				{
					fixedHeight = 8f,
					margin = new RectOffset(8, 8, 10, 10),
					border = new RectOffset(2, 2, 2, 2)
				};
				Paint(skin.horizontalSlider, val5, val5, Text);
				skin.horizontalSliderThumb = new GUIStyle(skin.horizontalSliderThumb)
				{
					fixedWidth = 15f,
					fixedHeight = 20f,
					overflow = new RectOffset(0, 0, 6, 6),
					border = new RectOffset(2, 2, 2, 2)
				};
				Paint(skin.horizontalSliderThumb, normal2, val4, Text);
				skin.verticalScrollbar = new GUIStyle(skin.verticalScrollbar)
				{
					fixedWidth = 12f,
					border = new RectOffset(1, 1, 1, 1)
				};
				Paint(skin.verticalScrollbar, val5, val5, Text);
				skin.verticalScrollbarThumb = new GUIStyle(skin.verticalScrollbarThumb)
				{
					fixedWidth = 12f,
					border = new RectOffset(1, 1, 1, 1)
				};
				Paint(skin.verticalScrollbarThumb, val3, val4, Text);
				section = new GUIStyle(skin.label)
				{
					fontSize = 16,
					fontStyle = (FontStyle)1,
					margin = new RectOffset(2, 2, 12, 5)
				};
				section.normal.textColor = Gold;
				muted = new GUIStyle(skin.label)
				{
					fontSize = 13
				};
				muted.normal.textColor = new Color(0.73f, 0.71f, 0.64f);
				primary = new GUIStyle(skin.button)
				{
					fontStyle = (FontStyle)1
				};
				Paint(primary, val4, val3, Gold);
				danger = new GUIStyle(skin.button);
				Paint(danger, normal, hover, new Color(1f, 0.81f, 0.7f));
				marker = new GUIStyle(skin.box)
				{
					font = skin.font,
					fontSize = 15,
					alignment = (TextAnchor)4
				};
				Paint(marker, val2, val2, new Color(1f, 0.55f, 0.95f));
			}
		}

		internal static void Section(string text)
		{
			GUILayout.Label(text, section, Array.Empty<GUILayoutOption>());
		}

		internal static void Hint(string text)
		{
			GUILayout.Label(text, muted, Array.Empty<GUILayoutOption>());
		}

		internal static bool Primary(string text)
		{
			return GUILayout.Button(text, primary, Array.Empty<GUILayoutOption>());
		}

		internal static bool Danger(string text)
		{
			return GUILayout.Button(text, danger, Array.Empty<GUILayoutOption>());
		}

		internal static void Marker(Rect rect, string text)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(rect, text, marker);
		}

		internal static void Release()
		{
			foreach (Texture2D texture in textures)
			{
				if ((Object)(object)texture != (Object)null)
				{
					Object.Destroy((Object)(object)texture);
				}
			}
			textures.Clear();
			if ((Object)(object)skin != (Object)null)
			{
				Object.Destroy((Object)(object)skin);
			}
			skin = null;
			section = (muted = (primary = (danger = (marker = null))));
		}
	}
	internal static class CompatibilityGuard
	{
		internal static MethodInfo Require(Type? type, string name, Type result, Type[] parameters, string[]? names = null)
		{
			if (type == null)
			{
				throw new InvalidOperationException("Missing required type for " + name);
			}
			MethodInfo method = type.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null);
			if (method == null || !method.IsStatic || method.ReturnType != result || (names != null && !(from p in method.GetParameters()
				select p.Name).SequenceEqual<string>(names)))
			{
				throw new InvalidOperationException("Unsupported method contract: " + type.FullName + "." + name);
			}
			return method;
		}
	}
	internal static class DryPlacement
	{
		private delegate bool FloodQuery(Vector3 point, out float level);

		private static Func<Vector3, bool>? dug;

		private static FloodQuery? flood;

		private static Func<Vector3, float>? density;

		private static ConfigEntry<bool>? enabled;

		private static readonly MethodInfo Ray = AccessTools.Method(typeof(Physics), "Raycast", new Type[5]
		{
			typeof(Vector3),
			typeof(Vector3),
			typeof(RaycastHit).MakeByRefType(),
			typeof(float),
			typeof(int)
		}, (Type[])null);

		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		internal static bool Enabled
		{
			get
			{
				if (enabled != null)
				{
					return enabled.Value;
				}
				return false;
			}
			set
			{
				if (enabled != null)
				{
					enabled.Value = value;
				}
			}
		}

		internal static void Install(BaseUnityPlugin plugin, Assembly upstream, Harmony harmony)
		{
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Expected O, but got Unknown
			Type type = upstream.GetType("ValheimTunneling.VoxelWorld");
			MethodInfo method = CompatibilityGuard.Require(type, "IsDugSpace", typeof(bool), new Type[1] { typeof(Vector3) });
			MethodInfo method2 = CompatibilityGuard.Require(type, "TryGetFloodLevel", typeof(bool), new Type[2]
			{
				typeof(Vector3),
				typeof(float).MakeByRefType()
			});
			MethodInfo method3 = CompatibilityGuard.Require(type, "SampleDensity", typeof(float), new Type[1] { typeof(Vector3) });
			density = (Func<Vector3, float>)Delegate.CreateDelegate(typeof(Func<Vector3, float>), method3);
			dug = (Func<Vector3, bool>)Delegate.CreateDelegate(typeof(Func<Vector3, bool>), method);
			flood = (FloodQuery)Delegate.CreateDelegate(typeof(FloodQuery), method2);
			enabled = plugin.Config.Bind<bool>("Building", "CorrectDryTunnelWaterRay", true, "Ignore stale water-plane hits only inside confirmed dry excavated space when aiming a piece forbidden in water. All native validation remains active.");
			MethodInfo methodInfo = AccessTools.Method(typeof(Player), "PieceRayTest", new Type[6]
			{
				typeof(Vector3).MakeByRefType(),
				typeof(Vector3).MakeByRefType(),
				typeof(Piece).MakeByRefType(),
				typeof(Heightmap).MakeByRefType(),
				typeof(Collider).MakeByRefType(),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo == null || methodInfo.ReturnType != typeof(bool))
			{
				throw new InvalidOperationException("Unsupported PieceRayTest contract");
			}
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DryPlacement), "Transpile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> input)
		{
			List<CodeInstruction> list = input.ToList();
			if (list.Count((CodeInstruction val2) => CodeInstructionExtensions.Calls(val2, Ray)) != 1)
			{
				throw new InvalidOperationException("Expected one native placement ray");
			}
			foreach (CodeInstruction i in list)
			{
				if (CodeInstructionExtensions.Calls(i, Ray))
				{
					CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					val.labels.AddRange(i.labels);
					i.labels.Clear();
					val.blocks.AddRange(i.blocks);
					i.blocks.Clear();
					yield return val;
					i.operand = AccessTools.Method(typeof(DryPlacement), "Cast", (Type[])null, (Type[])null);
				}
				yield return i;
			}
		}

		private static bool IsDry(Vector3 point)
		{
			//IL_001a: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			float level;
			if (dug != null && flood != null && density != null && dug(point) && density(point) < 0f)
			{
				return !flood(point, out level);
			}
			return false;
		}

		private static bool Cast(Vector3 origin, Vector3 direction, out RaycastHit hit, float distance, int mask, Player player)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_0126: 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_0137: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			bool flag = Physics.Raycast(origin, direction, ref hit, distance, mask);
			if (!Enabled || !flag || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)((RaycastHit)(ref hit)).collider == (Object)null)
			{
				return flag;
			}
			int num = LayerMask.NameToLayer("Water");
			GameObject val = Ghost.Invoke(player);
			Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
			if ((Object)(object)val2 == (Object)null || !val2.m_noInWater || val2.m_waterPiece || ((Component)((RaycastHit)(ref hit)).collider).gameObject.layer != num)
			{
				return flag;
			}
			try
			{
				if (!IsDry(((RaycastHit)(ref hit)).point))
				{
					return flag;
				}
				RaycastHit[] array = Physics.RaycastAll(origin, direction, distance, mask);
				Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
				RaycastHit[] array2 = array;
				for (int num2 = 0; num2 < array2.Length; num2++)
				{
					RaycastHit val3 = array2[num2];
					if (((RaycastHit)(ref val3)).distance < ((RaycastHit)(ref hit)).distance - 0.001f)
					{
						continue;
					}
					if (((Component)((RaycastHit)(ref val3)).collider).gameObject.layer == num)
					{
						if (!IsDry(((RaycastHit)(ref val3)).point))
						{
							return flag;
						}
						continue;
					}
					if (!IsDry(((RaycastHit)(ref val3)).point - ((Vector3)(ref direction)).normalized * 0.05f))
					{
						return flag;
					}
					hit = val3;
					return true;
				}
			}
			catch (Exception)
			{
			}
			return flag;
		}
	}
	internal sealed class ExcavationMode : MonoBehaviour
	{
		private static readonly ExcavationSessionState session = new ExcavationSessionState();

		private static MethodInfo worldIdentity = null;

		private static ConfigEntry<KeyboardShortcut>? toggleKey;

		private static readonly ManualLogSource Log = Logger.CreateLogSource("Tunnelheim excavation mode");

		[ThreadStatic]
		private static int voxelDamageDepth;

		private static bool tunnelingEnabled
		{
			get
			{
				return session.Enabled;
			}
			set
			{
				session.SetExplicit(value);
			}
		}

		internal static bool Enabled
		{
			get
			{
				EnsureSession();
				return tunnelingEnabled;
			}
		}

		internal static void Install(BaseUnityPlugin plugin, Assembly upstream, Harmony harmony)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Expected O, but got Unknown
			//IL_021b: Expected O, but got Unknown
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Expected O, but got Unknown
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			session.Reset();
			if (plugin.Config.Bind<bool>("Excavation", "EnabledOnStart", false, "Deprecated and ignored: every new local player/world session starts OFF. Press F4 to opt in. Config reload does not change an active session.").Value)
			{
				Log.LogWarning((object)"Legacy EnabledOnStart=true is ignored; excavation starts OFF and requires explicit F4 opt-in.");
			}
			worldIdentity = AccessTools.Method(typeof(ZNet), "GetWorldUID", (Type[])null, (Type[])null) ?? throw new Exception("Missing world identity for safe excavation sessions");
			toggleKey = plugin.Config.Bind<KeyboardShortcut>("Excavation", "ToggleKey", new KeyboardShortcut((KeyCode)285, Array.Empty<KeyCode>()), "Default F4 approved after local keybind audit; configurable. Choose an unused shortcut to toggle only this local player's excavation interception.");
			MethodInfo methodInfo = CompatibilityGuard.Require(upstream.GetType("ValheimTunneling.PickaxeDigPatch"), "Prefix", typeof(bool), new Type[5]
			{
				typeof(Vector3),
				typeof(GameObject),
				typeof(Character),
				typeof(ItemData),
				typeof(GameObject).MakeByRefType()
			}, new string[5] { "hitPoint", "prefab", "character", "weapon", "__result" });
			MethodInfo methodInfo2 = CompatibilityGuard.Require(upstream.GetType("ValheimTunneling.VoxelWorld"), "Dig", typeof(void), new Type[5]
			{
				typeof(Character),
				typeof(Vector3),
				typeof(Vector3),
				typeof(TerrainOp),
				typeof(ItemData)
			}, new string[5] { "attacker", "point", "swingDir", "op", "weapon" });
			NativeSurfaceSync.Install(plugin, upstream, harmony);
			HoeMode.Install(upstream, harmony);
			harmony.Patch((MethodBase)AccessTools.Method(upstream.GetType("ValheimTunneling.VoxelChunk"), "Damage", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ExcavationMode), "BeginVoxelDamage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ExcavationMode), "EndVoxelDamage", (Type[])null), (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ExcavationMode), "AllowExcavation", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ExcavationMode), "BypassDig", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((Component)plugin).gameObject.AddComponent<ExcavationMode>();
			Log.LogInfo((object)("Installed local excavation mode; tunnelingEnabled=" + tunnelingEnabled + "; hotkey=" + ((object)toggleKey.Value/*cast due to .constrained prefix*/).ToString()));
		}

		private static bool EnsureSession()
		{
			Player localPlayer = Player.m_localPlayer;
			string current = "";
			if ((Object)(object)localPlayer != (Object)null && worldIdentity != null && (Object)(object)ZNet.instance != (Object)null)
			{
				current = Convert.ToInt64(worldIdentity.Invoke(ZNet.instance, null)) + ":" + localPlayer.GetPlayerID() + ":" + ((Object)localPlayer).GetInstanceID();
			}
			if (!session.Observe(current))
			{
				return false;
			}
			RoutePlanner.Close();
			Log.LogInfo((object)"New local player/world session: tunneling OFF; explicit F4 opt-in required.");
			if ((Object)(object)localPlayer != (Object)null && (Object)(object)MessageHud.instance != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, "Tunneling OFF - press F4 to enable excavation", 0, (Sprite)null, false);
			}
			return true;
		}

		private static bool IsLocalOff(Character c)
		{
			EnsureSession();
			return ExcavationPolicy.IsLocalOff(tunnelingEnabled, (Object)(object)Player.m_localPlayer != (Object)null, (Object)(object)c == (Object)(object)Player.m_localPlayer);
		}

		private static bool AllowExcavation(Character attacker, Vector3 point, TerrainOp op, ItemData weapon)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!IsLocalOff(attacker))
			{
				return true;
			}
			if (voxelDamageDepth > 0)
			{
				NativeSurfaceSync.MineSurface(attacker, point, op, weapon);
			}
			return false;
		}

		private static bool BypassDig(Character character, ref bool __result)
		{
			if (!IsLocalOff(character))
			{
				return true;
			}
			__result = true;
			return false;
		}

		private static void BeginVoxelDamage(HitData hit, out bool __state)
		{
			__state = hit != null && IsLocalOff(hit.GetAttacker()) && hit.m_damage.m_pickaxe > 0f && !hit.m_ranged;
			if (__state)
			{
				voxelDamageDepth++;
			}
		}

		private static Exception? EndVoxelDamage(Exception? __exception, bool __state)
		{
			if (__state)
			{
				voxelDamageDepth--;
			}
			return __exception;
		}

		internal static void SetEnabled(bool value)
		{
			EnsureSession();
			tunnelingEnabled = value;
			Log.LogInfo((object)("Local tunneling=" + (value ? "ON" : "OFF; native mining")));
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, value ? "Tunneling ON" : "Tunneling OFF - native mining and exterior hoe", 0, (Sprite)null, false);
			}
		}

		private void Update()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (EnsureSession() || toggleKey == null)
			{
				return;
			}
			KeyboardShortcut value = toggleKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 0 && !((Object)(object)Player.m_localPlayer == (Object)null) && !Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Menu.IsVisible() && !TextInput.IsVisible())
			{
				value = toggleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					SetEnabled(!tunnelingEnabled);
				}
			}
		}
	}
	internal static class ExcavationPolicy
	{
		internal static bool IsLocalOff(bool enabled, bool localPlayerExists, bool samePlayer)
		{
			return !enabled && localPlayerExists && samePlayer;
		}
	}
	internal sealed class ExcavationSessionState
	{
		private string identity = "";

		internal bool Enabled { get; private set; }

		internal bool Observe(string current)
		{
			current = current ?? "";
			if (current == identity)
			{
				return false;
			}
			identity = current;
			Enabled = false;
			return true;
		}

		internal void SetExplicit(bool value)
		{
			Enabled = value;
		}

		internal void Reset()
		{
			identity = "";
			Enabled = false;
		}
	}
	internal static class HoeMode
	{
		private sealed class ActionInfo
		{
			internal string Name = "";

			internal int Alias;

			internal Settings Native;

			internal Settings Accepted;
		}

		private static ObjectDB? db;

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

		private static readonly Dictionary<int, ActionInfo> aliases = new Dictionary<int, ActionInfo>();

		private static readonly HashSet<Settings> accepted = new HashSet<Settings>();

		private static readonly ManualLogSource Log = Logger.CreateLogSource("Hoe mode");

		[ThreadStatic]
		private static ActionInfo? active;

		private static Vector3 lastAim;

		private static Player? aimPlayer;

		private static int aimFrame = -1;

		private static MethodInfo updateGhost = null;

		private static FieldInfo ghost = null;

		internal static bool Active => active != null;

		internal static bool Matches(TerrainOp op)
		{
			if (active != null)
			{
				return Utils.GetPrefabName(((Object)((Component)op).gameObject).name) == active.Name;
			}
			return false;
		}

		internal static bool IsAccepted(Settings s)
		{
			return accepted.Contains(s);
		}

		internal static void Install(Assembly upstream, Harmony harmony)
		{
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01b3: Expected O, but got Unknown
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Expected O, but got Unknown
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Expected O, but got Unknown
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Expected O, but got Unknown
			updateGhost = AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null) ?? throw new Exception("Missing placement refresh");
			ghost = AccessTools.Field(typeof(Player), "m_placementGhost") ?? throw new Exception("Missing placement ghost");
			MethodInfo methodInfo = AccessTools.Method(typeof(Settings), "Serialize", new Type[2]
			{
				typeof(ZPackage),
				typeof(GameObject)
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(Settings), "Deserialize", new Type[1] { typeof(ZPackage) }, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || methodInfo2.ReturnType != typeof(Settings) || !methodInfo2.IsStatic || AccessTools.Method(typeof(ZPackage), "GetPos", (Type[])null, (Type[])null) == null || AccessTools.Method(typeof(ZPackage), "SetPos", new Type[1] { typeof(int) }, (Type[])null) == null)
			{
				throw new Exception("Changed native terrain request contract");
			}
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "TryPlacePiece", new Type[1] { typeof(Piece) }, (Type[])null), new HarmonyMethod(typeof(HoeMode), "BeforePlace", (Type[])null)
			{
				priority = 800
			}, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(HoeMode), "AfterPlace", (Type[])null), (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "PieceRayTest", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(HoeMode), "AimObserved", (Type[])null)
			{
				priority = 0
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(HoeMode), "Serialize", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(HoeMode), "Deserialize", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Log.LogInfo((object)"0.5 candidate: OFF hoe uses marked native requests; ON retains upstream shaping.");
		}

		private static void Catalog()
		{
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				throw new Exception("Hoe prefabs not ready");
			}
			if ((Object)(object)db == (Object)(object)ObjectDB.instance && actions.Count > 0)
			{
				return;
			}
			db = ObjectDB.instance;
			actions.Clear();
			aliases.Clear();
			accepted.Clear();
			GameObject itemPrefab = db.GetItemPrefab("Hoe");
			PieceTable obj = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces);
			if ((Object)(object)obj == (Object)null)
			{
				throw new Exception("Native hoe table missing");
			}
			TerrainOp val = default(TerrainOp);
			TerrainOp val2 = default(TerrainOp);
			foreach (GameObject piece in obj.m_pieces)
			{
				if ((Object)(object)piece == (Object)null || (Object)(object)piece.GetComponent<TerrainOp>() == (Object)null)
				{
					continue;
				}
				string prefabName = Utils.GetPrefabName(((Object)piece).name);
				if (AcceptedSurfacePlan.NativeOnlyAction(prefabName))
				{
					string text = ((prefabName == "AddEarth") ? "raise_v2" : ((prefabName == "SmoothSurface") ? "mud_road_v2" : prefabName));
					if (!db.TryGetTerrainOp(StringExtensionMethods.GetStableHashCode(text), ref val))
					{
						throw new Exception("Unknown native hoe action " + text);
					}
					int stableHashCode = StringExtensionMethods.GetStableHashCode("local.tunnelheim.nativehoe.0.5/" + prefabName);
					if (db.TryGetTerrainOp(stableHashCode, ref val2) || aliases.ContainsKey(stableHashCode))
					{
						throw new Exception("Hoe request identifier collision");
					}
					Settings val3 = new Settings();
					FieldInfo[] fields = typeof(Settings).GetFields(BindingFlags.Instance | BindingFlags.Public);
					foreach (FieldInfo fieldInfo in fields)
					{
						fieldInfo.SetValue(val3, fieldInfo.GetValue(val.m_settings));
					}
					ActionInfo value = new ActionInfo
					{
						Name = prefabName,
						Alias = stableHashCode,
						Native = val.m_settings,
						Accepted = val3
					};
					actions.Add(prefabName, value);
					aliases.Add(stableHashCode, value);
					accepted.Add(val3);
				}
			}
		}

		private static void AimObserved(Player __instance, bool __result, Vector3 point)
		{
			//IL_0009: 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)
			if (__result)
			{
				aimPlayer = __instance;
				lastAim = point;
				aimFrame = Time.frameCount;
			}
		}

		private static bool BeforePlace(Player __instance, Piece piece, ref bool __result, out ActionInfo? __state)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			__state = active;
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || ExcavationMode.Enabled || (Object)(object)piece == (Object)null)
			{
				return true;
			}
			ItemData val = (ItemData)AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null).Invoke(__instance, null);
			if (val == null || (Object)(object)val.m_dropPrefab == (Object)null || Utils.GetPrefabName(((Object)val.m_dropPrefab).name) != "Hoe")
			{
				return true;
			}
			string prefabName = Utils.GetPrefabName(((Object)((Component)piece).gameObject).name);
			if ((Object)(object)((Component)piece).GetComponent<TerrainOp>() == (Object)null)
			{
				return true;
			}
			try
			{
				if (!AcceptedSurfacePlan.NativeOnlyAction(prefabName))
				{
					throw new Exception("This wall, ceiling or stair tool requires tunneling ON.");
				}
				Catalog();
				if (!actions.TryGetValue(prefabName, out ActionInfo value))
				{
					throw new Exception("Unsupported hoe action; use tunneling ON.");
				}
				updateGhost.Invoke(__instance, new object[1] { true });
				if ((int)__instance.GetPlacementStatus() != 0)
				{
					return true;
				}
				if ((Object)(object)aimPlayer != (Object)(object)__instance || aimFrame != Time.frameCount)
				{
					throw new Exception("No current terrain aim; retry.");
				}
				if (!NativeSurfaceSync.IsExterior(lastAim))
				{
					throw new Exception("Interior hoe shaping requires tunneling ON.");
				}
				GameObject val2 = (GameObject)ghost.GetValue(__instance);
				if ((Object)val2 == (Object)null)
				{
					throw new Exception("No placement preview; retry.");
				}
				NativeSurfaceSync.PreflightHoe(val2.transform.position, value.Accepted);
				active = value;
				return true;
			}
			catch (Exception ex)
			{
				__result = false;
				((Character)__instance).Message((MessageType)2, ex.GetBaseException().Message, 0, (Sprite)null, false);
				Log.LogWarning((object)("OFF hoe rejected before placement/resource debit: " + ex.GetBaseException().Message));
				return false;
			}
		}

		private static Exception? AfterPlace(Exception? __exception, ActionInfo? __state)
		{
			active = __state;
			return __exception;
		}

		private static bool Serialize(ZPackage pkg, GameObject prefab)
		{
			if (active == null || Utils.GetPrefabName(((Object)prefab).name) != active.Name)
			{
				return true;
			}
			pkg.Write(active.Alias);
			return false;
		}

		private static bool Deserialize(ZPackage pkg, ref Settings __result)
		{
			int pos = pkg.GetPos();
			int key = pkg.ReadInt();
			pkg.SetPos(pos);
			try
			{
				Catalog();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Hoe request catalog unavailable: " + ex.Message));
				return true;
			}
			if (!aliases.TryGetValue(key, out ActionInfo value))
			{
				return true;
			}
			pkg.ReadInt();
			__result = value.Accepted;
			return false;
		}
	}
	internal static class NativeSurfaceSync
	{
		internal sealed class CaptureState
		{
			internal Heightmap Hmap;

			internal bool Hoe;

			internal Settings Modifier;

			internal Vector3 Position;

			internal List<Cell> Cells = new List<Cell>();

			internal Dictionary<Vector2Int, object> Records = new Dictionary<Vector2Int, object>();
		}

		internal struct Cell
		{
			internal int X;

			internal int Z;

			internal float Native;

			internal float Top;

			internal Color Paint;
		}

		private static Type world = null;

		private static Type opType = null;

		private static MethodInfo sample = null;

		private static MethodInfo top = null;

		private static MethodInfo isColumn = null;

		private static MethodInfo apply = null;

		private static MethodInfo make = null;

		private static MethodInfo sync = null;

		private static MethodInfo begin = null;

		private static MethodInfo end = null;

		private static FieldInfo hmapField = null;

		private static FieldInfo initializedField = null;

		private static ObjectDB? cachedDb;

		private static readonly HashSet<Settings> stock = new HashSet<Settings>();

		private static readonly ManualLogSource Log = Logger.CreateLogSource("Native surface reconciliation");

		private static float nextMessage;

		private static MethodInfo saved = null;

		private static MethodInfo primary = null;

		private static bool failed;

		internal static void Install(BaseUnityPlugin plugin, Assembly upstream, Harmony harmony)
		{
			//IL_04ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fd: Expected O, but got Unknown
			//IL_0510: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_0532: Expected O, but got Unknown
			//IL_0532: Expected O, but got Unknown
			world = upstream.GetType("ValheimTunneling.VoxelWorld", throwOnError: true);
			opType = upstream.GetType("ValheimTunneling.VoxelOp", throwOnError: true);
			sample = Need(world, "SeedHeight", new Type[3]
			{
				typeof(Heightmap),
				typeof(float),
				typeof(float)
			});
			top = Need(world, "TryTopSurface", new Type[3]
			{
				typeof(Vector3),
				typeof(Vector3).MakeByRefType(),
				typeof(Vector3).MakeByRefType()
			});
			isColumn = Need(world, "IsVoxelColumnAt", new Type[2]
			{
				typeof(float),
				typeof(float)
			});
			apply = Need(world, "ApplySaved", new Type[2]
			{
				opType,
				typeof(Vector2Int)
			});
			make = Need(opType, "MakeTerrainSized", new Type[4]
			{
				typeof(int),
				typeof(Vector3),
				typeof(float),
				typeof(Settings)
			});
			sync = Need(world, "GetOrCreateSync", new Type[1] { typeof(Vector2Int) });
			saved = Need(world, "HasSavedTunnel", new Type[1] { typeof(Vector3) });
			primary = Need(world, "PrimarySync", new Type[1] { typeof(Vector2Int) });
			begin = Need(world, "BeginBatch", Type.EmptyTypes);
			end = Need(world, "EndBatchQueued", Type.EmptyTypes);
			hmapField = AccessTools.Field(typeof(TerrainComp), "m_hmap") ?? throw new Exception("TerrainComp heightmap field missing");
			initializedField = AccessTools.Field(typeof(TerrainComp), "m_initialized") ?? throw new Exception("TerrainComp initialization field missing");
			MethodInfo methodInfo = Need(world, "OnTerrainOp", new Type[1] { typeof(TerrainOp) });
			MethodInfo methodInfo2 = Need(typeof(TerrainComp), "DoOperation", new Type[3]
			{
				typeof(Vector3),
				typeof(Vector3),
				typeof(Settings)
			});
			MethodInfo method = Need(typeof(Heightmap), "Regenerate", Type.EmptyTypes);
			Type type = upstream.GetType("ValheimTunneling.VoxelColumnSync", throwOnError: true);
			Contract(sample, typeof(float), isStatic: true);
			Contract(top, typeof(bool), isStatic: true);
			Contract(isColumn, typeof(bool), isStatic: true);
			Contract(apply, typeof(void), isStatic: true);
			Contract(make, opType, isStatic: true);
			Contract(sync, type, isStatic: true);
			Contract(primary, type, isStatic: true);
			Contract(saved, typeof(bool), isStatic: true);
			Contract(begin, typeof(void), isStatic: true);
			Contract(end, typeof(void), isStatic: true);
			Contract(methodInfo, typeof(bool), isStatic: true);
			Contract(methodInfo2, typeof(void), isStatic: false);
			Contract(method, typeof(void), isStatic: false);
			Contract(Need(type, "SendOps", new Type[1] { typeof(List<>).MakeGenericType(opType) }), typeof(void), isStatic: false);
			string[] array = new string[4] { "IsValid", "Unreadable", "Built", "IsPending" };
			foreach (string text in array)
			{
				PropertyInfo propertyInfo = AccessTools.Property(type, text);
				if (propertyInfo == null || propertyInfo.PropertyType != typeof(bool) || propertyInfo.GetGetMethod(nonPublic: true) == null)
				{
					throw new Exception("Missing record property contract " + text);
				}
			}
			if (hmapField.FieldType != typeof(Heightmap) || initializedField.FieldType != typeof(bool))
			{
				throw new Exception("Native terrain field contract changed");
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(NativeSurfaceSync), "UseAcceptedNativeResult", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(NativeSurfaceSync), "Capture", (Type[])null), new HarmonyMethod(typeof(NativeSurfaceSync), "Reconcile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Log.LogInfo((object)"EXPERIMENT: native accepted lowering -> upstream TerrainSized records; no boundary exclusion zone.");
		}

		private static void Contract(MethodInfo method, Type result, bool isStatic)
		{
			if (method.ReturnType != result || method.IsStatic != isStatic)
			{
				throw new Exception("Changed method contract " + method.DeclaringType?.ToString() + "." + method.Name);
			}
		}

		private static MethodInfo Need(Type type, string name, Type[] args)
		{
			return AccessTools.Method(type, name, args, (Type[])null) ?? throw new Exception("Missing contract " + type?.ToString() + "." + name);
		}

		private static bool IsStock(Settings settings)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return false;
			}
			if ((Object)(object)cachedDb != (Object)(object)ObjectDB.instance)
			{
				cachedDb = ObjectDB.instance;
				stock.Clear();
				foreach (GameObject item in ObjectDB.instance.m_items)
				{
					ItemDrop component = item.GetComponent<ItemDrop>();
					if ((Object)(object)component == (Object)null || component.m_itemData.m_shared.m_damages.m_pickaxe <= 0f)
					{
						continue;
					}
					GameObject spawnOnHitTerrain = component.m_itemData.m_shared.m_spawnOnHitTerrain;
					if (!((Object)(object)spawnOnHitTerrain == (Object)null) && !((Object)spawnOnHitTerrain).name.EndsWith("_VVMC", StringComparison.Ordinal))
					{
						TerrainOp componentInChildren = spawnOnHitTerrain.GetComponentInChildren<TerrainOp>();
						if ((Object)(object)componentInChildren != (Object)null && componentInChildren.m_settings.m_raise && componentInChildren.m_settings.m_raiseDelta < 0f && !componentInChildren.m_settings.m_level && !componentInChildren.m_settings.m_smooth)
						{
							stock.Add(componentInChildren.m_settings);
						}
					}
				}
			}
			return stock.Contains(settings);
		}

		private static bool IsStockOp(TerrainOp op)
		{
			TerrainOp val = default(TerrainOp);
			if ((Object)(object)op != (Object)null && (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.TryGetTerrainOp(StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(((Object)((Component)op).gameObject).name)), ref val))
			{
				return IsStock(val.m_settings);
			}
			return false;
		}

		private static bool UseAcceptedNativeResult(TerrainOp op, ref bool __result)
		{
			if (!IsStockOp(op) && !HoeMode.Matches(op))
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool Capture(TerrainComp __instance, Vector3 pos, Settings modifier, out CaptureState? __state)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (!IsStock(modifier) && !HoeMode.IsAccepted(modifier))
			{
				return true;
			}
			try
			{
				if (failed)
				{
					throw new Exception("Previous reconciliation failed; stop this experimental test");
				}
				__state = CaptureCore(__instance, pos, modifier);
				return true;
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Native edit skipped before mutation; retry required: " + ex.Message));
				if ((Object)(object)Player.m_localPlayer != (Object)null && Time.realtimeSinceStartup >= nextMessage)
				{
					nextMessage = Time.realtimeSinceStartup + 2f;
					((Character)Player.m_localPlayer).Message((MessageType)2, failed ? "Terrain synchronization failed; stop this test and check the log." : "Tunnel terrain is still synchronizing; retry when ready.", 0, (Sprite)null, false);
				}
				return false;
			}
		}

		private unsafe static CaptureState? CaptureCore(TerrainComp __instance, Vector3 pos, Settings modifier)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0069: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			if ((!IsStock(modifier) && !HoeMode.IsAccepted(modifier)) || !(bool)initializedField.GetValue(__instance))
			{
				return null;
			}
			Heightmap val = (Heightmap)hmapField.GetValue(__instance);
			if ((Object)(object)val == (Object)null)
			{
				throw new Exception("Native heightmap unavailable");
			}
			CaptureState captureState = new CaptureState
			{
				Hmap = val,
				Hoe = HoeMode.IsAccepted(modifier),
				Modifier = modifier,
				Position = pos
			};
			float num = Mathf.Ceil(modifier.GetRadius() / val.m_scale) * val.m_scale + 2f * val.m_scale;
			int num2 = Mathf.FloorToInt((pos.x - num) / 0.5f);
			int num3 = Mathf.CeilToInt((pos.x + num) / 0.5f);
			int num4 = Mathf.FloorToInt((pos.z - num) / 0.5f);
			int num5 = Mathf.CeilToInt((pos.z + num) / 0.5f);
			HashSet<Vector2Int> hashSet = new HashSet<Vector2Int>();
			Vector3 val2 = default(Vector3);
			Vector2Int val3 = default(Vector2Int);
			Vector3 val4 = default(Vector3);
			for (int i = num4; i <= num5; i++)
			{
				for (int j = num2; j <= num3; j++)
				{
					((Vector3)(ref val2))..ctor((float)j * 0.5f, pos.y, (float)i * 0.5f);
					((Vector2Int)(ref val3))..ctor(Mathf.FloorToInt(val2.x / 16f), Mathf.FloorToInt(val2.z / 16f));
					bool flag = (bool)isColumn.Invoke(null, new object[2] { val2.x, val2.z });
					if (hashSet.Add(val3))
					{
						((Vector3)(ref val4))..ctor(((float)((Vector2Int)(ref val3)).x + 0.5f) * 16f, pos.y, ((float)((Vector2Int)(ref val3)).y + 0.5f) * 16f);
						bool flag2 = (bool)saved.Invoke(null, new object[1] { val4 });
						if (flag2 && !flag)
						{
							Vector2Int val5 = val3;
							throw new Exception("Saved tunnel column is not loaded: " + ((object)(*(Vector2Int*)(&val5))/*cast due to .constrained prefix*/).ToString());
						}
						if (flag)
						{
							object obj = primary.Invoke(null, new object[1] { val3 });
							if (obj == null && flag2)
							{
								Vector2Int val5 = val3;
								throw new Exception("Saved tunnel record is unavailable or unreadable: " + ((object)(*(Vector2Int*)(&val5))/*cast due to .constrained prefix*/).ToString());
							}
							if (obj == null)
							{
								obj = sync.Invoke(null, new object[1] { val3 });
							}
							bool recordValid = (bool)AccessTools.Property(obj.GetType(), "IsValid").GetValue(obj, null);
							bool unreadable = (bool)AccessTools.Property(obj.GetType(), "Unreadable").GetValue(obj, null);
							bool replayed = (bool)AccessTools.Property(obj.GetType(), "Built").GetValue(obj, null);
							bool pending = (bool)AccessTools.Property(obj.GetType(), "IsPending").GetValue(obj, null);
							if (!SurfaceReadinessPolicy.CanReconcile(flag2, flag, pending, recordValid, unreadable, replayed))
							{
								Vector2Int val5 = val3;
								throw new Exception("Tunnel data is not ready: " + ((object)(*(Vector2Int*)(&val5))/*cast due to .constrained prefix*/).ToString());
							}
							captureState.Records.Add(val3, obj);
						}
					}
					if (flag && val.IsPointInside(val2, 0f))
					{
						object[] array = new object[3]
						{
							val2,
							Vector3.zero,
							Vector3.zero
						};
						if (!(bool)top.Invoke(null, array))
						{
							throw new InvalidOperationException("Voxel top unavailable for native edit");
						}
						captureState.Cells.Add(new Cell
						{
							X = j,
							Z = i,
							Native = (float)sample.Invoke(null, new object[3] { val, val2.x, val2.z }),
							Top = ((Vector3)array[1]).y,
							Paint = val.GetPaintMask(val2)
						});
					}
				}
			}
			if (captureState.Cells.Count <= 0)
			{
				return null;
			}
			return captureState;
		}

		private static void Reconcile(TerrainComp __instance, CaptureState? __state)
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: 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_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Expected O, but got Unknown
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Expected O, but got Unknown
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null)
			{
				return;
			}
			Need(typeof(Heightmap), "Regenerate", Type.EmptyTypes).Invoke(__state.Hmap, null);
			Dictionary<Vector2Int, IList> dictionary = new Dictionary<Vector2Int, IList>();
			int num = 0;
			begin.Invoke(null, null);
			try
			{
				Vector2Int key = default(Vector2Int);
				foreach (Cell cell in __state.Cells)
				{
					float num2 = (float)cell.X * 0.5f;
					float num3 = (float)cell.Z * 0.5f;
					float num4 = (float)sample.Invoke(null, new object[3] { __state.Hmap, num2, num3 });
					if (float.IsNaN(num4) || float.IsInfinity(num4))
					{
						throw new Exception("Non-finite accepted native height");
					}
					List<AcceptedSurfacePlan.Step> list = AcceptedSurfacePlan.Create(cell.Native, num4, cell.Top, __state.Hoe);
					bool flag = __state.Hoe && __state.Modifier.m_paintCleared && (__state.Hmap.GetPaintMask(new Vector3(num2, num4, num3)) != cell.Paint || list.Count > 0);
					if (list.Count == 0 && !flag)
					{
						continue;
					}
					((Vector2Int)(ref key))..ctor(Mathf.FloorToInt(num2 / 16f), Mathf.FloorToInt(num3 / 16f));
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(opType));
						dictionary.Add(key, value);
					}
					foreach (AcceptedSurfacePlan.Step item in list)
					{
						float reference = item.Reference;
						float target = item.Target;
						Settings val = new Settings
						{
							m_level = false,
							m_raise = true,
							m_raiseRadius = 0.01f,
							m_raiseDelta = target - reference,
							m_raisePower = 0f,
							m_square = false,
							m_smooth = false,
							m_paintCleared = false
						};
						object value2 = make.Invoke(null, new object[4]
						{
							StringExtensionMethods.GetStableHashCode("digg"),
							(object)new Vector3(num2, reference, num3),
							0f,
							val
						});
						value.Add(value2);
						num++;
					}
					if (flag)
					{
						Settings val2 = new Settings
						{
							m_level = false,
							m_raise = false,
							m_smooth = false,
							m_paintCleared = true,
							m_paintRadius = 0.01f,
							m_square = false,
							m_paintType = __state.Modifier.m_paintType
						};
						float num5 = ((list.Count > 0) ? num4 : cell.Top);
						value.Add(make.Invoke(null, new object[4]
						{
							StringExtensionMethods.GetStableHashCode("digg"),
							(object)new Vector3(num2, num5, num3),
							0f,
							val2
						}));
						num++;
					}
				}
				foreach (KeyValuePair<Vector2Int, IList> item2 in dictionary)
				{
					foreach (object item3 in item2.Value)
					{
						apply.Invoke(null, new object[2] { item3, item2.Key });
					}
					object obj = __state.Records[item2.Key];
					Need(obj.GetType(), "SendOps", new Type[1] { typeof(List<>).MakeGenericType(opType) }).Invoke(obj, new object[1] { item2.Value });
				}
			}
			catch (Exception ex)
			{
				failed = true;
				Log.LogError((object)("EXPERIMENT FAILED after native edit; preserve checkpoint and stop testing: " + ex));
				throw;
			}
			finally
			{
				end.Invoke(null, null);
			}
			Log.LogInfo((object)("ACCEPTED native surface hmap=" + ((object)((Component)__state.Hmap).transform.position/*cast due to .constrained prefix*/).ToString() + " records=" + num + " columns=" + dictionary.Count + "; existing upstream replay/snapshot format"));
		}

		internal static bool IsExterior(Vector3 point)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (!(bool)isColumn.Invoke(null, new object[2] { point.x, point.z }))
			{
				return true;
			}
			object[] array = new object[3]
			{
				point,
				Vector3.zero,
				Vector3.zero
			};
			if (!(bool)top.Invoke(null, array))
			{
				throw new Exception("Tunnel surface unavailable; retry when ready.");
			}
			return AcceptedSurfacePlan.Exterior(point.y, ((Vector3)array[1]).y);
		}

		internal static void PreflightHoe(Vector3 point, Settings settings)
		{
			//IL_0006: 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)
			List<Heightmap> list = new List<Heightmap>();
			Heightmap.FindHeightmap(point, settings.GetRadius() + 2f, list);
			if (list.Count == 0)
			{
				throw new Exception("Terrain is not loaded; retry when ready.");
			}
			foreach (Heightmap item in list)
			{
				TerrainComp andCreateTerrainCompiler = item.GetAndCreateTerrainCompiler();
				if (!(bool)initializedField.GetValue(andCreateTerrainCompiler))
				{
					throw new Exception("Terrain is still initializing; retry when ready.");
				}
				CaptureCore(andCreateTerrainCompiler, point, settings);
			}
		}

		internal static void MineSurface(Character attacker, Vector3 point, TerrainOp op, ItemData weapon)
		{
			//IL_0014: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if (weapon == null || !IsStockOp(op))
			{
				return;
			}
			object[] array = new object[3]
			{
				point,
				Vector3.zero,
				Vector3.zero
			};
			if (!(bool)top.Invoke(null, array))
			{
				throw new Exception("Cannot identify voxel surface");
			}
			Vector3 val = (Vector3)array[1];
			if (point.y < val.y - 0.75f)
			{
				if (Time.realtimeSinceStartup >= nextMessage)
				{
					nextMessage = Time.realtimeSinceStartup + 2f;
					attacker.Message((MessageType)2, "Interior rock requires tunneling ON; ore mining remains enabled.", 0, (Sprite)null, false);
				}
			}
			else
			{
				Attack.SpawnOnHitTerrain(point, weapon.m_shared.m_spawnOnHitTerrain, attacker, 0f, weapon, (ItemData)null, false);
			}
		}
	}
	internal sealed class PlannerCaptureState
	{
		private bool armed;

		private int releaseFrames;

		internal bool Capturing { get; private set; }

		internal bool Draining { get; private set; }

		internal bool Blocking
		{
			get
			{
				if (!Capturing)
				{
					return Draining;
				}
				return true;
			}
		}

		internal void Tick(bool visible, bool focused, bool otherUi, bool modal, bool held, bool mouseHeld)
		{
			bool capturing = Capturing;
			if (!visible || !focused || otherUi)
			{
				Capturing = false;
				armed = false;
			}
			else
			{
				if (!held)
				{
					armed = true;
				}
				Capturing = modal || (held && armed);
			}
			if (capturing && !Capturing)
			{
				Draining = true;
				releaseFrames = 2;
			}
			if (Draining && !Capturing && !mouseHeld)
			{
				if (releaseFrames > 0)
				{
					releaseFrames--;
				}
				else
				{
					Draining = false;
				}
			}
		}

		internal void Suspend()
		{
			if (Capturing)
			{
				Draining = true;
				releaseFrames = 2;
			}
			Capturing = false;
			armed = false;
		}
	}
	[BepInPlugin("local.tunnelheim.buildingfix", "Tunnelheim Companion Experimental", "0.8.3")]
	[BepInDependency("sam.valheim.tunneling", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "local.tunnelheim.buildingfix";

		private Harmony? harmony;

		private void Awake()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.TryGetValue("sam.valheim.tunneling", out var value) || value.Metadata.Version != new Version(1, 0, 0))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Unverified Tunnelheim version; no patches applied.");
				return;
			}
			harmony = new Harmony("local.tunnelheim.buildingfix");
			try
			{
				DryPlacement.Install((BaseUnityPlugin)(object)this, ((object)value.Instance).GetType().Assembly, harmony);
				ExcavationMode.Install((BaseUnityPlugin)(object)this, ((object)value.Instance).GetType().Assembly, harmony);
				CanalMode.Install((BaseUnityPlugin)(object)this, value.Instance, harmony);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Local excavation toggle and dry tunnel water-ray correction installed; native placement validation retained.");
			}
			catch (Exception ex)
			{
				harmony.UnpatchSelf();
				ExcavationMode[] components = ((Component)this).GetComponents<ExcavationMode>();
				for (int i = 0; i < components.Length; i++)
				{
					Object.Destroy((Object)(object)components[i]);
				}
				CanalMode[] components2 = ((Component)this).GetComponents<CanalMode>();
				for (int i = 0; i < components2.Length; i++)
				{
					Object.Destroy((Object)(object)components2[i]);
				}
				RoutePlanner[] components3 = ((Component)this).GetComponents<RoutePlanner>();
				for (int i = 0; i < components3.Length; i++)
				{
					Object.Destroy((Object)(object)components3[i]);
				}
				((BaseUnityPlugin)this).Logger.LogError((object)("Companion disabled after incompatible hooks; upstream Tunnelheim remains active. F4/Canal controls disabled: " + ex));
			}
		}

		private void OnDestroy()
		{
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	public static class RouteCodec
	{
		private const int Magic = 1195591764;

		public static byte[] Encode(RouteSurface s, string identity)
		{
			s.Validate();
			if (identity == null || identity.Length < 1 || identity.Length > 96)
			{
				throw new ArgumentException("Invalid guide identity");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true))
			{
				binaryWriter.Write(1195591764);
				binaryWriter.Write(1);
				binaryWriter.Write(identity);
				binaryWriter.Write(s.Revision);
				binaryWriter.Write(s.NX);
				binaryWriter.Write(s.NZ);
				binaryWriter.Write(s.X0);
				binaryWriter.Write(s.Z0);
				binaryWriter.Write(s.Step);
				binaryWriter.Write(s.Sea);
				binaryWriter.Write(s.Settings.BottomWidth);
				binaryWriter.Write(s.Settings.Depth);
				binaryWriter.Write(s.Settings.BankRun);
				binaryWriter.Write(s.Controls.Length);
				RoutePoint[] controls = s.Controls;
				for (int i = 0; i < controls.Length; i++)
				{
					RoutePoint routePoint = controls[i];
					binaryWriter.Write(routePoint.X);
					binaryWriter.Write(routePoint.Z);
				}
				for (int j = 0; j < s.Heights.Length; j++)
				{