Decompiled source of OCDheim v0.3.4

plugins/OCDheim.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using OCDheim.Utilities;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("OCDheim")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OCDheim")]
[assembly: AssemblyCopyright("Copyright \ufffd  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.2.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.2.3")]
[module: UnverifiableCode]
namespace OCDheim
{
	public static class Config
	{
		private const string Keybinds = "Keybinds";

		private const string Functionalities = "Functionalities";

		private const string TerrainModification = "Terrain Modification";

		private const string Logging = "Logging";

		private const string DecidedByServer = "The Server decides for Everyone if The Server is running OCDheim.";

		private const string UnbindToDisable = "Unbind (set to None) to DISABLE {0}. To re-ENABLE {0} a restart of Valheim is required.";

		private const string AdditionalSnapPointsDesc = "Snap Build Pieces to Additional Snap Points derived by OCDheim.";

		private static readonly string AdditionalBuildPiecesDesc = "Show the Smooth Stone Build Pieces in the Build Menu. The Server decides for Everyone if The Server is running OCDheim.";

		private const string RemoveTerrainModificationsDesc = "Show Remove Terrain Modifications in The Hoe.";

		private static readonly string PileUpperDesc = "Stacks, Piles and Barrels now stack, pile, and... erm... barrel(:P) vertically on top of each other. The Server decides for Everyone if The Server is running OCDheim.";

		private const string HoverInfoDesc = "Show World Coords on Terrain Modification Tools in Grid Mode. Likely should be DISABLED in no-map runs.";

		private static readonly string RaiseTerrainLimitDesc = "How far terrain may be raised above its original level. Vanilla Valheim: 8m. The Server decides for Everyone if The Server is running OCDheim.";

		private static readonly string LowerTerrainLimitDesc = "How far terrain may be lowered below its original level. Vanilla Valheim: 8m. The Server decides for Everyone if The Server is running OCDheim.";

		private static readonly AcceptableValueRange<float> RaiseTerrainBounds = new AcceptableValueRange<float>(0f, 256f);

		private static readonly AcceptableValueRange<float> LowerTerrainBounds = new AcceptableValueRange<float>(0f, 256f);

		private const string LoggingLevelDesc = "No need to modify this *unless* you *know* you need to modify this ;)";

		private const string SnapModeJoyDesc = "HOLD to temporarily DISABLE Snap Mode.";

		private static readonly string GridModeDesc = "PRESS to toggle Grid Mode. " + string.Format("Unbind (set to None) to DISABLE {0}. To re-ENABLE {0} a restart of Valheim is required.", "Grid Mode");

		private static readonly string PrecisionModeDesc = "PRESS to toggle Precision Mode. " + string.Format("Unbind (set to None) to DISABLE {0}. To re-ENABLE {0} a restart of Valheim is required.", "Precision Mode");

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

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

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

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

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

		public static ConfigEntry<float> raiseTerrainLimit { get; private set; }

		public static ConfigEntry<float> lowerTerrainLimit { get; private set; }

		public static ConfigEntry<KeyCode> gridModeKey { get; private set; }

		public static ConfigEntry<KeyCode> precisionModeKey { get; private set; }

		public static ConfigEntry<GamepadButton> snapModeJoy { get; private set; }

		public static ConfigEntry<GamepadButton> gridModeJoy { get; private set; }

		public static ConfigEntry<GamepadButton> precisionModeJoy { get; private set; }

		public static ConfigEntry<LoggingLevel> loggingLevel { get; private set; }

		public static void Bind(ConfigFile config)
		{
			additionalSnapPoints = config.Bind<bool>("Functionalities", "Additional Snap Points", true, Describe("Snap Build Pieces to Additional Snap Points derived by OCDheim.", 4, adminOnly: false));
			additionalBuildPieces = config.Bind<bool>("Functionalities", "Additional Build Pieces", false, Describe(AdditionalBuildPiecesDesc, 3, adminOnly: true));
			removeTerrainModifications = config.Bind<bool>("Functionalities", "Remove Terrain Modifications", true, Describe("Show Remove Terrain Modifications in The Hoe.", 2, adminOnly: false));
			pileUpper = config.Bind<bool>("Functionalities", "Vertical Stacking", true, Describe(PileUpperDesc, 1, adminOnly: true));
			hoverInfo = config.Bind<bool>("Functionalities", "Hover Info", true, Describe("Show World Coords on Terrain Modification Tools in Grid Mode. Likely should be DISABLED in no-map runs.", 0, adminOnly: false));
			raiseTerrainLimit = config.Bind<float>("Terrain Modification", "Raise Terrain Limit", 8f, Describe(RaiseTerrainLimitDesc, 2, adminOnly: true, (AcceptableValueBase)(object)RaiseTerrainBounds));
			lowerTerrainLimit = config.Bind<float>("Terrain Modification", "Lower Terrain Limit", 8f, Describe(LowerTerrainLimitDesc, 1, adminOnly: true, (AcceptableValueBase)(object)LowerTerrainBounds));
			snapModeJoy = config.Bind<GamepadButton>("Keybinds", "Snap Mode Gamepad Button", (GamepadButton)10, Describe("HOLD to temporarily DISABLE Snap Mode.", 5, adminOnly: false));
			gridModeKey = config.Bind<KeyCode>("Keybinds", "Grid Mode Key", (KeyCode)308, Describe(GridModeDesc, 4, adminOnly: false));
			gridModeJoy = config.Bind<GamepadButton>("Keybinds", "Grid Mode Gamepad Button", (GamepadButton)16, Describe(GridModeDesc, 3, adminOnly: false));
			precisionModeKey = config.Bind<KeyCode>("Keybinds", "Precision Mode Key", (KeyCode)122, Describe(PrecisionModeDesc, 2, adminOnly: false));
			precisionModeJoy = config.Bind<GamepadButton>("Keybinds", "Precision Mode Gamepad Button", (GamepadButton)7, Describe(PrecisionModeDesc, 1, adminOnly: false));
			loggingLevel = config.Bind<LoggingLevel>("Logging", "Logging Level", LoggingLevel.WARNING, Describe("No need to modify this *unless* you *know* you need to modify this ;)", 1, adminOnly: false));
		}

		private static ConfigDescription Describe(string description, int order, bool adminOnly, AcceptableValueBase acceptableValues = null)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				Order = order,
				IsAdminOnly = adminOnly
			};
			return new ConfigDescription(description, acceptableValues, new object[1] { val });
		}
	}
	public class GroundLevelSpinner
	{
		public static readonly GroundLevelSpinner RaiseGroundSpinner = new GroundLevelSpinner(1f, 0f, 1f);

		public static readonly GroundLevelSpinner LowerGroundSpinner = new GroundLevelSpinner(-0.5f, -1f, 0f);

		public float value { get; private set; }

		private float maxValue { get; }

		private float minValue { get; }

		private GroundLevelSpinner(float value, float minValue, float maxValue)
		{
			this.value = value;
			this.minValue = minValue;
			this.maxValue = maxValue;
		}

		public void Refresh()
		{
			float num = KeyBinder.ScrollΔ();
			if (num > 0f)
			{
				Up(num);
			}
			if (num < 0f)
			{
				Down(num);
			}
		}

		private void Up(float scrollΔ)
		{
			if (value + scrollΔ > maxValue)
			{
				value = maxValue;
			}
			else
			{
				value = Mathf.Round((value + scrollΔ) * 100f) / 100f;
			}
		}

		private void Down(float scrollΔ)
		{
			if (value + scrollΔ < minValue)
			{
				value = minValue;
			}
			else
			{
				value = Mathf.Round((value + scrollΔ) * 100f) / 100f;
			}
		}
	}
	[HarmonyPatch]
	public static class BlockCameraZoom
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(ZInput))]
		[HarmonyPatch("GetMouseScrollWheel")]
		public static bool Prefix(ref float __result)
		{
			if (PlayerHelpers.player.HasRaiseGroundTerraformToolEquipped() && KeyBinder.gridModeEnabled)
			{
				__result = 0f;
				return false;
			}
			return true;
		}
	}
	public class KeyBinder : MonoBehaviour
	{
		private const string MouseScrollWheel = "Mouse ScrollWheel";

		public const string SuppressSnapModeKey = "AltPlace";

		public const string JoyScrollUnlock = "JoyLTrigger";

		public const string JoyScrollDown = "JoyDPadDown";

		public const string JoyScrollUp = "JoyDPadUp";

		private const float ScrollPrecision = 0.01f;

		private static bool _gridModeEnabled;

		private static bool _gridModeFreshlyEnabled;

		private static bool _gridModeFreshlyDisabled;

		private static ButtonConfig snapModeJoy { get; set; }

		public static ButtonConfig gridModeKey { get; private set; }

		public static ButtonConfig gridModeJoy { get; private set; }

		public static ButtonConfig precisionModeKey { get; private set; }

		public static ButtonConfig precisionModeJoy { get; private set; }

		public static bool snapModeDisabled
		{
			get
			{
				if (!ZInput.GetButton("AltPlace"))
				{
					return ZInput.GetButton(snapModeJoy.Name);
				}
				return true;
			}
		}

		public static bool snapModeEnabled => !snapModeDisabled;

		public static bool gridModeEnabled
		{
			get
			{
				return _gridModeEnabled;
			}
			private set
			{
				_gridModeEnabled = value;
				_gridModeFreshlyEnabled = value;
				_gridModeFreshlyDisabled = !value;
			}
		}

		public static bool gridModeDisabled => !gridModeEnabled;

		public static bool gridModFreshlyEnabled
		{
			get
			{
				bool gridModeFreshlyEnabled = _gridModeFreshlyEnabled;
				_gridModeFreshlyEnabled = false;
				return gridModeFreshlyEnabled;
			}
		}

		public static bool gridModFreshlyDisabled
		{
			get
			{
				bool gridModeFreshlyDisabled = _gridModeFreshlyDisabled;
				_gridModeFreshlyDisabled = false;
				return gridModeFreshlyDisabled;
			}
		}

		public static PrecisionMode precisionMode { get; private set; } = PrecisionMode.ORDINARY;

		private void Awake()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			snapModeJoy = AddButton(new ButtonConfig
			{
				Name = "snapModeJoy",
				GamepadConfig = Config.snapModeJoy
			});
			gridModeKey = AddButton(new ButtonConfig
			{
				Name = "gridModeKey",
				Config = Config.gridModeKey
			});
			gridModeJoy = AddButton(new ButtonConfig
			{
				Name = "gridModeJoy",
				GamepadConfig = Config.gridModeJoy
			});
			precisionModeKey = AddButton(new ButtonConfig
			{
				Name = "precisionModeKey",
				Config = Config.precisionModeKey
			});
			precisionModeJoy = AddButton(new ButtonConfig
			{
				Name = "precisionModeJoy",
				GamepadConfig = Config.precisionModeJoy
			});
		}

		private static ButtonConfig AddButton(ButtonConfig button)
		{
			InputManager.Instance.AddButton("dymek.dev.OCDheim", button);
			return button;
		}

		private void Update()
		{
			bool flag = ((ZInput.GetButtonDown(gridModeKey.Name) || (snapModeEnabled && ZInput.GetButtonDown(gridModeJoy.Name))) && (gridModeEnabled || PlayerHelpers.player.HasGridModeToolEquipped())) || (gridModeEnabled && !PlayerHelpers.player.HasGridModeToolEquipped());
			bool num = ((ZInput.GetButtonDown(precisionModeKey.Name) || (snapModeEnabled && ZInput.GetButtonDown(precisionModeJoy.Name))) && (precisionMode == PrecisionMode.SUPERIOR || PlayerHelpers.player.HasBuildPieceEquipped())) || (precisionMode == PrecisionMode.SUPERIOR && !PlayerHelpers.player.HasBuildPieceEquipped());
			if (flag)
			{
				gridModeEnabled = !gridModeEnabled;
				Logger.Info(() => "[" + (gridModeEnabled ? "ENABLED" : "DISABLED") + "] GRID MODE");
			}
			if (num)
			{
				precisionMode = ((precisionMode != PrecisionMode.ORDINARY) ? PrecisionMode.ORDINARY : PrecisionMode.SUPERIOR);
				Logger.Info(() => "[" + ((precisionMode == PrecisionMode.SUPERIOR) ? "ENABLED" : "DISABLED") + "] PRECISION MODE");
			}
		}

		public static float ScrollΔ()
		{
			float axis = Input.GetAxis("Mouse ScrollWheel");
			if (axis != 0f)
			{
				if (!(axis > 0f))
				{
					return -0.01f;
				}
				return 0.01f;
			}
			if (ZInput.GetButton("JoyLTrigger") && ZInput.GetButtonDown("JoyDPadDown"))
			{
				return -0.01f;
			}
			if (ZInput.GetButton("JoyLTrigger") && ZInput.GetButtonDown("JoyDPadUp"))
			{
				return 0.01f;
			}
			return axis;
		}
	}
	public class KeyHint
	{
		private const string KeyPath = "key_bkg/Key";

		private const string LabelPath = "Text";

		private string label { get; }

		private Func<string> keyResolver { get; }

		private Func<string> joyResolver { get; }

		private GameObject keyHint { get; }

		private GameObject joyHint { get; }

		private TMP_Text keyHintText { get; }

		private TMP_Text joyHintText { get; }

		private bool isVisible { get; set; }

		private bool isJoyActive { get; set; }

		public KeyHint(string label, Transform keyTemplate, Transform joyTemplate, Func<string> keyResolver, Func<string> joyResolver)
		{
			this.label = label;
			this.keyResolver = keyResolver;
			this.joyResolver = joyResolver;
			keyHint = Clone(keyTemplate, label);
			joyHint = Clone(joyTemplate, label);
			((Component)keyHint.transform.Find("Text")).GetComponent<TMP_Text>().text = label;
			Transform obj = keyHint.transform.Find("key_bkg/Key");
			keyHintText = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
			joyHintText = joyHint.GetComponent<TMP_Text>();
		}

		public KeyHint Before(Transform keyNeighbour, Transform joyNeighbour)
		{
			return MoveNextTo(keyNeighbour, joyNeighbour, 0);
		}

		public KeyHint After(Transform keyNeighbour, Transform joyNeighbour)
		{
			return MoveNextTo(keyNeighbour, joyNeighbour, 1);
		}

		public void Refresh(bool shouldBeVisible)
		{
			bool flag = ZInput.IsGamepadActive();
			if (shouldBeVisible == isVisible && flag == isJoyActive)
			{
				return;
			}
			isJoyActive = flag;
			isVisible = shouldBeVisible;
			if (!shouldBeVisible)
			{
				keyHint.SetActive(false);
				joyHint.SetActive(false);
				return;
			}
			string text = keyResolver?.Invoke();
			string text2 = joyResolver();
			if (Object.op_Implicit((Object)(object)keyHintText))
			{
				keyHintText.text = text ?? "";
			}
			joyHintText.text = label + " <mspace=0.6em> " + text2 + "</mspace>";
			keyHint.SetActive(text != "");
			joyHint.SetActive(text2 != "");
		}

		private KeyHint MoveNextTo(Transform keyNeighbour, Transform joyNeighbour, int offset)
		{
			keyHint.transform.SetSiblingIndex(keyNeighbour.GetSiblingIndex() + offset);
			joyHint.transform.SetSiblingIndex(joyNeighbour.GetSiblingIndex() + offset);
			return this;
		}

		private static GameObject Clone(Transform template, string label)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, template.parent);
			((Object)val).name = "OCDheim " + label;
			val.SetActive(false);
			TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = "";
			}
			return val;
		}
	}
	[HarmonyPatch]
	public class KeyHinter : MonoBehaviour
	{
		private const string CycleKeyPath = "Keyboard/Snap";

		private const string CycleJoyPath = "Gamepad/Text - Snap";

		private const string PlaceKeyPath = "Keyboard/Place";

		private const string BlockKeyPath = "Keyboard/Block";

		private const string RotateKeyPath = "Keyboard/rotate";

		private const string PlaceJoyPath = "Gamepad/Text - Place";

		private const string BlockJoyPath = "Gamepad/Text - Block";

		private const string RotateJoyPath = "Gamepad/Text - Rotate";

		private const string BuildMenuJoyPath = "Gamepad/Text - BuildMenu";

		private KeyHints hints { get; set; }

		private KeyHint gridModeHint { get; set; }

		private KeyHint precisionModeHint { get; set; }

		private KeyHint fineTuneEffectHint { get; set; }

		private KeyHint pickaxeGridModeHint { get; set; }

		private Transform cycleKeyHint { get; set; }

		private Transform cycleJoyHint { get; set; }

		private Transform rotateKeyHint { get; set; }

		private Transform rotateJoyHint { get; set; }

		private bool showHelperHints { get; set; } = true;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(KeyHints))]
		[HarmonyPatch("Awake")]
		private static void Initialize(KeyHints __instance)
		{
			((Component)__instance).gameObject.AddComponent<KeyHinter>();
		}

		private void Awake()
		{
			hints = ((Component)this).GetComponent<KeyHints>();
			Transform transform = hints.m_buildHints.transform;
			Transform transform2 = hints.m_combatHints.transform;
			cycleKeyHint = transform.Find("Keyboard/Snap");
			cycleJoyHint = transform.Find("Gamepad/Text - Snap");
			rotateKeyHint = transform.Find("Keyboard/rotate");
			rotateJoyHint = transform.Find("Gamepad/Text - Rotate");
			Transform keyTemplate = transform.Find("Keyboard/Place");
			Transform joyTemplate = transform.Find("Gamepad/Text - Place");
			Transform keyTemplate2 = transform2.Find("Keyboard/Block");
			Transform joyTemplate2 = transform2.Find("Gamepad/Text - Block");
			Transform joyNeighbour = transform.Find("Gamepad/Text - BuildMenu");
			gridModeHint = new KeyHint("Grid Mode", keyTemplate, joyTemplate, () => Key(KeyBinder.gridModeKey), () => Joy(KeyBinder.gridModeJoy)).Before(rotateKeyHint, joyNeighbour);
			precisionModeHint = new KeyHint("Precision Mode", keyTemplate, joyTemplate, () => Key(KeyBinder.precisionModeKey), () => Joy(KeyBinder.precisionModeJoy)).Before(rotateKeyHint, joyNeighbour);
			fineTuneEffectHint = new KeyHint("Fine-Tune Effect", rotateKeyHint, rotateJoyHint, null, () => Combo("JoyLTrigger", "JoyDPadUp", "JoyDPadDown")).After(rotateKeyHint, rotateJoyHint);
			pickaxeGridModeHint = new KeyHint("Grid Mode", keyTemplate2, joyTemplate2, () => Key(KeyBinder.gridModeKey), () => Joy(KeyBinder.gridModeJoy));
		}

		private void Update()
		{
			if (hints.m_combatHints.activeSelf)
			{
				pickaxeGridModeHint.Refresh(PlayerHelpers.player.HasPickaxeEquipped());
			}
			if (hints.m_buildHints.activeSelf)
			{
				gridModeHint.Refresh(PlayerHelpers.player.HasGridModeToolEquipped());
				precisionModeHint.Refresh(PlayerHelpers.player.HasBuildPieceEquipped());
				fineTuneEffectHint.Refresh(PlayerHelpers.player.HasRaiseGroundTerraformToolEquipped() && KeyBinder.gridModeEnabled);
			}
			if (showHelperHints == PlayerHelpers.player.HasOverlayVisible())
			{
				showHelperHints = !showHelperHints;
				((Component)cycleKeyHint).gameObject.SetActive(showHelperHints);
				((Component)cycleJoyHint).gameObject.SetActive(showHelperHints);
				((Component)rotateKeyHint).gameObject.SetActive(showHelperHints);
				((Component)rotateJoyHint).gameObject.SetActive(showHelperHints);
			}
		}

		private static string Key(ButtonConfig button)
		{
			return Localization.instance.GetBoundKeyString(button.Name, true);
		}

		private static string Joy(ButtonConfig button)
		{
			return ZInput.instance.GetBoundKeyString("Joy!" + button.Name, true);
		}

		private static string Joy(string buttonName)
		{
			return ZInput.instance.GetBoundKeyString(buttonName, true);
		}

		private static string Combo(string modifier, string b1, string b2)
		{
			return Joy(modifier) + " + " + Joy(b1) + " / " + Joy(b2);
		}
	}
	[BepInPlugin("dymek.dev.OCDheim", "OCDheim", "0.3.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class OCDheim : BaseUnityPlugin
	{
		public const string GUID = "dymek.dev.OCDheim";

		private const string Name = "OCDheim";

		private const string Version = "0.3.4";

		private const string RemoveTerrainModificationsPieceName = "Remove Terrain Modifications";

		private const string RemoveTerrainModificationsPrefabName = "remove_terrain_modifications";

		public static AssetBundle resourceBundle { get; } = LoadResourceBundle();

		private Texture2D brick1x1 { get; } = LoadTextureFromDisk("brick_1x1.png");

		private Texture2D brick2x1 { get; } = LoadTextureFromDisk("brick_2x1.png");

		private Texture2D brick2x2 { get; } = LoadTextureFromDisk("brick_2x2.png");

		private Texture2D brick1x2 { get; } = LoadTextureFromDisk("brick_1x2.png");

		private Texture2D brick4x2 { get; } = LoadTextureFromDisk("brick_4x2.png");

		private List<Piece> bricks { get; } = new List<Piece>();

		private Harmony harmony { get; } = new Harmony("dymek.dev.OCDheim");

		private static AssetBundle LoadResourceBundle()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected I4, but got Unknown
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			RuntimePlatform platform = Application.platform;
			if ((int)platform <= 7)
			{
				if ((int)platform <= 1)
				{
					goto IL_006b;
				}
				if ((int)platform != 2 && (int)platform != 7)
				{
					goto IL_0084;
				}
			}
			else
			{
				if ((int)platform == 13 || (int)platform == 16)
				{
					goto IL_0052;
				}
				switch (platform - 43)
				{
				case 1:
					break;
				case 0:
					goto IL_0052;
				case 2:
					goto IL_006b;
				default:
					goto IL_0084;
				}
			}
			return AssetUtils.LoadAssetBundleFromResources(Path.Combine("bundle_windows"));
			IL_006b:
			return AssetUtils.LoadAssetBundleFromResources(Path.Combine("bundle_osx"));
			IL_0052:
			return AssetUtils.LoadAssetBundleFromResources(Path.Combine("bundle_linux"));
			IL_0084:
			throw new PlatformNotSupportedException(((object)Application.platform/*cast due to .constrained prefix*/).ToString());
		}

		public static Texture2D LoadTextureFromDisk(string fileName)
		{
			return AssetUtils.LoadTexture(Path.Combine(Path.GetDirectoryName(typeof(OCDheim).Assembly.Location) ?? throw new InvalidOperationException(), fileName), true);
		}

		private void Awake()
		{
			Config.Bind(((BaseUnityPlugin)this).Config);
			Config.additionalBuildPieces.SettingChanged += delegate
			{
				FlipBrickBuildPieceAvailability();
			};
			Config.removeTerrainModifications.SettingChanged += delegate
			{
				FlipRemoveTerrainModificationsAvailability();
			};
			harmony.PatchAll();
			((Component)this).gameObject.AddComponent<KeyBinder>();
			PrefabManager.OnVanillaPrefabsAvailable += AddOCDheimToolPieces;
			PrefabManager.OnVanillaPrefabsAvailable += AddOCDheimBuildPieces;
			PrefabManager.OnVanillaPrefabsAvailable += ModVanillaValheimTools;
		}

		private void AddOCDheimToolPieces()
		{
			AddToolPiece<RemoveModificationsOverlayVisualizer>("remove_terrain_modifications", "Remove Terrain Modifications", "mud_road_v2", "Hoe", OverlayVisualizer.remove);
			FlipRemoveTerrainModificationsAvailability();
		}

		private void FlipRemoveTerrainModificationsAvailability()
		{
			PieceManager.Instance.GetPiece("remove_terrain_modifications").Piece.m_enabled = Config.removeTerrainModifications.Value;
			if (Object.op_Implicit((Object)(object)PlayerHelpers.player))
			{
				PlayerHelpers.player.UpdateKnownRecipesList();
				PlayerHelpers.player.UpdateAvailablePiecesList();
			}
		}

		private void AddToolPiece<TOverlayVisualizer>(string prefabName, string pieceName, string basePieceName, string pieceTable, Texture2D iconTexture, bool level = false, bool raise = false, bool smooth = false, bool paint = false) where TOverlayVisualizer : OverlayVisualizer
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			if (PieceManager.Instance.GetPiece(prefabName) == null)
			{
				Sprite icon = Sprite.Create(iconTexture, new Rect(0f, 0f, (float)((Texture)iconTexture).width, (float)((Texture)iconTexture).height), Vector2.zero);
				CustomPiece val = new CustomPiece(prefabName, basePieceName, new PieceConfig
				{
					Name = pieceName,
					Icon = icon,
					PieceTable = pieceTable
				});
				TerrainOp component = val.PiecePrefab.GetComponent<TerrainOp>();
				component.m_settings.m_level = level;
				component.m_settings.m_raise = raise;
				component.m_settings.m_smooth = smooth;
				component.m_settings.m_paintCleared = paint;
				val.PiecePrefab.AddComponent<TOverlayVisualizer>();
				PieceManager.Instance.AddPiece(val);
				TerrainOpsRegistry.Register(component);
			}
		}

		private void AddOCDheimBuildPieces()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			AddBrickBuildPiece("1x1", new Vector3(0.5f, 1f, 0.5f), 3, brick1x1);
			AddBrickBuildPiece("2x1", new Vector3(1f, 1f, 0.5f), 4, brick2x1);
			AddBrickBuildPiece("1x2", new Vector3(0.5f, 2f, 0.5f), 5, brick1x2);
			AddBrickBuildPiece("4x2", new Vector3(2f, 2f, 0.5f), 6, brick4x2);
			AddBrickBuildPiece("2x2 (Vertical)", new Vector3(1f, 2f, 0.5f), 5, brick2x2);
			PrefabManager.OnVanillaPrefabsAvailable -= AddOCDheimBuildPieces;
		}

		private void AddBrickBuildPiece(string brickSuffix, Vector3 brickScale, int brickPrice, Texture2D iconTexture)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			string text = "Smooth Stone " + brickSuffix;
			string text2 = brickSuffix.Replace(" ", "_").Replace("(", "").Replace(")", "")
				.ToLower();
			if (PieceManager.Instance.GetPiece(text) == null)
			{
				GameObject val = PrefabManager.Instance.CreateClonedPrefab("stone_floor_" + text2, "stone_floor_2x2");
				Sprite icon = Sprite.Create(iconTexture, new Rect(0f, 0f, (float)((Texture)iconTexture).width, (float)((Texture)iconTexture).height), Vector2.zero);
				val.GetComponent<Piece>().m_clipGround = false;
				val.transform.localScale = brickScale;
				PieceConfig val2 = new PieceConfig();
				val2.Name = text;
				val2.Icon = icon;
				val2.PieceTable = "Hammer";
				val2.Category = "HeavyBuild";
				val2.Usage = new string[2]
				{
					PieceUsages.Building,
					PieceUsages.Wall
				};
				val2.Enabled = Config.additionalBuildPieces.Value;
				val2.AddRequirement(new RequirementConfig("Stone", brickPrice, 0, true));
				PieceManager.Instance.AddPiece(new CustomPiece(val, false, val2));
				bricks.Add(val.GetComponent<Piece>());
			}
		}

		private void FlipBrickBuildPieceAvailability()
		{
			foreach (Piece brick in bricks)
			{
				brick.m_enabled = Config.additionalBuildPieces.Value;
			}
			if (Object.op_Implicit((Object)(object)PlayerHelpers.player))
			{
				PlayerHelpers.player.UpdateKnownRecipesList();
				PlayerHelpers.player.UpdateAvailablePiecesList();
			}
		}

		private void ModVanillaValheimTools()
		{
			PrefabManager.Instance.GetPrefab("mud_road_v2").AddComponent<LevelGroundOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("raise_v2").AddComponent<RaiseGroundOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("path_v2").AddComponent<PaveRoadOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("paved_road_v2").AddComponent<PaveRoadOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("cultivate_v2").AddComponent<CultivateOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("replant_v2").AddComponent<SeedGrassOverlayVisualizer>();
			PrefabManager.OnVanillaPrefabsAvailable -= ModVanillaValheimTools;
		}
	}
	[HarmonyPatch]
	public static class PileUpper
	{
		private static readonly List<string> ApplicableSuffixes = new List<string> { "pile", "stack", "barrel" };

		[HarmonyPostfix]
		[HarmonyPatch(typeof(WearNTear))]
		[HarmonyPatch("Start")]
		private static void MakePilesAsDurableAsWood(WearNTear __instance)
		{
			if (!Config.pileUpper.Value)
			{
				return;
			}
			string name = ((Object)__instance).name;
			foreach (string applicableSuffix in ApplicableSuffixes)
			{
				if (name.Contains(applicableSuffix))
				{
					__instance.m_supports = true;
				}
			}
		}
	}
	public static class PlacementValidator
	{
		private static readonly int PiecesOnly = LayerMask.GetMask(new string[1] { "piece" });

		private static readonly int LiquidOnly = LayerMask.GetMask(new string[1] { "Water" });

		public static PlacementStatus Validate(Piece buildPiece, RaycastHit surface)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Invalid comparison between Unknown and I4
			//IL_016b: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Invalid comparison between Unknown and I4
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			PlacementStatus result = (PlacementStatus)0;
			Vector3 point = ((RaycastHit)(ref surface)).point;
			Vector3 normal = ((RaycastHit)(ref surface)).normal;
			Piece componentInParent = ((Component)((RaycastHit)(ref surface)).collider).GetComponentInParent<Piece>();
			Heightmap component = ((Component)((RaycastHit)(ref surface)).collider).GetComponent<Heightmap>();
			WearNTear val = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).GetComponent<WearNTear>() : null);
			StationExtension component2 = ((Component)buildPiece).GetComponent<StationExtension>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				CraftingStation val2 = component2.FindClosestStationInRange(point);
				if (Object.op_Implicit((Object)(object)val2))
				{
					component2.StartConnectionEffect(val2, 1f);
				}
				else
				{
					component2.StopConnectionEffect();
					result = (PlacementStatus)7;
				}
				if (component2.OtherExtensionInRange(buildPiece.m_spaceRequirement))
				{
					result = (PlacementStatus)5;
				}
			}
			if (buildPiece.m_blockRadius > 0f && IsBlocked(buildPiece, point))
			{
				result = (PlacementStatus)5;
			}
			if (Object.op_Implicit((Object)(object)val) && !val.m_supports)
			{
				result = (PlacementStatus)1;
			}
			if (buildPiece.m_waterPiece && !IsUnderWater(point))
			{
				result = (PlacementStatus)1;
			}
			if (buildPiece.m_noInWater && IsUnderWater(point))
			{
				result = (PlacementStatus)1;
			}
			if (buildPiece.m_groundOnly && !Object.op_Implicit((Object)(object)component))
			{
				result = (PlacementStatus)1;
			}
			if (buildPiece.m_cultivatedGroundOnly && (!Object.op_Implicit((Object)(object)component) || !component.IsCultivated(point)))
			{
				result = (PlacementStatus)9;
			}
			if (buildPiece.m_notOnWood && Object.op_Implicit((Object)(object)val) && ((int)val.m_materialType == 0 || (int)val.m_materialType == 3))
			{
				result = (PlacementStatus)1;
			}
			if (buildPiece.m_notOnTiltingSurface && normal.y < 0.8f)
			{
				result = (PlacementStatus)1;
			}
			if (buildPiece.m_inCeilingOnly && normal.y > -0.5f)
			{
				result = (PlacementStatus)1;
			}
			if (buildPiece.m_notOnFloor && normal.y > 0.1f)
			{
				result = (PlacementStatus)1;
			}
			if (!buildPiece.m_allowedInDungeons && ((Character)PlayerHelpers.player).InInterior() && !EnvMan.instance.CheckInteriorBuildingOverride() && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)34))
			{
				result = (PlacementStatus)11;
			}
			if ((int)PlayerHelpers.player.m_currentBiome == 64 && Object.op_Implicit((Object)(object)component) && component.GetCultivationMask(point) > PlayerHelpers.player.m_deepSnowBuildHeight)
			{
				result = (PlacementStatus)13;
			}
			return result;
		}

		private static bool IsUnderWater(Vector3 point)
		{
			//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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			return Physics.Raycast(point + Vector3.up * 250f, Vector3.down, 250f, LiquidOnly);
		}

		private static bool IsBlocked(Piece buildPiece, Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(point, buildPiece.m_blockRadius, PiecesOnly);
			foreach (Collider val in array)
			{
				Piece neighbourPiece = ((Component)val).GetComponentInParent<Piece>();
				if (Object.op_Implicit((Object)(object)neighbourPiece) && buildPiece.m_blockingPieces.Exists((Piece blockingPiece) => blockingPiece.m_name == neighbourPiece.m_name))
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	public static class RemoveExpensiveUnnecessaryCalls
	{
		private static bool ShouldSuppressVanillaValheim()
		{
			if ((!KeyBinder.gridModeEnabled || !PrecisePieceSnapper.GridModeRequirementsSatisfied()) && (!KeyBinder.snapModeEnabled || !PrecisePieceSnapper.SnapModeRequirementsSatisfied()))
			{
				return KeyBinder.snapModeDisabled;
			}
			return true;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player))]
		[HarmonyPatch("UpdatePlacementGhost")]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			bool foundCodeToRemove = false;
			bool foundCodeToReplace = false;
			foreach (CodeInstruction instruction in instructions)
			{
				foundCodeToRemove = (foundCodeToRemove ? foundCodeToRemove : (instruction.opcode == OpCodes.Ldstr && (string)instruction.operand == "AltPlace"));
				if (foundCodeToRemove && !foundCodeToReplace)
				{
					foundCodeToReplace = (foundCodeToReplace ? foundCodeToReplace : (instruction.opcode == OpCodes.Call));
					if (!foundCodeToReplace)
					{
						instruction.opcode = OpCodes.Nop;
						instruction.operand = null;
						yield return instruction;
						continue;
					}
					instruction.opcode = OpCodes.Call;
					instruction.operand = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => ShouldSuppressVanillaValheim()));
					yield return instruction;
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
	[HarmonyPatch]
	public static class PrecisePieceSnapperBeforePlacementValidator
	{
		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player))]
		[HarmonyPatch("UpdatePlacementGhost")]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			//IL_000f: 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_002e: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[5]
			{
				new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null),
				new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(Player), "m_placementGhost"), (string)null),
				new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.PropertyGetter(typeof(GameObject), "transform"), (string)null),
				new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.PropertyGetter(typeof(Transform), "position"), (string)null),
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Location), "IsInsideNoBuildLocation", (Type[])null, (Type[])null), (string)null)
			});
			if (val.IsValid)
			{
				CodeInstruction val2 = new CodeInstruction(OpCodes.Call, (object)SymbolExtensions.GetMethodInfo((Expression<Action>)(() => SnapBuildPiece())));
				CodeInstructionExtensions.MoveLabelsTo(val.Instruction, val2);
				val.Insert((CodeInstruction[])(object)new CodeInstruction[1] { val2 });
			}
			else
			{
				Logger.Warn(() => "FAILED to find Vanilla Valheim code to transpile in: " + original.DeclaringType?.Name + "." + original.Name);
			}
			return val.InstructionEnumeration();
		}

		private static void SnapBuildPiece()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit? val = PrecisePieceSnapper.SnapBuildPiece();
			if (val.HasValue)
			{
				RaycastHit valueOrDefault = val.GetValueOrDefault();
				if (PlayerHelpers.player.HasBuildPieceEquipped())
				{
					PlayerHelpers.player.m_placementStatus = PlacementValidator.Validate(PieceHelpers.buildPiece, valueOrDefault);
				}
			}
		}
	}
	public static class PrecisePieceSnapper
	{
		private const float NeighbourhoodSize = 2.5f;

		private const float ClippingTolerance = 0.25f;

		private static readonly int PiecesOnly = LayerMask.GetMask(new string[1] { "piece" });

		private static readonly int LayerMask = PlayerHelpers.player.m_placeRayMask - LayerMask.GetMask(new string[1] { "piece_nonsolid" });

		private static readonly Collider[] NeighbourColliders = (Collider[])(object)new Collider[255];

		private static readonly List<Piece> NeighbourPieces = new List<Piece>();

		public static bool GridModeRequirementsSatisfied()
		{
			if (!PlayerHelpers.player.HasBuildPieceEquipped())
			{
				return PlayerHelpers.player.HasOverlayVisible();
			}
			return true;
		}

		public static bool SnapModeRequirementsSatisfied()
		{
			if (Config.additionalSnapPoints.Value && PlayerHelpers.player.HasBuildPieceEquipped())
			{
				if (PieceHelpers.buildPiece.Type() == PieceType.CONSTRUCTION)
				{
					return KeyBinder.precisionMode == PrecisionMode.SUPERIOR;
				}
				return true;
			}
			return false;
		}

		private static bool ShouldUsePlayerPositionAsGroundLevelReference()
		{
			if (PlayerHelpers.player.HasLevelGroundTerraformToolEquipped())
			{
				return KeyBinder.snapModeEnabled;
			}
			return false;
		}

		public static RaycastHit? SnapBuildPiece()
		{
			if (KeyBinder.gridModeEnabled && GridModeRequirementsSatisfied())
			{
				return SnapToWorldGrid(PieceHelpers.buildPiece);
			}
			if (KeyBinder.snapModeEnabled && SnapModeRequirementsSatisfied())
			{
				return SnapToNeighbourPiece(PieceHelpers.buildPiece);
			}
			return null;
		}

		private static RaycastHit? SnapToWorldGrid(Piece buildPiece)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			Vector3 playerPoV = DeterminePlayerPoV();
			int precisionMode = (int)KeyBinder.precisionMode;
			var (num, num2) = SnapToWorldGrid(playerPoV, precisionMode);
			if (PlayerHelpers.player.HasOverlayVisible())
			{
				FixVanillaValheimBugWithSpinningTerrainModificationVFX();
			}
			if (ShouldUsePlayerPositionAsGroundLevelReference())
			{
				((Component)buildPiece).transform.position = new Vector3(num, PlayerHelpers.playerPos.y, num2);
				return null;
			}
			Vector2 drillCoords = default(Vector2);
			((Vector2)(ref drillCoords))..ctor(num, num2);
			PrecisionDrill.Floor floor = ((PlayerHelpers.player.HasOverlayVisible() || buildPiece.IsGroundBound()) ? PrecisionDrill.DrillDownTillGround(drillCoords) : PrecisionDrill.DrillDownTillFloor(drillCoords, DetermineReferenceLevel(buildPiece), DetermineRequiredRoom(buildPiece)));
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(num, floor.level, num2);
			if (!buildPiece.ClipsIntoBuildPieces() && (!buildPiece.ClipsIntoGround() || !floor.isGround))
			{
				SnapExternally(buildPiece, val, Vector3.up);
			}
			else
			{
				((Component)buildPiece).transform.position = val;
			}
			return floor.drillStrike;
		}

		private static float DetermineReferenceLevel(Piece buildPiece)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!buildPiece.ClipsIntoBuildPieces())
			{
				return buildPiece.BottomLevel();
			}
			return ((Component)buildPiece).transform.position.y;
		}

		private static float DetermineRequiredRoom(Piece buildPiece)
		{
			if (!buildPiece.ClipsIntoBuildPieces())
			{
				return Mathf.Max(0f, buildPiece.TopLevel() - buildPiece.BottomLevel() - 0.25f);
			}
			return 0f;
		}

		private static (float xOnGrid, float zOnGrid) SnapToWorldGrid(Vector3 playerPoV, int precision)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			float item;
			float item2;
			if (PlayerHelpers.player.HasColorBrushEquipped())
			{
				float num = Mathf.Floor(playerPoV.x / 64f) * 64f;
				float num2 = Mathf.Floor(playerPoV.z / 64f) * 64f;
				float num3 = num - 32f;
				float num4 = num2 - 32f;
				float num5 = playerPoV.x - num3;
				float num6 = playerPoV.z - num4;
				item = num3 + Mathf.Floor(num5 / (64f / 65f)) * (64f / 65f) + 32f / 65f;
				item2 = num4 + Mathf.Floor(num6 / (64f / 65f)) * (64f / 65f) + 32f / 65f;
			}
			else
			{
				item = Mathf.Round(playerPoV.x * (float)precision) / (float)precision;
				item2 = Mathf.Round(playerPoV.z * (float)precision) / (float)precision;
			}
			return (xOnGrid: item, zOnGrid: item2);
		}

		private static RaycastHit? SnapToNeighbourPiece(Piece buildPiece)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Vector3 playerPoV = DeterminePlayerPoV();
			List<Piece> neighbourPieces = FindNeighbourPieces(playerPoV);
			switch (buildPiece.Type())
			{
			case PieceType.CONSTRUCTION:
				return SnapInternally(buildPiece, neighbourPieces);
			case PieceType.FURNITURE:
			case PieceType.TABLE:
				return SnapExternally(buildPiece, neighbourPieces, playerPoV);
			default:
				return null;
			}
		}

		private static RaycastHit? SnapInternally(Piece buildPiece, List<Piece> neighbourPieces)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			SnapTree.TraversalResult? traversalResult = ((KeyBinder.precisionMode == PrecisionMode.ORDINARY) ? SnapTree.FindNearestOrdinaryPrecisionSnapNodeCombinationOf(buildPiece, neighbourPieces) : SnapTree.FindNearestSuperiorPrecisionSnapNodeCombinationOf(buildPiece, neighbourPieces));
			if (traversalResult.HasValue)
			{
				SnapTree.TraversalResult valueOrDefault = traversalResult.GetValueOrDefault();
				Transform transform = ((Component)buildPiece).transform;
				transform.position += (Vector3)valueOrDefault.neighbourSnapNode - valueOrDefault.buildPieceSnapNode;
				return DeterminePlayerPoVOn(valueOrDefault.neighbourSnapNode, valueOrDefault.neighbourPiece);
			}
			return null;
		}

		private static RaycastHit? SnapExternally(Piece buildPiece, List<Piece> neighbourPieces, Vector3 playerPoV)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			SnapTree.TraversalResult? traversalResult = ((KeyBinder.precisionMode == PrecisionMode.ORDINARY) ? SnapTree.FindNearestOrdinaryPrecisionSnapNodeTo(playerPoV, neighbourPieces) : SnapTree.FindNearestSuperiorPrecisionSnapNodeTo(playerPoV, neighbourPieces));
			if (traversalResult.HasValue)
			{
				SnapTree.TraversalResult valueOrDefault = traversalResult.GetValueOrDefault();
				RaycastHit? val = DeterminePlayerPoVOn(valueOrDefault.neighbourSnapNode, valueOrDefault.neighbourPiece);
				if (val.HasValue)
				{
					RaycastHit valueOrDefault2 = val.GetValueOrDefault();
					Vector3 observer = (Vector3)valueOrDefault.neighbourSnapNode + ((RaycastHit)(ref valueOrDefault2)).normal;
					Vector3 val2 = valueOrDefault.neighbourPiece.ExitTo(observer);
					if (!buildPiece.ClipsIntoBuildPieces())
					{
						SnapExternally(buildPiece, val2, ((RaycastHit)(ref valueOrDefault2)).normal);
					}
					else
					{
						((Component)buildPiece).transform.position = val2;
					}
					return valueOrDefault2;
				}
			}
			return null;
		}

		private static void SnapExternally(Piece buildPiece, Vector3 neighbourPieceExit, Vector3 perpendicularToPlayerPoV)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			((Component)buildPiece).transform.position = neighbourPieceExit + perpendicularToPlayerPoV * 10f;
			Vector3 buildPieceExit = buildPiece.ExitTo(neighbourPieceExit);
			SnapPiecesByExits(buildPiece, buildPieceExit, neighbourPieceExit, perpendicularToPlayerPoV);
		}

		private static Vector3 DeterminePlayerPoV()
		{
			//IL_000a: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)GameCamera.instance).transform.position;
			Vector3 forward = ((Component)GameCamera.instance).transform.forward;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(position, forward, ref val, 250f, LayerMask))
			{
				return ((Component)PieceHelpers.buildPiece).transform.position;
			}
			return ((RaycastHit)(ref val)).point;
		}

		private static RaycastHit? DeterminePlayerPoVOn(Vector3 neighbourSnapNode, Piece neighbourPiece)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)GameCamera.instance).transform.position;
			Vector3 val = PokeToMiddle(neighbourSnapNode, neighbourPiece) - position;
			RaycastHit value = default(RaycastHit);
			if (!Physics.Raycast(position, val, ref value, 250f, LayerMask))
			{
				return null;
			}
			return value;
		}

		private static List<Piece> FindNeighbourPieces(Vector3 playerPoV)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			NeighbourPieces.Clear();
			int num = Physics.OverlapSphereNonAlloc(playerPoV, 2.5f, NeighbourColliders, PiecesOnly);
			for (int i = 0; i < num; i++)
			{
				Transform root = ((Component)NeighbourColliders[i]).transform.root;
				Piece val = ((root != null) ? ((Component)root).GetComponentInChildren<Piece>() : null);
				if ((Object)(object)val != (Object)null && val.Type().IsSnappable())
				{
					NeighbourPieces.Add(val);
				}
			}
			return NeighbourPieces;
		}

		private static Vector3 PokeToMiddle(Vector3 snapNode, Piece piece)
		{
			//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_000c: 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_0014: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)piece).transform.position - snapNode;
			Vector3 val2 = ((Vector3)(ref val)).normalized * 0.05f;
			return snapNode + val2;
		}

		private static void SnapPiecesByExits(Piece buildPiece, Vector3 buildPieceExit, Vector3 neighbourPieceEntry, Vector3 perpendicularToNeighbourPiece)
		{
			//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_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.Project(neighbourPieceEntry - buildPieceExit, perpendicularToNeighbourPiece);
			Transform transform = ((Component)buildPiece).transform;
			transform.position += val;
		}

		private static void FixVanillaValheimBugWithSpinningTerrainModificationVFX()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			((Component)PieceHelpers.buildPiece).transform.rotation = Quaternion.Euler(0f, 0f, 0f);
		}
	}
	[HarmonyPatch]
	public static class PreciseTerrainModifier
	{
		private const int AoESize = 1;

		public const int HTilesPerChunk = 64;

		private const int PTilesPerChunk = 65;

		public const float HalfPTilesPerChunk = 32f;

		public const float PTileSize = 64f / 65f;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("InternalDoOperation")]
		private static bool Prefix(Vector3 pos, Settings modifier, Heightmap ___m_hmap, ref float[] ___m_levelDelta, ref float[] ___m_smoothDelta, ref Color[] ___m_paintMask, ref bool[] ___m_modifiedHeight, ref bool[] ___m_modifiedPaint)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!modifier.m_level && !modifier.m_raise && !modifier.m_smooth && !modifier.m_paintCleared)
			{
				RemoveTerrainModifications(pos, ___m_hmap, ref ___m_levelDelta, ref ___m_smoothDelta, ref ___m_modifiedHeight);
				RecolorTerrain(pos, (PaintType)3, ___m_hmap, ref ___m_paintMask, ref ___m_modifiedPaint, removeColor: true);
			}
			return true;
		}

		public static void SmoothenTerrain(Vector3 worldPos, Heightmap hMap, TerrainComp compiler, ref float[] ΔL, ref float[] ΔS, ref bool[] modifiedHeight)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug(() => "[INIT] Smooth Terrain Modification");
			int xPos = default(int);
			int yPos = default(int);
			hMap.WorldToVertex(worldPos, ref xPos, ref yPos);
			float referenceH = worldPos.y - ((Component)compiler).transform.position.y;
			Logger.Debug(() => $"worldPos: {worldPos}, xPos: {xPos}, yPos: {yPos}, referenceH: {referenceH}");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int x = minVal; x <= maxVal; x++)
			{
				for (int y = minVal2; y <= maxVal2; y++)
				{
					int num = y * 65 + x;
					float tileH = hMap.GetHeight(x, y);
					float oldΔS = ΔS[num];
					float visibleOldΔS = TerrainLimiter.VisibleΔS(ΔL[num], oldΔS);
					float newΔS = visibleOldΔS + referenceH - tileH;
					float roundedNewΔS = RoundToTwoDecimals(tileH, visibleOldΔS, newΔS);
					float limitedNewΔS = TerrainLimiter.LimitΔS(ΔL[num], visibleOldΔS, roundedNewΔS);
					ΔS[num] = limitedNewΔS;
					modifiedHeight[num] = true;
					Logger.Debug(() => $"tilePos: ({x}, {y}), tileH: {tileH}, referenceH: {referenceH}, oldΔS: {oldΔS}, visibleΔS: {visibleOldΔS}, newΔS: {newΔS}, roundedNewΔS: {roundedNewΔS}, limitedNewΔS: {limitedNewΔS}");
				}
			}
			Logger.Debug(() => "[SUCCESS] Smooth Terrain Modification");
		}

		public static void RaiseTerrain(Vector3 worldPos, Heightmap hMap, TerrainComp compiler, float power, ref float[] ΔL, ref float[] ΔS, ref bool[] modifiedHeight)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug(() => "[INIT] Raise Terrain Modification");
			int xPos = default(int);
			int yPos = default(int);
			hMap.WorldToVertex(worldPos, ref xPos, ref yPos);
			float referenceH = worldPos.y - ((Component)compiler).transform.position.y + power;
			Logger.Debug(() => $"worldPos: {worldPos}, xPos: {xPos}, yPos: {yPos}, power: {power}, referenceH: {referenceH}");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int x = minVal; x <= maxVal; x++)
			{
				for (int y = minVal2; y <= maxVal2; y++)
				{
					int num = y * 65 + x;
					float tileH = hMap.GetHeight(x, y);
					if (referenceH >= tileH)
					{
						float oldΔL = ΔL[num];
						float oldΔS = ΔS[num];
						float num2 = TerrainLimiter.ΔH(oldΔL, oldΔS);
						float newΔL = num2 + referenceH - tileH;
						float newΔS = 0f;
						float roundedNewΔL = RoundToTwoDecimals(tileH, num2, newΔL + newΔS);
						float limitedNewΔL = TerrainLimiter.LimitΔL(num2, roundedNewΔL);
						ΔL[num] = limitedNewΔL;
						ΔS[num] = newΔS;
						modifiedHeight[num] = true;
						Logger.Debug(() => $"tilePos: ({x}, {y}), tileH: {tileH}, referenceH: {referenceH}, oldΔL: {oldΔL}, oldΔS: {oldΔS}, newΔL: {newΔL}, newΔS: {newΔS}, roundedNewΔL: {roundedNewΔL}, limitedNewΔL: {limitedNewΔL}");
					}
					else
					{
						Logger.Debug(() => "Declined to process tile: tileH > referenceH!");
						Logger.Debug(() => $"tilePos: ({x}, {y}), tileH: {tileH}, referenceH: {referenceH}");
					}
				}
			}
			Logger.Debug(() => "[SUCCESS] Raise Terrain Modification");
		}

		public static void RecolorTerrain(Vector3 worldPos, PaintType paintType, Heightmap hMap, ref Color[] paintMask, ref bool[] modifiedPaint, bool removeColor = false)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			Logger.Info(() => "[INIT] Color Terrain Modification");
			Color tileColor = ResolveColor(paintType);
			PositionRelativeTo(((Component)hMap).transform.position, worldPos, out var xPos, out var yPos);
			Logger.Info(() => $"worldPos: {worldPos}, chunkPos: {((Component)hMap).transform.position}, relPos: ({xPos}, {yPos})");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int num = minVal; num <= maxVal; num++)
			{
				for (int num2 = minVal2; num2 <= maxVal2; num2++)
				{
					tileColor.a = ResolveAlpha(hMap, num, num2);
					ApplyColor(num, num2, tileColor, ref paintMask, ref modifiedPaint, removeColor);
				}
			}
			Logger.Info(() => "[SUCCESS] Color Terrain Modification");
		}

		private static void RemoveTerrainModifications(Vector3 worldPos, Heightmap hMap, ref float[] ΔL, ref float[] ΔS, ref bool[] modifiedHeight)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug(() => "[INIT] Remove Terrain Modifications");
			int xPos = default(int);
			int yPos = default(int);
			hMap.WorldToVertex(worldPos, ref xPos, ref yPos);
			Logger.Debug(() => $"worldPos: {worldPos}, vertexPos: ({xPos}, {yPos})");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int x = minVal; x <= maxVal; x++)
			{
				for (int y = minVal2; y <= maxVal2; y++)
				{
					int tileIndex = y * 65 + x;
					ΔL[tileIndex] = 0f;
					ΔS[tileIndex] = 0f;
					modifiedHeight[tileIndex] = false;
					Logger.Debug(() => $"tilePos: ({x}, {y}), tileIndex: {tileIndex}");
				}
			}
			Logger.Debug(() => "[SUCCESS] Remove Terrain Modifications");
		}

		private static void FindExtremums(int val, out int minVal, out int maxVal)
		{
			minVal = Mathf.Max(0, val - 1);
			maxVal = Mathf.Min(val + 1, 64);
		}

		private static float RoundToTwoDecimals(float oldH, float oldΔ, float newΔ)
		{
			float newH = oldH - oldΔ + newΔ;
			float roundedNewH = Mathf.Round(newH * 100f) / 100f;
			float roundedNewΔ = roundedNewH - oldH + oldΔ;
			Logger.Debug(() => $"oldH: {oldH}, oldΔ: {oldΔ}, newΔ: {newΔ}, newH: {newH}, roundedNewH: {roundedNewH}, roundedNewΔ: {roundedNewΔ}");
			return roundedNewΔ;
		}

		private static void PositionRelativeTo(Vector3 chunkMid, Vector3 worldPos, out int x, out int y)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = chunkMid - new Vector3(32f, 0f, 32f);
			Vector3 val2 = worldPos - val;
			x = Mathf.FloorToInt(val2.x / (64f / 65f));
			y = Mathf.FloorToInt(val2.z / (64f / 65f));
		}

		private static float ResolveAlpha(Heightmap hMap, int x, int y)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return hMap.GetPaintMask(x, y).a;
		}

		private static Color ResolveColor(PaintType paintType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected I4, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			return (Color)((int)paintType switch
			{
				0 => Heightmap.m_paintMaskDirt, 
				2 => Heightmap.m_paintMaskPaved, 
				1 => Heightmap.m_paintMaskCultivated, 
				4 => Heightmap.m_paintMaskClearVegetation, 
				5 => Heightmap.m_paintMaskDeepSnow, 
				_ => Heightmap.m_paintMaskNothing, 
			});
		}

		private static void ApplyColor(int x, int y, Color tileColor, ref Color[] paintMask, ref bool[] modifiedPaint, bool removeColor = false)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			int tileIndex = y * 65 + x;
			paintMask[tileIndex] = tileColor;
			modifiedPaint[tileIndex] = !removeColor;
			Logger.Info(() => $"tilePos: ({x}, {y}), tileIndex: {tileIndex}, tileColor: {tileColor}");
		}
	}
	[HarmonyPatch]
	public static class PreciseSmoothTerrainModification
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("SmoothTerrain")]
		private static bool Prefix(Vector3 worldPos, TerrainComp __instance, Heightmap ___m_hmap, ref float[] ___m_levelDelta, ref float[] ___m_smoothDelta, ref bool[] ___m_modifiedHeight)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (GridModeOverride.enabled)
			{
				PreciseTerrainModifier.SmoothenTerrain(worldPos, ___m_hmap, __instance, ref ___m_levelDelta, ref ___m_smoothDelta, ref ___m_modifiedHeight);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class PreciseRaiseTerrainModification
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("RaiseTerrain")]
		private static bool Prefix(Vector3 worldPos, TerrainComp __instance, Heightmap ___m_hmap, ref float[] ___m_levelDelta, ref float[] ___m_smoothDelta, ref bool[] ___m_modifiedHeight)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (GridModeOverride.enabled)
			{
				PreciseTerrainModifier.RaiseTerrain(worldPos, ___m_hmap, __instance, GridModeOverride.raiseGroundΔ, ref ___m_levelDelta, ref ___m_smoothDelta, ref ___m_modifiedHeight);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class PreciseColorTerrainModification
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("PaintCleared")]
		private static bool Prefix(Vector3 worldPos, Settings settings, Heightmap ___m_hmap, ref Color[] ___m_paintMask, ref bool[] ___m_modifiedPaint)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (GridModeOverride.enabled)
			{
				PreciseTerrainModifier.RecolorTerrain(worldPos, settings.m_paintType, ___m_hmap, ref ___m_paintMask, ref ___m_modifiedPaint);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class GridModeOverride
	{
		private const string RPC = "RPC_ApplyOperation";

		private const int TailSize = 12;

		private static readonly int Marker = StringExtensionMethods.GetStableHashCode("OCDheim.GridMode");

		public static bool enabled { get; private set; }

		public static float raiseGroundΔ { get; private set; }

		public static float lowerGroundΔ { get; private set; }

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("ApplyOperation")]
		private static bool Send(TerrainOp modifier, ZNetView ___m_nview)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			if (!ShouldOverride(modifier))
			{
				return true;
			}
			ZPackage val = new ZPackage();
			AppendVanillaModifiers(val, modifier);
			AppendOCDheimModifiers(val);
			___m_nview.InvokeRPC("RPC_ApplyOperation", new object[1] { val });
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("RPC_ApplyOperation")]
		private static void Receive([HarmonyArgument("pkg")] ZPackage envelope)
		{
			int num = envelope.Size() - 12;
			enabled = false;
			if (num >= 0)
			{
				envelope.SetPos(num);
				if (envelope.ReadInt() == Marker)
				{
					enabled = true;
					raiseGroundΔ = envelope.ReadSingle();
					lowerGroundΔ = envelope.ReadSingle();
				}
				envelope.SetPos(0);
			}
		}

		private static bool ShouldOverride(TerrainOp modifier)
		{
			if (KeyBinder.gridModeEnabled && IsOCDheim(modifier))
			{
				return !IsSnow(modifier);
			}
			return false;
		}

		private static bool IsOCDheim(TerrainOp modifier)
		{
			return Object.op_Implicit((Object)(object)((Component)modifier).GetComponent<OverlayVisualizer>());
		}

		private static bool IsSnow(TerrainOp modifier)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0024: 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)
			Settings settings = modifier.m_settings;
			Vector3 position = ((Component)modifier).transform.position;
			if (settings.m_paintCleared && (int)settings.m_paintType == 1)
			{
				return WorldGenerator.IsDeepnorth(position.x, position.z);
			}
			return false;
		}

		private static void AppendVanillaModifiers(ZPackage envelope, TerrainOp modifier)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			envelope.Write(((Component)modifier).transform.position);
			envelope.Write(modifier.m_settings.m_rotation);
			if (modifier.m_settings.m_rotation)
			{
				envelope.Write(((Component)modifier).transform.forward);
			}
			modifier.m_settings.Serialize(envelope, ((Component)modifier).gameObject);
		}

		private static void AppendOCDheimModifiers(ZPackage envelope)
		{
			envelope.Write(Marker);
			envelope.Write(GroundLevelSpinner.RaiseGroundSpinner.value);
			envelope.Write(GroundLevelSpinner.LowerGroundSpinner.value);
		}
	}
	public static class PrecisionDrill
	{
		public readonly struct Floor
		{
			public float level { get; }

			public bool isGround { get; }

			public RaycastHit? drillStrike { get; }

			public Floor(RaycastHit drillStrike)
				: this(((RaycastHit)(ref drillStrike)).point.y, IsGround(((RaycastHit)(ref drillStrike)).collider), drillStrike)
			{
			}//IL_0003: 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)


			private Floor(float level, bool isGround, RaycastHit? drillStrike)
			{
				this.level = level;
				this.isGround = isGround;
				this.drillStrike = drillStrike;
			}

			public static Floor FallBack(Vector2 drillCoords)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				Logger.Warn(() => $"[FAILED] Precision Drill for: {drillCoords}");
				return new Floor(((Component)PlayerHelpers.player).transform.position.y, isGround: true, null);
			}

			private static bool IsGround(Collider collider)
			{
				return (GroundLayerMask & (1 << ((Component)collider).gameObject.layer)) != 0;
			}
		}

		public const float DropFromExosphere = 250f;

		private const float DrillSize = 0.01f;

		private static readonly int GroundLayerMask = LayerMask.GetMask(new string[1] { "terrain" });

		private static readonly int FloorLayerMask = LayerMask.GetMask(new string[3] { "terrain", "piece", "static_solid" });

		public static Floor DrillDownTillGround(Vector2 drillCoords)
		{
			//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_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit drillStrike = default(RaycastHit);
			if (!Physics.Raycast(WhereToDrillFrom(drillCoords), Vector3.down, ref drillStrike, 250f, GroundLayerMask))
			{
				return Floor.FallBack(drillCoords);
			}
			return new Floor(drillStrike);
		}

		private static Vector3 WhereToDrillFrom(Vector2 drillCoords)
		{
			//IL_0000: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(drillCoords.x, 250f, drillCoords.y);
		}

		public static Floor DrillDownTillFloor(Vector2 drillCoords, float referenceLevel, float requiredRoom)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			List<Floor> list = DrillDownFloors(drillCoords, requiredRoom);
			if (list.Count == 0)
			{
				return DrillDownTillGround(drillCoords);
			}
			Floor result = list[0];
			float num = Math.Abs(referenceLevel - result.level);
			foreach (Floor item in list)
			{
				float num2 = Math.Abs(referenceLevel - item.level);
				if (num2 < num)
				{
					num = num2;
					result = item;
				}
			}
			return result;
		}

		private static List<Floor> DrillDownFloors(Vector2 drillCoords, float requiredRoom, float drillTill = 250f)
		{
			//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_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = WhereToDrillFrom(drillCoords);
			float num = val.y;
			List<Floor> list = new List<Floor>();
			RaycastHit drillStrike = default(RaycastHit);
			while (Physics.SphereCast(val, 0.01f, Vector3.down, ref drillStrike, drillTill, FloorLayerMask))
			{
				float y = ((RaycastHit)(ref drillStrike)).point.y;
				if (!ShouldSkipDueToInsufficientSize(((RaycastHit)(ref drillStrike)).collider) && !ShouldSkipDueToInsufficientRoom(y, num, requiredRoom))
				{
					Floor item = new Floor(drillStrike);
					list.Add(item);
				}
				float val2 = UndersideOf(((RaycastHit)(ref drillStrike)).collider, drillCoords, y) ?? y;
				val.y -= ((RaycastHit)(ref drillStrike)).distance + 0.0001f;
				drillTill -= ((RaycastHit)(ref drillStrike)).distance + 0.0001f;
				num = Math.Min(num, val2);
			}
			return list;
		}

		private static float? UndersideOf(Collider collider, Vector2 drillCoords, float topLevel)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(drillCoords.x, topLevel - 250f, drillCoords.y);
			Ray val2 = default(Ray);
			((Ray)(ref val2))..ctor(val, Vector3.up);
			RaycastHit val3 = default(RaycastHit);
			if (!collider.Raycast(val2, ref val3, 250f))
			{
				return null;
			}
			return ((RaycastHit)(ref val3)).point.y;
		}

		private static bool ShouldSkipDueToInsufficientSize(Collider collider)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)((Component)collider).transform.root).GetComponentInChildren<Piece>() != (Object)null)
			{
				return false;
			}
			Bounds bounds = collider.bounds;
			if (!(((Bounds)(ref bounds)).max.x - ((Bounds)(ref bounds)).min.x < 0.5f))
			{
				return ((Bounds)(ref bounds)).max.z - ((Bounds)(ref bounds)).min.z < 0.5f;
			}
			return true;
		}

		private static bool ShouldSkipDueToInsufficientRoom(float floorLevel, float roofLevel, float requiredRoom)
		{
			float num = roofLevel - floorLevel;
			if (!(num <= 0f))
			{
				return num < requiredRoom;
			}
			return true;
		}
	}
	public enum PrecisionMode
	{
		ORDINARY = 1,
		SUPERIOR
	}
	public readonly struct Box : ISide
	{
		private const double Epsilon = 1E-08;

		private char name { get; }

		private Vector3 minMinSnapNode { get; }

		private Vector3 minMaxSnapNode { get; }

		private Vector3 maxMinSnapNode { get; }

		private Vector3 maxMaxSnapNode { get; }

		private SnapNode.Type primarySnapNodeType { get; }

		public Box(char name, Vector3 minMinSnapNode, Vector3 minMaxSnapNode, Vector3 maxMinSnapNode, Vector3 maxMaxSnapNode)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			this.minMinSnapNode = minMinSnapNode;
			this.minMaxSnapNode = minMaxSnapNode;
			this.maxMinSnapNode = maxMinSnapNode;
			this.maxMaxSnapNode = maxMaxSnapNode;
			primarySnapNodeType = SnapNode.Type.PRIMARY;
		}

		public Box(Piece piece, Vector2 shift, char name = 'A')
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			Vector3 val = piece.TopMiddle();
			minMinSnapNode = val + ((Component)piece).transform.rotation * new Vector3(0f - shift.x, 0f, 0f - shift.y);
			minMaxSnapNode = val + ((Component)piece).transform.rotation * new Vector3(0f - shift.x, 0f, shift.y);
			maxMinSnapNode = val + ((Component)piece).transform.rotation * new Vector3(shift.x, 0f, 0f - shift.y);
			maxMaxSnapNode = val + ((Component)piece).transform.rotation * new Vector3(shift.x, 0f, shift.y);
			primarySnapNodeType = SnapNode.Type.IMPOSED;
		}

		public void FillUp(HashSet<SnapNode> snapNodes)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0013: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 dimensionΔ = minMaxSnapNode - minMinSnapNode;
			Vector3 dimensionΔ2 = maxMinSnapNode - minMinSnapNode;
			(Vector3, int) tuple = RecursiveSplit(dimensionΔ);
			Vector3 item = tuple.Item1;
			int item2 = tuple.Item2;
			(Vector3, int) tuple2 = RecursiveSplit(dimensionΔ2);
			Vector3 item3 = tuple2.Item1;
			int item4 = tuple2.Item2;
			double num = Math.Pow(2.0, item2) + 1.0;
			double num2 = Math.Pow(2.0, item4) + 1.0;
			for (int i = 0; (double)i < num; i++)
			{
				for (int j = 0; (double)j < num2; j++)
				{
					Vector3 position = minMinSnapNode + item * (float)i + item3 * (float)j;
					if ((i == 0 || Math.Abs((double)i - (num - 1.0)) < 1E-08) && (j == 0 || Math.Abs((double)j - (num2 - 1.0)) < 1E-08))
					{
						snapNodes.Add(new SnapNode(position, primarySnapNodeType, SnapNode.Precision.ORDINARY));
					}
					else if ((float)i % 2f == 0f && (float)j % 2f == 0f)
					{
						snapNodes.Add(new SnapNode(position, SnapNode.Type.DERIVED, SnapNode.Precision.ORDINARY));
					}
					else
					{
						snapNodes.Add(new SnapNode(position, SnapNode.Type.DERIVED, SnapNode.Precision.SUPERIOR));
					}
				}
			}
		}

		private (Vector3, int) RecursiveSplit(Vector3 dimensionΔ, int splitLevel = 0)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (((Vector3)(ref dimensionΔ)).magnitude > 0.75f)
			{
				return RecursiveSplit(dimensionΔ * 0.5f, ++splitLevel);
			}
			return (dimensionΔ, splitLevel);
		}

		public override string ToString()
		{
			//IL_001c: 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_0038: 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)
			return $"Box {name}: ({minMinSnapNode}, {minMaxSnapNode}, {maxMinSnapNode}, {maxMaxSnapNode})";
		}
	}
	public readonly struct Circle : ISide
	{
		private const int CircleDivisions = 8;

		private char name { get; }

		private Vector3 midSnapNode { get; }

		private Vector2 radial { get; }

		public Circle(Piece piece, Vector2 radial, char name = 'A')
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			this.radial = radial;
			midSnapNode = piece.TopMiddle();
		}

		public void FillUp(HashSet<SnapNode> snapNodes)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 8; i++)
			{
				Vector3 val = Quaternion.Euler(new Vector3(0f, 45f * (float)i, 0f)) * Vector2.op_Implicit(radial);
				Vector3 val2 = midSnapNode + val;
				snapNodes.Add(new SnapNode(midSnapNode, SnapNode.Type.IMPOSED, SnapNode.Precision.ORDINARY));
				snapNodes.Add(new SnapNode(val2, SnapNode.Type.IMPOSED, SnapNode.Precision.ORDINARY));
				SnapNode.RecursiveSplit(midSnapNode, val2, snapNodes);
			}
		}

		public override string ToString()
		{
			//IL_0011: 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)
			return $"Circle {name}: {midSnapNode} + {radial} * quaternion rotation";
		}
	}
	public interface ISide
	{
		void FillUp(HashSet<SnapNode> snapNodes);
	}
	public readonly struct Line : ISide
	{
		private char name { get; }

		private Vector3 minSnapNode { get; }

		private Vector3 maxSnapNode { get; }

		public void FillUp(HashSet<SnapNode> snapNodes)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			SnapNode.RecursiveSplit(minSnapNode, maxSnapNode, snapNodes);
		}

		public Line(char name, Vector3 minSnapNode, Vector3 maxSnapNode)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			this.minSnapNode = minSnapNode;
			this.maxSnapNode = maxSnapNode;
		}

		public override string ToString()
		{
			//IL_0011: 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)
			return $"Line {name}: ({minSnapNode}, {maxSnapNode})";
		}
	}
	public readonly struct SnapNode : IEquatable<SnapNode>
	{
		public enum Type
		{
			PRIMARY,
			IMPOSED,
			DERIVED
		}

		public enum Precision
		{
			ORDINARY,
			SUPERIOR
		}

		public const float OrdinaryPrecisionSplitThreshold = 1.5f;

		public const float SuperiorPrecisionMultiplier = 2f;

		public Precision precision { get; }

		private Vector3 position { get; }

		private Type type { get; }

		private static bool ShouldSplitInOrdinaryPrecisionMode(Vector3 prevSnapNode, Vector3 nextSnapNode)
		{
			//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)
			return Vector3.Distance(prevSnapNode, nextSnapNode) > 1.5f;
		}

		private static bool ShouldSplitInSuperiorPrecisionMode(Vector3 prevSnapNode, Vector3 nextSnapNode)
		{
			//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)
			return Vector3.Distance(prevSnapNode, nextSnapNode) > 0.75f;
		}

		public SnapNode(Vector3 position, Type type, Precision precision)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			this.position = position;
			this.type = type;
			this.precision = precision;
		}

		public static void RecursiveSplit(Vector3 snapNodeA, Vector3 snapNodeB, HashSet<SnapNode> snapNodes)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			snapNodes.Add(new SnapNode(snapNodeA, Type.PRIMARY, Precision.ORDINARY));
			snapNodes.Add(new SnapNode(snapNodeB, Type.PRIMARY, Precision.ORDINARY));
			RecursiveSplitInOrdinaryPrecisionMode(snapNodeA, snapNodeB, snapNodes);
		}

		private static void RecursiveSplitInOrdinaryPrecisionMode(Vector3 snapNodeA, Vector3 snapNodeB, HashSet<SnapNode> snapNodes, int splitLevel = 0)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due