Decompiled source of Flattenheim v1.0.0

plugins/Flattenheim/Flattenheim.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Flattenheim;

[BepInPlugin("Flattenheim.Valheim", "Flattenheim", "1.0.0")]
public sealed class FlattenheimPlugin : BaseUnityPlugin
{
	private enum FlattenShape
	{
		Square,
		Circle
	}

	private enum GroundTextureMode
	{
		Dirt,
		KeepExisting
	}

	private enum TerrainToolKind
	{
		None,
		Hoe,
		Cultivator
	}

	private sealed class TerrainOpRadiusSnapshot
	{
		private readonly TerrainOp _terrainOp;

		private readonly float _levelRadius;

		private readonly float _raiseRadius;

		private readonly float _smoothRadius;

		private readonly float _paintRadius;

		internal TerrainOpRadiusSnapshot(TerrainOp terrainOp)
		{
			_terrainOp = terrainOp;
			_levelRadius = terrainOp.m_settings.m_levelRadius;
			_raiseRadius = terrainOp.m_settings.m_raiseRadius;
			_smoothRadius = terrainOp.m_settings.m_smoothRadius;
			_paintRadius = terrainOp.m_settings.m_paintRadius;
		}

		internal void Restore()
		{
			if (!((Object)(object)_terrainOp == (Object)null) && _terrainOp.m_settings != null)
			{
				_terrainOp.m_settings.m_levelRadius = _levelRadius;
				_terrainOp.m_settings.m_raiseRadius = _raiseRadius;
				_terrainOp.m_settings.m_smoothRadius = _smoothRadius;
				_terrainOp.m_settings.m_paintRadius = _paintRadius;
			}
		}
	}

	private sealed class TerrainModifierRadiusSnapshot
	{
		private readonly TerrainModifier _modifier;

		private readonly float _levelRadius;

		private readonly float _smoothRadius;

		internal TerrainModifierRadiusSnapshot(TerrainModifier modifier)
		{
			_modifier = modifier;
			_levelRadius = modifier.m_levelRadius;
			_smoothRadius = modifier.m_smoothRadius;
		}

		internal void Restore()
		{
			if (!((Object)(object)_modifier == (Object)null))
			{
				_modifier.m_levelRadius = _levelRadius;
				_modifier.m_smoothRadius = _smoothRadius;
			}
		}
	}

	private sealed class PlacementRadiusScope
	{
		internal readonly List<TerrainOpRadiusSnapshot> TerrainOps = new List<TerrainOpRadiusSnapshot>();

		internal readonly List<TerrainModifierRadiusSnapshot> TerrainModifiers = new List<TerrainModifierRadiusSnapshot>();

		internal readonly HashSet<int> SeenObjects = new HashSet<int>();

		internal int TerrainOpCount => TerrainOps.Count;

		internal int TerrainModifierCount => TerrainModifiers.Count;

		internal void Restore()
		{
			for (int i = 0; i < TerrainOps.Count; i++)
			{
				TerrainOps[i].Restore();
			}
			for (int j = 0; j < TerrainModifiers.Count; j++)
			{
				TerrainModifiers[j].Restore();
			}
			TerrainOps.Clear();
			TerrainModifiers.Clear();
			SeenObjects.Clear();
		}
	}

	public const string PluginGuid = "Flattenheim.Valheim";

	public const string PluginName = "Flattenheim";

	public const string PluginVersion = "1.0.0";

	private const float GridSize = 1f;

	private const float ApplyMoveThreshold = 0.5f;

	private const float ApplyInterval = 0.15f;

	private const float MaxTerrainOffset = 8f;

	private const string RampPrefabName = "Flattenheim_Ramp";

	private const string RevertPrefabName = "Flattenheim_RevertOriginalTerrain";

	private ConfigEntry<bool> _enabled;

	private ConfigEntry<float> _size;

	private ConfigEntry<float> _hardnessSmoothness;

	private ConfigEntry<FlattenShape> _shape;

	private ConfigEntry<GroundTextureMode> _groundTexture;

	private ConfigEntry<bool> _gridMovement;

	private ConfigEntry<bool> _toolRadiusEnabled;

	private ConfigEntry<float> _hoeRadius;

	private ConfigEntry<float> _cultivatorRadius;

	private ConfigEntry<KeyboardShortcut> _radiusIncreaseKey;

	private ConfigEntry<KeyboardShortcut> _radiusDecreaseKey;

	private ConfigEntry<float> _rampThickness;

	private ConfigEntry<float> _revertRadius;

	private ConfigEntry<KeyboardShortcut> _flattenHold;

	private bool _wasHolding;

	private Vector3 _lastApplyPosition = new Vector3(999999f, 999999f, 999999f);

	private float _lastApplyTime = -10f;

	private float _lastAppliedSize = -1f;

	private float _lastAppliedSmoothness = -1f;

	private FlattenShape _lastAppliedShape;

	private GroundTextureMode _lastAppliedTexture;

	private static FlattenheimPlugin _instance;

	private Harmony _harmony;

	private static bool _radiusToolActive = false;

	private static float _radiusOriginal = 0f;

	private static float _radiusTarget = 0f;

	private static float _radiusDelta = 0f;

	private static Vector3 _radiusGhostScale = Vector3.one;

	private static int _radiusSelectedPieceId = 0;

	private static TerrainToolKind _radiusToolKind = TerrainToolKind.None;

	private static FieldInfo _placementGhostField;

	private static MethodInfo _getRightItemMethod;

	private static PlacementRadiusScope _activePlacementRadiusScope;

	private GameObject _rampPiecePrefab;

	private PieceTable _rampHoeTable;

	private Texture2D _rampIconTexture;

	private Sprite _rampIconSprite;

	private Material _rampGhostMaterial;

	private static MethodInfo _updateAvailablePiecesMethod;

	private GameObject _rampTrajectoryRoot;

	private LineRenderer _rampTrajectoryOutline;

	private LineRenderer _rampTrajectoryCenter;

	private Material _rampTrajectoryMaterial;

	private bool _rampTrajectoryValid;

	private Vector3 _rampTrajectoryStart;

	private Vector3 _rampTrajectoryEnd;

	private GameObject _toolRadiusPreviewRoot;

	private LineRenderer _toolRadiusPreviewLine;

	private Material _toolRadiusPreviewMaterial;

	private GameObject _revertPiecePrefab;

	private PieceTable _revertHoeTable;

	private Texture2D _revertIconTexture;

	private Sprite _revertIconSprite;

	private GameObject _revertPreviewRoot;

	private LineRenderer _revertPreviewLine;

	private Material _revertPreviewMaterial;

	private bool _revertPreviewValid;

	private Vector3 _revertPreviewCenter;

	private GameObject _previewRoot;

	private LineRenderer _previewLine;

	private Material _previewMaterial;

	private static FieldInfo _fieldHmap;

	private static FieldInfo _fieldSize;

	private static FieldInfo _fieldLevelDelta;

	private static FieldInfo _fieldSmoothDelta;

	private static FieldInfo _fieldModifiedHeight;

	private static FieldInfo _fieldPaintMask;

	private static FieldInfo _fieldModifiedPaint;

	private static FieldInfo _fieldNview;

	private static MethodInfo _saveMethod;

	private bool _loggedBackendError;

	private void Awake()
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Expected O, but got Unknown
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Expected O, but got Unknown
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Expected O, but got Unknown
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Expected O, but got Unknown
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Expected O, but got Unknown
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Expected O, but got Unknown
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Expected O, but got Unknown
		//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Expected O, but got Unknown
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Expected O, but got Unknown
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0256: Expected O, but got Unknown
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0295: Expected O, but got Unknown
		//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Expected O, but got Unknown
		//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0306: Unknown result type (might be due to invalid IL or missing references)
		//IL_0310: Expected O, but got Unknown
		_instance = this;
		_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Enable or disable Flattenheim.", (AcceptableValueBase)null, new object[0]));
		_size = ((BaseUnityPlugin)this).Config.Bind<float>("Flattening", "Size (m)", 10f, new ConfigDescription("Total width/depth or diameter of the flattened area in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), new object[0]));
		_hardnessSmoothness = ((BaseUnityPlugin)this).Config.Bind<float>("Flattening", "Hardness / Smoothness", 35f, new ConfigDescription("0 = hardest/sharpest edge, 100 = widest/smoothest edge blend.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[0]));
		_shape = ((BaseUnityPlugin)this).Config.Bind<FlattenShape>("Flattening", "Shape", FlattenShape.Square, new ConfigDescription("Shape of the flattened area.", (AcceptableValueBase)null, new object[0]));
		_groundTexture = ((BaseUnityPlugin)this).Config.Bind<GroundTextureMode>("Flattening", "Ground Texture", GroundTextureMode.Dirt, new ConfigDescription("Dirt paints the flattened area with Valheim dirt. KeepExisting changes terrain height only and preserves the current ground texture.", (AcceptableValueBase)null, new object[0]));
		_gridMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "8 Direction Grid Movement", true, new ConfigDescription("While Flatten Hold is pressed with a pickaxe equipped, movement is locked to world-grid N/NE/E/SE/S/SW/W/NW directions regardless of camera angle.", (AcceptableValueBase)null, new object[0]));
		_toolRadiusEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Hoe & Cultivator Radius", "Enabled", true, new ConfigDescription("Enable adjustable radius for vanilla Hoe and Cultivator terrain operations.", (AcceptableValueBase)null, new object[0]));
		_hoeRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Hoe & Cultivator Radius", "Hoe Radius (m)", 2f, new ConfigDescription("Current Hoe terrain-operation radius in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 20f), new object[0]));
		_cultivatorRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Hoe & Cultivator Radius", "Cultivator Radius (m)", 2f, new ConfigDescription("Current Cultivator terrain-operation radius in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 20f), new object[0]));
		_radiusIncreaseKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hoe & Cultivator Radius", "Increase Radius", new KeyboardShortcut((KeyCode)280, (KeyCode[])(object)new KeyCode[0]), new ConfigDescription("Increase the radius of the currently equipped Hoe or Cultivator by 1 meter. Fully remappable.", (AcceptableValueBase)null, new object[0]));
		_radiusDecreaseKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hoe & Cultivator Radius", "Decrease Radius", new KeyboardShortcut((KeyCode)281, (KeyCode[])(object)new KeyCode[0]), new ConfigDescription("Decrease the radius of the currently equipped Hoe or Cultivator by 1 meter. Fully remappable.", (AcceptableValueBase)null, new object[0]));
		_rampThickness = ((BaseUnityPlugin)this).Config.Bind<float>("Ramp", "Thickness (m)", 4f, new ConfigDescription("Total width of the Ramp in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), new object[0]));
		_revertRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Revert Original Terrain", "Radius (m)", 5f, new ConfigDescription("Radius of the Revert Original Terrain Hoe tool.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), new object[0]));
		_flattenHold = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Flatten Hold", new KeyboardShortcut((KeyCode)324, (KeyCode[])(object)new KeyCode[0]), new ConfigDescription("Hold this while a pickaxe is equipped to flatten terrain under your character. Default: Right Mouse Button.", (AcceptableValueBase)null, new object[0]));
		CacheTerrainMembers();
		_updateAvailablePiecesMethod = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null);
		CreatePreviewObjects();
		PatchMovementControls();
		PatchTerrainToolRadius();
		PatchRampPlacement();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Flattenheim 1.0.0 loaded.");
	}

	private void OnDestroy()
	{
		try
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch
		{
		}
		RemoveRampPiece();
		RemoveRevertPiece();
		DestroyRampTrajectoryPreview();
		DestroyTerrainToolRadiusPreview();
		DestroyRevertPreview();
		_instance = null;
		DestroyPreviewObjects();
	}

	private void Update()
	{
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		if (_enabled == null || !_enabled.Value)
		{
			_wasHolding = false;
			SetPreviewVisible(visible: false);
			SetRampTrajectoryVisible(visible: false);
			SetTerrainToolRadiusPreviewVisible(visible: false);
			SetRevertPreviewVisible(visible: false);
			_rampTrajectoryValid = false;
			_revertPreviewValid = false;
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null)
		{
			EnsureRampPieceRegistered(localPlayer);
		}
		if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			_wasHolding = false;
			SetPreviewVisible(visible: false);
			SetRampTrajectoryVisible(visible: false);
			SetTerrainToolRadiusPreviewVisible(visible: false);
			SetRevertPreviewVisible(visible: false);
			_rampTrajectoryValid = false;
			_revertPreviewValid = false;
			return;
		}
		UpdateRampTrajectoryPreview(localPlayer);
		UpdateTerrainToolRadiusPreview(localPlayer);
		UpdateRevertPreview(localPlayer);
		ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon();
		HandleTerrainToolRadius(localPlayer);
		if (!IsPickaxe(currentWeapon))
		{
			_wasHolding = false;
			SetPreviewVisible(visible: false);
			return;
		}
		float num = Mathf.Clamp((_size != null) ? _size.Value : 10f, 1f, 20f);
		float num2 = Mathf.Clamp((_hardnessSmoothness != null) ? _hardnessSmoothness.Value : 35f, 0f, 100f);
		FlattenShape flattenShape = ((_shape != null) ? _shape.Value : FlattenShape.Square);
		GroundTextureMode groundTextureMode = ((_groundTexture != null) ? _groundTexture.Value : GroundTextureMode.Dirt);
		Vector3 position = ((Component)localPlayer).transform.position;
		Vector3 snappedCenter = GetSnappedCenter(position);
		UpdatePreview(snappedCenter, num, flattenShape);
		if (!ShortcutIsHeld((KeyboardShortcut)((_flattenHold != null) ? _flattenHold.Value : new KeyboardShortcut((KeyCode)324, (KeyCode[])(object)new KeyCode[0]))))
		{
			_wasHolding = false;
			return;
		}
		bool flag = !_wasHolding;
		bool flag2 = HorizontalDistance(snappedCenter, _lastApplyPosition) >= 0.5f;
		bool flag3 = Mathf.Abs(num - _lastAppliedSize) > 0.01f;
		bool flag4 = Mathf.Abs(num2 - _lastAppliedSmoothness) > 0.01f;
		bool flag5 = flattenShape != _lastAppliedShape;
		bool flag6 = groundTextureMode != _lastAppliedTexture;
		bool flag7 = Time.unscaledTime - _lastApplyTime >= 0.15f;
		_wasHolding = true;
		if (flag || flag3 || flag4 || flag5 || flag6 || (flag2 && flag7))
		{
			float groundHeight = ZoneSystem.instance.GetGroundHeight(position);
			if (ApplyFlatten(snappedCenter, groundHeight, num, num2, flattenShape, groundTextureMode))
			{
				_lastApplyPosition = snappedCenter;
				_lastAppliedSize = num;
				_lastAppliedSmoothness = num2;
				_lastAppliedShape = flattenShape;
				_lastAppliedTexture = groundTextureMode;
				_lastApplyTime = Time.unscaledTime;
			}
		}
	}

	private bool ApplyFlatten(Vector3 center, float targetWorldHeight, float size, float smoothnessPercent, FlattenShape shape, GroundTextureMode groundTexture)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0305: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_035c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			CacheTerrainMembers();
			float num = Mathf.Clamp(size * 0.5f, 0.5f, 10f);
			float num2 = Mathf.Clamp01(smoothnessPercent / 100f);
			float num3 = num * 0.5f * num2;
			HashSet<TerrainComp> hashSet = CollectTerrainCompilers(center, num);
			if (hashSet.Count == 0)
			{
				LogBackendError("No TerrainComp could be found or created for the selected area.");
				return false;
			}
			bool result = false;
			foreach (TerrainComp item in hashSet)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ClaimOwnership(item);
				Heightmap field = GetField<Heightmap>(_fieldHmap, item);
				float[] field2 = GetField<float[]>(_fieldLevelDelta, item);
				float[] field3 = GetField<float[]>(_fieldSmoothDelta, item);
				bool[] field4 = GetField<bool[]>(_fieldModifiedHeight, item);
				Color[] field5 = GetField<Color[]>(_fieldPaintMask, item);
				bool[] field6 = GetField<bool[]>(_fieldModifiedPaint, item);
				if ((Object)(object)field == (Object)null || field2 == null || field3 == null || field4 == null)
				{
					continue;
				}
				int width = field.m_width;
				float scale = field.m_scale;
				Vector3 position = ((Component)field).transform.position;
				int num4 = width / 2;
				bool flag = false;
				for (int i = 0; i <= width; i++)
				{
					for (int j = 0; j <= width; j++)
					{
						float num5 = position.x + (float)(j - num4) * scale;
						float num6 = position.z + (float)(i - num4) * scale;
						float num7 = num5 - center.x;
						float num8 = num6 - center.z;
						float num9 = ((shape != FlattenShape.Square) ? Mathf.Sqrt(num7 * num7 + num8 * num8) : Mathf.Max(Mathf.Abs(num7), Mathf.Abs(num8)));
						if (num9 > num + scale * 0.5f + 0.05f)
						{
							continue;
						}
						int num10 = i * (width + 1) + j;
						if (num10 < 0 || num10 >= field2.Length || num10 >= field3.Length || num10 >= field4.Length)
						{
							continue;
						}
						float height = field.GetHeight(j, i);
						float num11 = 1f;
						if (num3 > 0.001f)
						{
							float num12 = num - num9;
							num11 = Mathf.Clamp01(num12 / num3);
							num11 = num11 * num11 * (3f - 2f * num11);
						}
						float num13 = Mathf.Lerp(height, targetWorldHeight, num11);
						float num14 = num13 - height;
						num14 += field3[num10];
						field3[num10] = 0f;
						field2[num10] += num14;
						field2[num10] = Mathf.Clamp(field2[num10], -8f, 8f);
						field4[num10] = true;
						if (groundTexture == GroundTextureMode.Dirt && field5 != null && field6 != null && j < width && i < width)
						{
							int num15 = i * width + j;
							if (num15 >= 0 && num15 < field5.Length && num15 < field6.Length)
							{
								Color paintMaskDirt = Heightmap.m_paintMaskDirt;
								try
								{
									paintMaskDirt.a = field.GetPaintMask(j, i).a;
								}
								catch
								{
									paintMaskDirt.a = field5[num15].a;
								}
								field5[num15] = paintMaskDirt;
								field6[num15] = true;
							}
						}
						flag = true;
						result = true;
					}
				}
				if (flag)
				{
					SaveTerrainComp(item);
					field.Poke(0, false);
					if ((Object)(object)ClutterSystem.instance != (Object)null)
					{
						ClutterSystem.instance.ResetGrass(center, num + 2f);
					}
				}
			}
			return result;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Flattenheim direct TerrainComp operation failed: " + ex));
			return false;
		}
	}

	private static HashSet<TerrainComp> CollectTerrainCompilers(Vector3 center, float halfSize)
	{
		//IL_0078: 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)
		HashSet<TerrainComp> hashSet = new HashSet<TerrainComp>();
		float num = 0f - halfSize - 4f;
		float num2 = halfSize + 4f;
		Vector3 point = default(Vector3);
		for (float num3 = num; num3 <= num2; num3 += 8f)
		{
			for (float num4 = num; num4 <= num2; num4 += 8f)
			{
				((Vector3)(ref point))..ctor(center.x + num3, center.y, center.z + num4);
				TerrainComp orCreateCompiler = GetOrCreateCompiler(point);
				if ((Object)(object)orCreateCompiler != (Object)null)
				{
					hashSet.Add(orCreateCompiler);
				}
			}
		}
		TerrainComp orCreateCompiler2 = GetOrCreateCompiler(center);
		if ((Object)(object)orCreateCompiler2 != (Object)null)
		{
			hashSet.Add(orCreateCompiler2);
		}
		return hashSet;
	}

	private static TerrainComp GetOrCreateCompiler(Vector3 point)
	{
		//IL_0000: 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)
		TerrainComp val = TerrainComp.FindTerrainCompiler(point);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		Heightmap val2 = Heightmap.FindHeightmap(point);
		if ((Object)(object)val2 == (Object)null)
		{
			return null;
		}
		return val2.GetAndCreateTerrainCompiler();
	}

	private static void ClaimOwnership(TerrainComp comp)
	{
		if ((Object)(object)comp == (Object)null || _fieldNview == null)
		{
			return;
		}
		try
		{
			object? value = _fieldNview.GetValue(comp);
			ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
			if ((Object)(object)val != (Object)null && val.IsValid() && !val.IsOwner())
			{
				val.ClaimOwnership();
			}
		}
		catch
		{
		}
	}

	private static void SaveTerrainComp(TerrainComp comp)
	{
		if ((Object)(object)comp == (Object)null || _saveMethod == null)
		{
			return;
		}
		try
		{
			_saveMethod.Invoke(comp, new object[1] { false });
		}
		catch
		{
		}
	}

	private static T GetField<T>(FieldInfo field, object instance) where T : class
	{
		if (field == null || instance == null)
		{
			return null;
		}
		return field.GetValue(instance) as T;
	}

	private void UpdateRampTrajectoryPreview(Player player)
	{
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_0208: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_027c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		_rampTrajectoryValid = false;
		if ((Object)(object)player == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			SetRampTrajectoryVisible(visible: false);
			return;
		}
		Piece piece = null;
		try
		{
			piece = player.GetSelectedPiece();
		}
		catch
		{
		}
		if (!IsRampPiece(piece))
		{
			SetRampTrajectoryVisible(visible: false);
			return;
		}
		GameObject val = null;
		try
		{
			if (_placementGhostField != null)
			{
				object? value = _placementGhostField.GetValue(player);
				val = (GameObject)((value is GameObject) ? value : null);
			}
		}
		catch
		{
		}
		if ((Object)(object)val == (Object)null)
		{
			SetRampTrajectoryVisible(visible: false);
			return;
		}
		Vector3 position = ((Component)player).transform.position;
		Vector3 position2 = val.transform.position;
		position.y = ZoneSystem.instance.GetGroundHeight(position);
		position2.y = ZoneSystem.instance.GetGroundHeight(position2);
		float num = position2.x - position.x;
		float num2 = position2.z - position.z;
		float num3 = Mathf.Sqrt(num * num + num2 * num2);
		if (num3 < 0.25f)
		{
			SetRampTrajectoryVisible(visible: false);
			return;
		}
		float num4 = Mathf.Clamp((_rampThickness != null) ? _rampThickness.Value : 4f, 1f, 20f);
		float num5 = num4 * 0.5f;
		EnsureRampTrajectoryPreview();
		if (!((Object)(object)_rampTrajectoryOutline == (Object)null) && !((Object)(object)_rampTrajectoryCenter == (Object)null))
		{
			float num6 = num / num3;
			float num7 = num2 / num3;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0f - num7, 0f, num6);
			Vector3 val3 = position + val2 * num5;
			Vector3 val4 = position2 + val2 * num5;
			Vector3 val5 = position - val2 * num5;
			Vector3 val6 = position2 - val2 * num5;
			val3.y = position.y + 0.1f;
			val5.y = position.y + 0.1f;
			val4.y = position2.y + 0.1f;
			val6.y = position2.y + 0.1f;
			Vector3 val7 = position;
			Vector3 val8 = position2;
			val7.y += 0.13f;
			val8.y += 0.13f;
			_rampTrajectoryOutline.positionCount = 5;
			_rampTrajectoryOutline.SetPosition(0, val3);
			_rampTrajectoryOutline.SetPosition(1, val4);
			_rampTrajectoryOutline.SetPosition(2, val6);
			_rampTrajectoryOutline.SetPosition(3, val5);
			_rampTrajectoryOutline.SetPosition(4, val3);
			_rampTrajectoryCenter.positionCount = 2;
			_rampTrajectoryCenter.SetPosition(0, val7);
			_rampTrajectoryCenter.SetPosition(1, val8);
			_rampTrajectoryStart = position;
			_rampTrajectoryEnd = position2;
			_rampTrajectoryValid = true;
			SetRampTrajectoryVisible(visible: true);
		}
	}

	private void EnsureRampTrajectoryPreview()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Expected O, but got Unknown
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Expected O, but got Unknown
		if (!((Object)(object)_rampTrajectoryRoot != (Object)null))
		{
			_rampTrajectoryRoot = new GameObject("Flattenheim_Ramp_Trajectory");
			((Object)_rampTrajectoryRoot).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)_rampTrajectoryRoot);
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Unlit/Color");
			}
			_rampTrajectoryMaterial = new Material(val);
			((Object)_rampTrajectoryMaterial).hideFlags = (HideFlags)61;
			_rampTrajectoryMaterial.color = new Color(1f, 0.82f, 0.18f, 0.95f);
			GameObject val2 = new GameObject("RampOutline");
			val2.transform.SetParent(_rampTrajectoryRoot.transform, false);
			_rampTrajectoryOutline = val2.AddComponent<LineRenderer>();
			ConfigureRampLine(_rampTrajectoryOutline, 0.065f);
			GameObject val3 = new GameObject("RampCenter");
			val3.transform.SetParent(_rampTrajectoryRoot.transform, false);
			_rampTrajectoryCenter = val3.AddComponent<LineRenderer>();
			ConfigureRampLine(_rampTrajectoryCenter, 0.035f);
			SetRampTrajectoryVisible(visible: false);
		}
	}

	private void ConfigureRampLine(LineRenderer line, float width)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)line == (Object)null))
		{
			line.useWorldSpace = true;
			line.loop = false;
			line.startWidth = width;
			line.endWidth = width;
			((Renderer)line).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)line).receiveShadows = false;
			line.numCornerVertices = 2;
			line.numCapVertices = 1;
			((Renderer)line).material = _rampTrajectoryMaterial;
			line.startColor = _rampTrajectoryMaterial.color;
			line.endColor = _rampTrajectoryMaterial.color;
		}
	}

	private void SetRampTrajectoryVisible(bool visible)
	{
		if ((Object)(object)_rampTrajectoryRoot != (Object)null && _rampTrajectoryRoot.activeSelf != visible)
		{
			_rampTrajectoryRoot.SetActive(visible);
		}
	}

	private void DestroyRampTrajectoryPreview()
	{
		_rampTrajectoryValid = false;
		if ((Object)(object)_rampTrajectoryMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)_rampTrajectoryMaterial);
			_rampTrajectoryMaterial = null;
		}
		if ((Object)(object)_rampTrajectoryRoot != (Object)null)
		{
			Object.Destroy((Object)(object)_rampTrajectoryRoot);
			_rampTrajectoryRoot = null;
		}
		_rampTrajectoryOutline = null;
		_rampTrajectoryCenter = null;
	}

	private void UpdateTerrainToolRadiusPreview(Player player)
	{
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || _toolRadiusEnabled == null || !_toolRadiusEnabled.Value)
		{
			SetTerrainToolRadiusPreviewVisible(visible: false);
			return;
		}
		Piece val = null;
		try
		{
			val = player.GetSelectedPiece();
		}
		catch
		{
		}
		if ((Object)(object)val == (Object)null || IsRampPiece(val) || IsRevertPiece(val) || (Object)(object)((Component)val).GetComponent<TerrainOp>() == (Object)null)
		{
			SetTerrainToolRadiusPreviewVisible(visible: false);
			return;
		}
		ItemData equippedTerrainToolItem = GetEquippedTerrainToolItem(player);
		TerrainToolKind terrainToolKind = GetTerrainToolKind(equippedTerrainToolItem);
		if (terrainToolKind == TerrainToolKind.None)
		{
			SetTerrainToolRadiusPreviewVisible(visible: false);
			return;
		}
		GameObject val2 = null;
		try
		{
			if (_placementGhostField != null)
			{
				object? value = _placementGhostField.GetValue(player);
				val2 = (GameObject)((value is GameObject) ? value : null);
			}
		}
		catch
		{
		}
		if ((Object)(object)val2 == (Object)null)
		{
			SetTerrainToolRadiusPreviewVisible(visible: false);
			return;
		}
		float configuredToolRadius = GetConfiguredToolRadius(terrainToolKind);
		Vector3 position = val2.transform.position;
		position.y = ZoneSystem.instance.GetGroundHeight(position);
		EnsureTerrainToolRadiusPreview();
		if (!((Object)(object)_toolRadiusPreviewLine == (Object)null))
		{
			_toolRadiusPreviewLine.positionCount = 65;
			Vector3 val3 = default(Vector3);
			for (int i = 0; i <= 64; i++)
			{
				float num = (float)i / 64f * (float)Math.PI * 2f;
				((Vector3)(ref val3))..ctor(position.x + Mathf.Cos(num) * configuredToolRadius, position.y, position.z + Mathf.Sin(num) * configuredToolRadius);
				val3.y = ZoneSystem.instance.GetGroundHeight(val3) + 0.1f;
				_toolRadiusPreviewLine.SetPosition(i, val3);
			}
			SetTerrainToolRadiusPreviewVisible(visible: true);
		}
	}

	private void EnsureTerrainToolRadiusPreview()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_toolRadiusPreviewRoot != (Object)null))
		{
			_toolRadiusPreviewRoot = new GameObject("Flattenheim_ToolRadius_Preview");
			((Object)_toolRadiusPreviewRoot).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)_toolRadiusPreviewRoot);
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Unlit/Color");
			}
			_toolRadiusPreviewMaterial = new Material(val);
			((Object)_toolRadiusPreviewMaterial).hideFlags = (HideFlags)61;
			_toolRadiusPreviewMaterial.color = new Color(1f, 0.9f, 0.35f, 0.95f);
			_toolRadiusPreviewLine = _toolRadiusPreviewRoot.AddComponent<LineRenderer>();
			_toolRadiusPreviewLine.useWorldSpace = true;
			_toolRadiusPreviewLine.loop = false;
			_toolRadiusPreviewLine.startWidth = 0.055f;
			_toolRadiusPreviewLine.endWidth = 0.055f;
			((Renderer)_toolRadiusPreviewLine).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_toolRadiusPreviewLine).receiveShadows = false;
			_toolRadiusPreviewLine.numCornerVertices = 2;
			((Renderer)_toolRadiusPreviewLine).material = _toolRadiusPreviewMaterial;
			_toolRadiusPreviewLine.startColor = _toolRadiusPreviewMaterial.color;
			_toolRadiusPreviewLine.endColor = _toolRadiusPreviewMaterial.color;
			SetTerrainToolRadiusPreviewVisible(visible: false);
		}
	}

	private void SetTerrainToolRadiusPreviewVisible(bool visible)
	{
		if ((Object)(object)_toolRadiusPreviewRoot != (Object)null && _toolRadiusPreviewRoot.activeSelf != visible)
		{
			_toolRadiusPreviewRoot.SetActive(visible);
		}
	}

	private void DestroyTerrainToolRadiusPreview()
	{
		if ((Object)(object)_toolRadiusPreviewMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)_toolRadiusPreviewMaterial);
			_toolRadiusPreviewMaterial = null;
		}
		if ((Object)(object)_toolRadiusPreviewRoot != (Object)null)
		{
			Object.Destroy((Object)(object)_toolRadiusPreviewRoot);
			_toolRadiusPreviewRoot = null;
		}
		_toolRadiusPreviewLine = null;
	}

	private bool EnsureRevertPieceInTable(PieceTable table)
	{
		if ((Object)(object)table == (Object)null)
		{
			return false;
		}
		if ((Object)(object)_revertPiecePrefab == (Object)null)
		{
			GameObject val = FindHoeLevelGroundSource(table);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			_revertPiecePrefab = CreateRevertPiecePrefab(val);
			if ((Object)(object)_revertPiecePrefab == (Object)null)
			{
				return false;
			}
		}
		bool result = false;
		if (!table.m_pieces.Contains(_revertPiecePrefab))
		{
			int num = (((Object)(object)_rampPiecePrefab != (Object)null) ? table.m_pieces.IndexOf(_rampPiecePrefab) : (-1));
			int index = ((num >= 0) ? (num + 1) : table.m_pieces.Count);
			table.m_pieces.Insert(index, _revertPiecePrefab);
			result = true;
		}
		_revertHoeTable = table;
		return result;
	}

	private GameObject CreateRevertPiecePrefab(GameObject source)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		//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_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		Piece val = (((Object)(object)source != (Object)null) ? source.GetComponent<Piece>() : null);
		GameObject val2 = new GameObject("Flattenheim_RevertOriginalTerrain");
		val2.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)val2);
		Piece val3 = val2.AddComponent<Piece>();
		val3.m_name = "Revert Original Terrain";
		val3.m_description = "Restores terrain modifications inside the selected radius.";
		val3.m_enabled = true;
		val3.m_canBeRemoved = false;
		if ((Object)(object)val != (Object)null)
		{
			try
			{
				val3.m_category = val.m_category;
			}
			catch
			{
			}
		}
		if ((Object)(object)_revertIconSprite == (Object)null)
		{
			_revertIconSprite = CreateRevertIcon();
		}
		if ((Object)(object)_revertIconSprite != (Object)null)
		{
			val3.m_icon = _revertIconSprite;
		}
		GameObject val4 = new GameObject("_GhostOnly");
		val4.transform.SetParent(val2.transform, false);
		return val2;
	}

	private Sprite CreateRevertIcon()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_0086: 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_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		_revertIconTexture = new Texture2D(64, 64, (TextureFormat)4, false);
		((Texture)_revertIconTexture).filterMode = (FilterMode)0;
		Color[] array = (Color[])(object)new Color[4096];
		Color val = default(Color);
		((Color)(ref val))..ctor(0f, 0f, 0f, 0f);
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(0.44f, 0.28f, 0.13f, 1f);
		Color val3 = default(Color);
		((Color)(ref val3))..ctor(0.88f, 0.88f, 0.62f, 1f);
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = val;
		}
		for (int j = 0; j < 64; j++)
		{
			for (int k = 0; k < 64; k++)
			{
				float num = (float)k - 32f;
				float num2 = (float)j - 32f;
				float num3 = Mathf.Sqrt(num * num + num2 * num2);
				if (num3 <= 22f)
				{
					array[j * 64 + k] = val2;
				}
				if (num3 >= 16f && num3 <= 20f && k <= 48 && j >= 18)
				{
					array[j * 64 + k] = val3;
				}
			}
		}
		for (int l = 17; l <= 35; l++)
		{
			for (int m = 7; m <= 26; m++)
			{
				if (m - 7 + Mathf.Abs(l - 26) <= 18)
				{
					array[l * 64 + m] = val3;
				}
			}
		}
		_revertIconTexture.SetPixels(array);
		_revertIconTexture.Apply(false, false);
		_revertIconSprite = Sprite.Create(_revertIconTexture, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f);
		((Object)_revertIconSprite).name = "Flattenheim_Revert_Icon";
		return _revertIconSprite;
	}

	private static bool IsRevertPiece(Piece piece)
	{
		FlattenheimPlugin instance = _instance;
		if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).gameObject == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)instance._revertPiecePrefab == (Object)null)
		{
			return false;
		}
		Piece component = instance._revertPiecePrefab.GetComponent<Piece>();
		if ((Object)(object)piece == (Object)(object)component)
		{
			return true;
		}
		string a = ((Object)((Component)piece).gameObject).name ?? "";
		if (!string.Equals(a, "Flattenheim_RevertOriginalTerrain", StringComparison.Ordinal))
		{
			return string.Equals(a, "Flattenheim_RevertOriginalTerrain(Clone)", StringComparison.Ordinal);
		}
		return true;
	}

	private static bool TryGetLiveTerrainAimPoint(Player player, out Vector3 terrainPoint)
	{
		//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_003c: 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_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		terrainPoint = Vector3.zero;
		if ((Object)(object)player == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			return false;
		}
		Camera main = Camera.main;
		if ((Object)(object)main == (Object)null)
		{
			return false;
		}
		Ray val = default(Ray);
		((Ray)(ref val))..ctor(((Component)main).transform.position, ((Component)main).transform.forward);
		RaycastHit[] array;
		try
		{
			array = Physics.RaycastAll(val, 100f, -1, (QueryTriggerInteraction)1);
		}
		catch
		{
			return false;
		}
		if (array == null || array.Length == 0)
		{
			return false;
		}
		Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
		for (int num = 0; num < array.Length; num++)
		{
			Collider collider = ((RaycastHit)(ref array[num])).collider;
			if (!((Object)(object)collider == (Object)null))
			{
				Heightmap val2 = ((Component)collider).GetComponent<Heightmap>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = ((Component)collider).GetComponentInParent<Heightmap>();
				}
				if (!((Object)(object)val2 == (Object)null))
				{
					terrainPoint = ((RaycastHit)(ref array[num])).point;
					terrainPoint.y = ZoneSystem.instance.GetGroundHeight(terrainPoint);
					return true;
				}
			}
		}
		return false;
	}

	private void UpdateRevertPreview(Player player)
	{
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		_revertPreviewValid = false;
		if ((Object)(object)player == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			SetRevertPreviewVisible(visible: false);
			return;
		}
		Piece piece = null;
		try
		{
			piece = player.GetSelectedPiece();
		}
		catch
		{
		}
		if (!IsRevertPiece(piece))
		{
			SetRevertPreviewVisible(visible: false);
			return;
		}
		if (!TryGetLiveTerrainAimPoint(player, out var terrainPoint))
		{
			SetRevertPreviewVisible(visible: false);
			return;
		}
		float num = Mathf.Clamp((_revertRadius != null) ? _revertRadius.Value : 5f, 1f, 20f);
		EnsureRevertPreview();
		if (!((Object)(object)_revertPreviewLine == (Object)null))
		{
			_revertPreviewLine.positionCount = 65;
			Vector3 val = default(Vector3);
			for (int i = 0; i <= 64; i++)
			{
				float num2 = (float)i / 64f * (float)Math.PI * 2f;
				((Vector3)(ref val))..ctor(terrainPoint.x + Mathf.Cos(num2) * num, terrainPoint.y, terrainPoint.z + Mathf.Sin(num2) * num);
				val.y = ZoneSystem.instance.GetGroundHeight(val) + 0.1f;
				_revertPreviewLine.SetPosition(i, val);
			}
			_revertPreviewCenter = terrainPoint;
			_revertPreviewValid = true;
			SetRevertPreviewVisible(visible: true);
		}
	}

	private void EnsureRevertPreview()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_revertPreviewRoot != (Object)null))
		{
			_revertPreviewRoot = new GameObject("Flattenheim_Revert_Preview");
			((Object)_revertPreviewRoot).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)_revertPreviewRoot);
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Unlit/Color");
			}
			_revertPreviewMaterial = new Material(val);
			((Object)_revertPreviewMaterial).hideFlags = (HideFlags)61;
			_revertPreviewMaterial.color = new Color(0.7f, 0.95f, 0.58f, 0.95f);
			_revertPreviewLine = _revertPreviewRoot.AddComponent<LineRenderer>();
			_revertPreviewLine.useWorldSpace = true;
			_revertPreviewLine.loop = false;
			_revertPreviewLine.startWidth = 0.065f;
			_revertPreviewLine.endWidth = 0.065f;
			((Renderer)_revertPreviewLine).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_revertPreviewLine).receiveShadows = false;
			_revertPreviewLine.numCornerVertices = 2;
			((Renderer)_revertPreviewLine).material = _revertPreviewMaterial;
			_revertPreviewLine.startColor = _revertPreviewMaterial.color;
			_revertPreviewLine.endColor = _revertPreviewMaterial.color;
			SetRevertPreviewVisible(visible: false);
		}
	}

	private void SetRevertPreviewVisible(bool visible)
	{
		if ((Object)(object)_revertPreviewRoot != (Object)null && _revertPreviewRoot.activeSelf != visible)
		{
			_revertPreviewRoot.SetActive(visible);
		}
	}

	private void DestroyRevertPreview()
	{
		_revertPreviewValid = false;
		if ((Object)(object)_revertPreviewMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)_revertPreviewMaterial);
			_revertPreviewMaterial = null;
		}
		if ((Object)(object)_revertPreviewRoot != (Object)null)
		{
			Object.Destroy((Object)(object)_revertPreviewRoot);
			_revertPreviewRoot = null;
		}
		_revertPreviewLine = null;
	}

	private bool ApplyRevertOriginalTerrain(Player player)
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		UpdateRevertPreview(player);
		if (!_revertPreviewValid)
		{
			((Character)player).Message((MessageType)2, "Revert: no valid target.", 0, (Sprite)null, false);
			return false;
		}
		float radius = Mathf.Clamp((_revertRadius != null) ? _revertRadius.Value : 5f, 1f, 20f);
		int num = RevertTerrainAt(_revertPreviewCenter, radius);
		((Character)player).Message((MessageType)2, "Reverted terrain: " + num + " vertices", 0, (Sprite)null, false);
		return num > 0;
	}

	private int RevertTerrainAt(Vector3 center, float radius)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0287: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		CacheTerrainMembers();
		HashSet<TerrainComp> hashSet = CollectTerrainCompilers(center, radius + 4f);
		int num = 0;
		foreach (TerrainComp item in hashSet)
		{
			if ((Object)(object)item == (Object)null)
			{
				continue;
			}
			ClaimOwnership(item);
			Heightmap field = GetField<Heightmap>(_fieldHmap, item);
			float[] field2 = GetField<float[]>(_fieldLevelDelta, item);
			float[] field3 = GetField<float[]>(_fieldSmoothDelta, item);
			bool[] field4 = GetField<bool[]>(_fieldModifiedHeight, item);
			Color[] field5 = GetField<Color[]>(_fieldPaintMask, item);
			bool[] field6 = GetField<bool[]>(_fieldModifiedPaint, item);
			if ((Object)(object)field == (Object)null || field2 == null || field3 == null || field4 == null)
			{
				continue;
			}
			int width = field.m_width;
			float scale = field.m_scale;
			int num2 = width / 2;
			Vector3 position = ((Component)field).transform.position;
			bool flag = false;
			for (int i = 0; i <= width; i++)
			{
				for (int j = 0; j <= width; j++)
				{
					float num3 = position.x + (float)(j - num2) * scale;
					float num4 = position.z + (float)(i - num2) * scale;
					float num5 = num3 - center.x;
					float num6 = num4 - center.z;
					if (num5 * num5 + num6 * num6 > radius * radius)
					{
						continue;
					}
					int num7 = i * (width + 1) + j;
					if (num7 < 0 || num7 >= field2.Length || num7 >= field3.Length || num7 >= field4.Length)
					{
						continue;
					}
					if (field4[num7] || Mathf.Abs(field2[num7]) > 0.0001f || Mathf.Abs(field3[num7]) > 0.0001f)
					{
						num++;
						flag = true;
					}
					field2[num7] = 0f;
					field3[num7] = 0f;
					field4[num7] = false;
					if (field5 == null || field6 == null || j >= width || i >= width)
					{
						continue;
					}
					int num8 = i * width + j;
					if (num8 >= 0 && num8 < field5.Length && num8 < field6.Length)
					{
						if (field6[num8])
						{
							flag = true;
						}
						Color paintMaskNothing = Heightmap.m_paintMaskNothing;
						try
						{
							paintMaskNothing.a = field.GetPaintMask(j, i).a;
						}
						catch
						{
						}
						field5[num8] = paintMaskNothing;
						field6[num8] = false;
					}
				}
			}
			if (flag)
			{
				SaveTerrainComp(item);
				field.Poke(0, false);
			}
		}
		if (num > 0 && (Object)(object)ClutterSystem.instance != (Object)null)
		{
			ClutterSystem.instance.ResetGrass(center, radius + 2f);
		}
		return num;
	}

	private void RemoveRevertPiece()
	{
		try
		{
			if ((Object)(object)_revertHoeTable != (Object)null && (Object)(object)_revertPiecePrefab != (Object)null)
			{
				_revertHoeTable.m_pieces.Remove(_revertPiecePrefab);
			}
		}
		catch
		{
		}
		_revertHoeTable = null;
		if ((Object)(object)_revertPiecePrefab != (Object)null)
		{
			Object.Destroy((Object)(object)_revertPiecePrefab);
			_revertPiecePrefab = null;
		}
		if ((Object)(object)_revertIconSprite != (Object)null)
		{
			Object.Destroy((Object)(object)_revertIconSprite);
			_revertIconSprite = null;
		}
		if ((Object)(object)_revertIconTexture != (Object)null)
		{
			Object.Destroy((Object)(object)_revertIconTexture);
			_revertIconTexture = null;
		}
	}

	private void PatchRampPlacement()
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		try
		{
			if (_harmony == null)
			{
				_harmony = new Harmony("Flattenheim.Valheim");
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(Player), "TryPlacePiece", new Type[1] { typeof(Piece) }, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(FlattenheimPlugin), "RampTryPlacePiecePrefix", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not hook Player.TryPlacePiece for Ramp.");
				return;
			}
			HarmonyMethod val = new HarmonyMethod(methodInfo2);
			val.priority = 1000;
			_harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Flattenheim Ramp placement hook initialized.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not initialize Ramp placement: " + ex.Message));
		}
	}

	private static bool RampTryPlacePiecePrefix(Player __instance, Piece piece, ref bool __result)
	{
		FlattenheimPlugin instance = _instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
		{
			return true;
		}
		if (IsRampPiece(piece))
		{
			__result = instance.ApplyRampFromPlayerToCursor(__instance);
			return false;
		}
		if (IsRevertPiece(piece))
		{
			__result = instance.ApplyRevertOriginalTerrain(__instance);
			return false;
		}
		return true;
	}

	private void EnsureRampPieceRegistered(Player player)
	{
		if ((Object)(object)ObjectDB.instance == (Object)null)
		{
			return;
		}
		GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hoe");
		if ((Object)(object)itemPrefab == (Object)null)
		{
			return;
		}
		ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
		if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null || (Object)(object)component.m_itemData.m_shared.m_buildPieces == (Object)null)
		{
			return;
		}
		PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces;
		if ((Object)(object)_rampPiecePrefab == (Object)null)
		{
			GameObject val = FindHoeLevelGroundSource(buildPieces);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			_rampPiecePrefab = CreateRampPiecePrefab(val);
			if ((Object)(object)_rampPiecePrefab == (Object)null)
			{
				return;
			}
		}
		if (!buildPieces.m_pieces.Contains(_rampPiecePrefab))
		{
			int num = buildPieces.m_pieces.IndexOf(FindHoeLevelGroundSource(buildPieces));
			if (num >= 0 && num + 1 <= buildPieces.m_pieces.Count)
			{
				buildPieces.m_pieces.Insert(num + 1, _rampPiecePrefab);
			}
			else
			{
				buildPieces.m_pieces.Add(_rampPiecePrefab);
			}
			try
			{
				if ((Object)(object)player != (Object)null && _updateAvailablePiecesMethod != null)
				{
					_updateAvailablePiecesMethod.Invoke(player, null);
				}
			}
			catch
			{
			}
		}
		_rampHoeTable = buildPieces;
		if (!EnsureRevertPieceInTable(buildPieces))
		{
			return;
		}
		try
		{
			if ((Object)(object)player != (Object)null && _updateAvailablePiecesMethod != null)
			{
				_updateAvailablePiecesMethod.Invoke(player, null);
			}
		}
		catch
		{
		}
	}

	private void RemoveRampPiece()
	{
		try
		{
			if ((Object)(object)_rampHoeTable != (Object)null && (Object)(object)_rampPiecePrefab != (Object)null)
			{
				_rampHoeTable.m_pieces.Remove(_rampPiecePrefab);
			}
		}
		catch
		{
		}
		_rampHoeTable = null;
		if ((Object)(object)_rampPiecePrefab != (Object)null)
		{
			Object.Destroy((Object)(object)_rampPiecePrefab);
			_rampPiecePrefab = null;
		}
		if ((Object)(object)_rampGhostMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)_rampGhostMaterial);
			_rampGhostMaterial = null;
		}
		if ((Object)(object)_rampIconSprite != (Object)null)
		{
			Object.Destroy((Object)(object)_rampIconSprite);
			_rampIconSprite = null;
		}
		if ((Object)(object)_rampIconTexture != (Object)null)
		{
			Object.Destroy((Object)(object)_rampIconTexture);
			_rampIconTexture = null;
		}
	}

	private static GameObject FindHoeLevelGroundSource(PieceTable table)
	{
		if ((Object)(object)table == (Object)null || table.m_pieces == null)
		{
			return null;
		}
		GameObject val = null;
		for (int i = 0; i < table.m_pieces.Count; i++)
		{
			GameObject val2 = table.m_pieces[i];
			if (!((Object)(object)val2 == (Object)null))
			{
				TerrainOp component = val2.GetComponent<TerrainOp>();
				Piece component2 = val2.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null && (Object)(object)val == (Object)null)
				{
					val = val2;
				}
				string text = ((Object)val2).name ?? "";
				string text2 = (((Object)(object)component2 != (Object)null) ? (component2.m_name ?? "") : "");
				if (text.IndexOf("mud_road", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("level", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return val2;
				}
			}
		}
		return val;
	}

	private GameObject CreateRampPiecePrefab(GameObject source)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		//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)
		Piece val = (((Object)(object)source != (Object)null) ? source.GetComponent<Piece>() : null);
		GameObject val2 = new GameObject("Flattenheim_Ramp");
		val2.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)val2);
		Piece val3 = val2.AddComponent<Piece>();
		val3.m_name = "Ramp";
		val3.m_description = "Creates a terrain ramp from your feet to the cursor.";
		val3.m_enabled = true;
		val3.m_canBeRemoved = false;
		if ((Object)(object)val != (Object)null)
		{
			try
			{
				val3.m_category = val.m_category;
			}
			catch
			{
			}
		}
		if ((Object)(object)_rampIconSprite == (Object)null)
		{
			_rampIconSprite = CreateRampIcon();
		}
		if ((Object)(object)_rampIconSprite != (Object)null)
		{
			val3.m_icon = _rampIconSprite;
		}
		CreateRampGhostVisual(val2);
		return val2;
	}

	private void CreateRampGhostVisual(GameObject root)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		if (!((Object)(object)root == (Object)null))
		{
			GameObject val = new GameObject("_GhostOnly");
			val.transform.SetParent(root.transform, false);
		}
	}

	private Sprite CreateRampIcon()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		_rampIconTexture = new Texture2D(64, 64, (TextureFormat)4, false);
		((Object)_rampIconTexture).name = "Flattenheim_Ramp_Icon";
		((Texture)_rampIconTexture).filterMode = (FilterMode)0;
		Color val = default(Color);
		((Color)(ref val))..ctor(0f, 0f, 0f, 0f);
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(0.44f, 0.28f, 0.12f, 1f);
		Color val3 = default(Color);
		((Color)(ref val3))..ctor(0.65f, 0.44f, 0.2f, 1f);
		Color val4 = default(Color);
		((Color)(ref val4))..ctor(0.18f, 0.1f, 0.04f, 1f);
		Color[] array = (Color[])(object)new Color[4096];
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = val;
		}
		for (int j = 7; j <= 56; j++)
		{
			float num = (float)(j - 7) / 49f;
			int num2 = Mathf.RoundToInt(Mathf.Lerp(8f, 52f, num));
			for (int k = 8; k <= num2; k++)
			{
				bool flag = k == 8 || k >= num2 - 1 || j == 7 || j == 56;
				Color val5 = (flag ? val4 : val2);
				if (!flag && (j * 17 + k * 31) % 23 < 3)
				{
					val5 = val3;
				}
				array[k * 64 + j] = val5;
			}
		}
		_rampIconTexture.SetPixels(array);
		_rampIconTexture.Apply(false, false);
		Sprite val6 = Sprite.Create(_rampIconTexture, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f);
		((Object)val6).name = "Flattenheim_Ramp_Icon";
		return val6;
	}

	private static bool IsRampPiece(Piece piece)
	{
		FlattenheimPlugin instance = _instance;
		if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).gameObject == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)instance._rampPiecePrefab == (Object)null)
		{
			return false;
		}
		Piece component = instance._rampPiecePrefab.GetComponent<Piece>();
		if ((Object)(object)piece == (Object)(object)component)
		{
			return true;
		}
		string a = ((Object)((Component)piece).gameObject).name ?? "";
		if (!string.Equals(a, "Flattenheim_Ramp", StringComparison.Ordinal))
		{
			return string.Equals(a, "Flattenheim_Ramp(Clone)", StringComparison.Ordinal);
		}
		return true;
	}

	private bool ApplyRampFromPlayerToCursor(Player player)
	{
		//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_0040: 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_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			return false;
		}
		UpdateRampTrajectoryPreview(player);
		if (!_rampTrajectoryValid)
		{
			((Character)player).Message((MessageType)2, "Ramp: no valid trajectory.", 0, (Sprite)null, false);
			return false;
		}
		Vector3 rampTrajectoryStart = _rampTrajectoryStart;
		Vector3 rampTrajectoryEnd = _rampTrajectoryEnd;
		float num = rampTrajectoryEnd.x - rampTrajectoryStart.x;
		float num2 = rampTrajectoryEnd.z - rampTrajectoryStart.z;
		float num3 = Mathf.Sqrt(num * num + num2 * num2);
		if (num3 < 0.5f)
		{
			((Character)player).Message((MessageType)2, "Ramp: aim farther away.", 0, (Sprite)null, false);
			return false;
		}
		float num4 = Mathf.Clamp((_rampThickness != null) ? _rampThickness.Value : 4f, 1f, 20f);
		float halfWidth = num4 * 0.5f;
		float smoothnessPercent = Mathf.Clamp((_hardnessSmoothness != null) ? _hardnessSmoothness.Value : 35f, 0f, 100f);
		GroundTextureMode texture = ((_groundTexture != null) ? _groundTexture.Value : GroundTextureMode.Dirt);
		bool flag = ApplyRampTerrain(rampTrajectoryStart, rampTrajectoryEnd, halfWidth, smoothnessPercent, texture);
		if (flag)
		{
			((Character)player).Message((MessageType)2, "Ramp: " + num3.ToString("0.0") + " m | rise " + (rampTrajectoryEnd.y - rampTrajectoryStart.y).ToString("+0.0;-0.0;0.0") + " m", 0, (Sprite)null, false);
		}
		return flag;
	}

	private bool ApplyRampTerrain(Vector3 start, Vector3 end, float halfWidth, float smoothnessPercent, GroundTextureMode texture)
	{
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_03af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0424: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_036c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Unknown result type (might be due to invalid IL or missing references)
		CacheTerrainMembers();
		float num = end.x - start.x;
		float num2 = end.z - start.z;
		float num3 = num * num + num2 * num2;
		if (num3 < 0.01f)
		{
			return false;
		}
		float num4 = Mathf.Sqrt(num3);
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor((start.x + end.x) * 0.5f, (start.y + end.y) * 0.5f, (start.z + end.z) * 0.5f);
		float num5 = num4 * 0.5f + halfWidth + 4f;
		HashSet<TerrainComp> hashSet = CollectTerrainCompilers(val, num5);
		if (hashSet.Count == 0)
		{
			return false;
		}
		float num6 = Mathf.Clamp01(smoothnessPercent / 100f);
		float num7 = halfWidth * 0.5f * num6;
		bool flag = false;
		foreach (TerrainComp item in hashSet)
		{
			if ((Object)(object)item == (Object)null)
			{
				continue;
			}
			ClaimOwnership(item);
			Heightmap field = GetField<Heightmap>(_fieldHmap, item);
			float[] field2 = GetField<float[]>(_fieldLevelDelta, item);
			float[] field3 = GetField<float[]>(_fieldSmoothDelta, item);
			bool[] field4 = GetField<bool[]>(_fieldModifiedHeight, item);
			Color[] field5 = GetField<Color[]>(_fieldPaintMask, item);
			bool[] field6 = GetField<bool[]>(_fieldModifiedPaint, item);
			if ((Object)(object)field == (Object)null || field2 == null || field3 == null || field4 == null)
			{
				continue;
			}
			int width = field.m_width;
			float scale = field.m_scale;
			int num8 = width / 2;
			Vector3 position = ((Component)field).transform.position;
			bool flag2 = false;
			for (int i = 0; i <= width; i++)
			{
				for (int j = 0; j <= width; j++)
				{
					float num9 = position.x + (float)(j - num8) * scale;
					float num10 = position.z + (float)(i - num8) * scale;
					float num11 = num9 - start.x;
					float num12 = num10 - start.z;
					float num13 = num / num4;
					float num14 = num2 / num4;
					float num15 = num11 * num13 + num12 * num14;
					if (num15 < 0f || num15 > num4)
					{
						continue;
					}
					float num16 = 0f - num14;
					float num17 = num13;
					float num18 = num11 * num16 + num12 * num17;
					float num19 = Mathf.Abs(num18);
					if (num19 > halfWidth + scale * 0.25f)
					{
						continue;
					}
					float num20 = Mathf.Clamp01(num15 / num4);
					int num21 = i * (width + 1) + j;
					if (num21 < 0 || num21 >= field2.Length || num21 >= field3.Length || num21 >= field4.Length)
					{
						continue;
					}
					float num22 = 1f;
					if (num7 > 0.001f)
					{
						float num23 = halfWidth - num19;
						num22 = Mathf.Clamp01(num23 / num7);
						num22 = num22 * num22 * (3f - 2f * num22);
					}
					float num24 = Mathf.Lerp(start.y, end.y, num20);
					float height = field.GetHeight(j, i);
					float num25 = Mathf.Lerp(height, num24, num22);
					float num26 = num25 - height + field3[num21];
					field3[num21] = 0f;
					field2[num21] += num26;
					field2[num21] = Mathf.Clamp(field2[num21], -8f, 8f);
					field4[num21] = true;
					if (texture == GroundTextureMode.Dirt && field5 != null && field6 != null && j < width && i < width)
					{
						int num27 = i * width + j;
						if (num27 >= 0 && num27 < field5.Length && num27 < field6.Length)
						{
							Color paintMaskDirt = Heightmap.m_paintMaskDirt;
							try
							{
								paintMaskDirt.a = field.GetPaintMask(j, i).a;
							}
							catch
							{
								paintMaskDirt.a = field5[num27].a;
							}
							field5[num27] = paintMaskDirt;
							field6[num27] = true;
						}
					}
					flag2 = true;
					flag = true;
				}
			}
			if (flag2)
			{
				SaveTerrainComp(item);
				field.Poke(0, false);
			}
		}
		if (flag && (Object)(object)ClutterSystem.instance != (Object)null)
		{
			ClutterSystem.instance.ResetGrass(val, num5);
		}
		return flag;
	}

	private void PatchTerrainToolRadius()
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		//IL_00dc: Expected O, but got Unknown
		try
		{
			if (_harmony == null)
			{
				_harmony = new Harmony("Flattenheim.Valheim");
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			_placementGhostField = typeof(Player).GetField("m_placementGhost", bindingAttr);
			_getRightItemMethod = typeof(Humanoid).GetMethod("GetRightItem", bindingAttr);
			MethodInfo methodInfo = AccessTools.Method(typeof(Player), "TryPlacePiece", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(FlattenheimPlugin), "PlayerTryPlacePiecePrefix", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(FlattenheimPlugin), "PlayerTryPlacePieceFinalizer", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || methodInfo3 == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not locate Player.TryPlacePiece for Hoe/Cultivator radius support.");
				return;
			}
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Flattenheim Hoe/Cultivator radius hooked to Player.TryPlacePiece.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not initialize Hoe/Cultivator radius support: " + ex.Message));
		}
	}

	private static void PlayerTryPlacePiecePrefix(Player __instance, Piece piece)
	{
		FlattenheimPlugin instance = _instance;
		RestoreActivePlacementRadiusScope();
		if ((Object)(object)instance == (Object)null || instance._enabled == null || !instance._enabled.Value || instance._toolRadiusEnabled == null || !instance._toolRadiusEnabled.Value || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null || !_radiusToolActive || _radiusToolKind == TerrainToolKind.None)
		{
			return;
		}
		float targetRadius = Mathf.Clamp(_radiusTarget, 2f, 20f);
		PlacementRadiusScope placementRadiusScope = new PlacementRadiusScope();
		try
		{
			ScaleTerrainComponentsForPlacement(((Component)piece).gameObject, targetRadius, placementRadiusScope);
			Piece val = null;
			try
			{
				val = __instance.GetSelectedPiece();
			}
			catch
			{
			}
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)piece)
			{
				ScaleTerrainComponentsForPlacement(((Component)val).gameObject, targetRadius, placementRadiusScope);
			}
			if (placementRadiusScope.TerrainOpCount == 0 && placementRadiusScope.TerrainModifierCount == 0)
			{
				placementRadiusScope.Restore();
				return;
			}
			_activePlacementRadiusScope = placementRadiusScope;
			((Character)__instance).Message((MessageType)1, "Placement radius: " + targetRadius.ToString("0") + " m | ops: " + placementRadiusScope.TerrainOpCount + " | mods: " + placementRadiusScope.TerrainModifierCount, 0, (Sprite)null, false);
		}
		catch
		{
			placementRadiusScope.Restore();
			_activePlacementRadiusScope = null;
			throw;
		}
	}

	private static Exception PlayerTryPlacePieceFinalizer(Exception __exception)
	{
		RestoreActivePlacementRadiusScope();
		return __exception;
	}

	private static void RestoreActivePlacementRadiusScope()
	{
		if (_activePlacementRadiusScope == null)
		{
			return;
		}
		try
		{
			_activePlacementRadiusScope.Restore();
		}
		finally
		{
			_activePlacementRadiusScope = null;
		}
	}

	private static void ScaleTerrainComponentsForPlacement(GameObject root, float targetRadius, PlacementRadiusScope scope)
	{
		if ((Object)(object)root == (Object)null || scope == null)
		{
			return;
		}
		TerrainOp[] componentsInChildren = root.GetComponentsInChildren<TerrainOp>(true);
		foreach (TerrainOp val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && val.m_settings != null)
			{
				int instanceID = ((Object)val).GetInstanceID();
				if (scope.SeenObjects.Add(instanceID) && TryGetMaximumRadius(val, out var maximumRadius) && !(maximumRadius <= 0.001f))
				{
					scope.TerrainOps.Add(new TerrainOpRadiusSnapshot(val));
					float scale = targetRadius / maximumRadius;
					ScaleTerrainOpSettings(val, scale);
				}
			}
		}
		TerrainModifier[] componentsInChildren2 = root.GetComponentsInChildren<TerrainModifier>(true);
		foreach (TerrainModifier val2 in componentsInChildren2)
		{
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			int instanceID2 = ((Object)val2).GetInstanceID();
			if (scope.SeenObjects.Add(instanceID2))
			{
				float terrainModifierMaximumRadius = GetTerrainModifierMaximumRadius(val2);
				if (!(terrainModifierMaximumRadius <= 0.001f))
				{
					scope.TerrainModifiers.Add(new TerrainModifierRadiusSnapshot(val2));
					float scale2 = targetRadius / terrainModifierMaximumRadius;
					ScaleTerrainModifier(val2, scale2);
				}
			}
		}
	}

	private static void ScaleTerrainOpSettings(TerrainOp terrainOp, float scale)
	{
		if (!((Object)(object)terrainOp == (Object)null) && terrainOp.m_settings != null)
		{
			scale = Mathf.Max(0.01f, scale);
			if (terrainOp.m_settings.m_level)
			{
				terrainOp.m_settings.m_levelRadius = Mathf.Clamp(terrainOp.m_settings.m_levelRadius * scale, 0.5f, 20f);
			}
			if (terrainOp.m_settings.m_raise)
			{
				terrainOp.m_settings.m_raiseRadius = Mathf.Clamp(terrainOp.m_settings.m_raiseRadius * scale, 0.5f, 20f);
			}
			if (terrainOp.m_settings.m_smooth)
			{
				terrainOp.m_settings.m_smoothRadius = Mathf.Clamp(terrainOp.m_settings.m_smoothRadius * scale, 0.5f, 20f);
			}
			if (terrainOp.m_settings.m_paintCleared)
			{
				terrainOp.m_settings.m_paintRadius = Mathf.Clamp(terrainOp.m_settings.m_paintRadius * scale, 0.5f, 20f);
			}
		}
	}

	private static float GetTerrainModifierMaximumRadius(TerrainModifier modifier)
	{
		if ((Object)(object)modifier == (Object)null)
		{
			return 0f;
		}
		float num = 0f;
		if (modifier.m_level)
		{
			num = Mathf.Max(num, modifier.m_levelRadius);
		}
		if (modifier.m_smooth)
		{
			num = Mathf.Max(num, modifier.m_smoothRadius);
		}
		return num;
	}

	private static void ScaleTerrainModifier(TerrainModifier modifier, float scale)
	{
		if (!((Object)(object)modifier == (Object)null))
		{
			scale = Mathf.Max(0.01f, scale);
			if (modifier.m_level)
			{
				modifier.m_levelRadius = Mathf.Clamp(modifier.m_levelRadius * scale, 0.5f, 20f);
			}
			if (modifier.m_smooth)
			{
				modifier.m_smoothRadius = Mathf.Clamp(modifier.m_smoothRadius * scale, 0.5f, 20f);
			}
		}
	}

	private void HandleTerrainToolRadius(Player player)
	{
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		if (_toolRadiusEnabled == null || !_toolRadiusEnabled.Value || (Object)(object)player == (Object)null || !((Character)player).InPlaceMode())
		{
			ResetRadiusToolState(player);
			return;
		}
		Piece val = null;
		try
		{
			val = player.GetSelectedPiece();
		}
		catch
		{
		}
		if (IsRampPiece(val) || IsRevertPiece(val))
		{
			ResetRadiusToolState(player);
			return;
		}
		TerrainOp val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TerrainOp>() : null);
		if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
		{
			ResetRadiusToolState(player);
			return;
		}
		ItemData equippedTerrainToolItem = GetEquippedTerrainToolItem(player);
		TerrainToolKind terrainToolKind = GetTerrainToolKind(equippedTerrainToolItem);
		if (terrainToolKind == TerrainToolKind.None)
		{
			ResetRadiusToolState(player);
			return;
		}
		if (!TryGetMaximumRadius(val2, out var maximumRadius))
		{
			ResetRadiusToolState(player);
			return;
		}
		int instanceID = ((Object)val).GetInstanceID();
		if (!_radiusToolActive || _radiusSelectedPieceId != instanceID || _radiusToolKind != terrainToolKind || Mathf.Abs(_radiusOriginal - maximumRadius) > 0.001f)
		{
			_radiusToolActive = true;
			_radiusSelectedPieceId = instanceID;
			_radiusToolKind = terrainToolKind;
			_radiusOriginal = maximumRadius;
		}
		bool flag = _radiusIncreaseKey != null && ShortcutIsDown(_radiusIncreaseKey.Value);
		bool flag2 = _radiusDecreaseKey != null && ShortcutIsDown(_radiusDecreaseKey.Value);
		if (flag != flag2)
		{
			float configuredToolRadius = GetConfiguredToolRadius(terrainToolKind);
			float radius = Mathf.Clamp(configuredToolRadius + (flag ? 1f : (-1f)), 2f, 20f);
			SetConfiguredToolRadius(terrainToolKind, radius);
			((Character)player).Message((MessageType)2, ((terrainToolKind == TerrainToolKind.Hoe) ? "Hoe Radius: " : "Cultivator Radius: ") + radius.ToString("0") + " m", 0, (Sprite)null, false);
		}
		_radiusTarget = GetConfiguredToolRadius(terrainToolKind);
		_radiusDelta = _radiusTarget - _radiusOriginal;
		float num = ((_radiusOriginal > 0.001f) ? (_radiusTarget / _radiusOriginal) : 1f);
		_radiusGhostScale = new Vector3(num, num, num);
	}

	private static void ResetRadiusToolState(Player player)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		_radiusToolActive = false;
		_radiusOriginal = 0f;
		_radiusTarget = 0f;
		_radiusDelta = 0f;
		_radiusGhostScale = Vector3.one;
		_radiusSelectedPieceId = 0;
		_radiusToolKind = TerrainToolKind.None;
	}

	private void SetConfiguredToolRadius(TerrainToolKind kind, float radius)
	{
		radius = Mathf.Clamp(radius, 2f, 20f);
		switch (kind)
		{
		case TerrainToolKind.Hoe:
			if (_hoeRadius != null)
			{
				_hoeRadius.Value = radius;
			}
			break;
		case TerrainToolKind.Cultivator:
			if (_cultivatorRadius != null)
			{
				_cultivatorRadius.Value = radius;
			}
			break;
		}
	}

	private float GetConfiguredToolRadius(TerrainToolKind kind)
	{
		return kind switch
		{
			TerrainToolKind.Hoe => Mathf.Clamp((_hoeRadius != null) ? _hoeRadius.Value : 2f, 2f, 20f), 
			TerrainToolKind.Cultivator => Mathf.Clamp((_cultivatorRadius != null) ? _cultivatorRadius.Value : 2f, 2f, 20f), 
			_ => 2f, 
		};
	}

	private static ItemData GetEquippedTerrainToolItem(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		try
		{
			if (_getRightItemMethod != null)
			{
				object? obj = _getRightItemMethod.Invoke(player, null);
				ItemData val = (ItemData)((obj is ItemData) ? obj : null);
				if (val != null)
				{
					return val;
				}
			}
		}
		catch
		{
		}
		try
		{
			return ((Humanoid)player).GetCurrentWeapon();
		}
		catch
		{
			return null;
		}
	}

	private static TerrainToolKind GetTerrainToolKind(ItemData item)
	{
		if (item == null || item.m_shared == null)
		{
			return TerrainToolKind.None;
		}
		string value = "";
		try
		{
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				value = ((Object)item.m_dropPrefab).name ?? "";
			}
		}
		catch
		{
		}
		string value2 = item.m_shared.m_name ?? "";
		string value3 = "";
		try
		{
			if ((Object)(object)item.m_shared.m_buildPieces != (Object)null)
			{
				value3 = ((Object)item.m_shared.m_buildPieces).name ?? "";
			}
		}
		catch
		{
		}
		if (ContainsIgnoreCase(value, "cultivator") || ContainsIgnoreCase(value2, "cultivator") || ContainsIgnoreCase(value3, "cultivator"))
		{
			return TerrainToolKind.Cultivator;
		}
		if (ContainsIgnoreCase(value, "hoe") || ContainsIgnoreCase(value2, "hoe") || ContainsIgnoreCase(value3, "hoe"))
		{
			return TerrainToolKind.Hoe;
		}
		return TerrainToolKind.None;
	}

	private static bool ContainsIgnoreCase(string value, string text)
	{
		if (!string.IsNullOrEmpty(value))
		{
			return value.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return false;
	}

	private static bool TryGetMaximumRadius(TerrainOp terrainOp, out float maximumRadius)
	{
		maximumRadius = 0f;
		if ((Object)(object)terrainOp == (Object)null)
		{
			return false;
		}
		if (terrainOp.m_settings.m_level)
		{
			maximumRadius = Mathf.Max(maximumRadius, terrainOp.m_settings.m_levelRadius);
		}
		if (terrainOp.m_settings.m_raise)
		{
			maximumRadius = Mathf.Max(maximumRadius, terrainOp.m_settings.m_raiseRadius);
		}
		if (terrainOp.m_settings.m_smooth)
		{
			maximumRadius = Mathf.Max(maximumRadius, terrainOp.m_settings.m_smoothRadius);
		}
		if (terrainOp.m_settings.m_paintCleared)
		{
			maximumRadius = Mathf.Max(maximumRadius, terrainOp.m_settings.m_paintRadius);
		}
		return maximumRadius > 0.001f;
	}

	private static void ApplyRadiusDeltaToTerrainOp(TerrainOp terrainOp, float delta)
	{
		if (!((Object)(object)terrainOp == (Object)null))
		{
			if (terrainOp.m_settings.m_level)
			{
				terrainOp.m_settings.m_levelRadius = ModifyTerrainRadius(terrainOp.m_settings.m_levelRadius, delta);
			}
			if (terrainOp.m_settings.m_raise)
			{
				terrainOp.m_settings.m_raiseRadius = ModifyTerrainRadius(terrainOp.m_settings.m_raiseRadius, delta);
			}
			if (terrainOp.m_settings.m_smooth)
			{
				terrainOp.m_settings.m_smoothRadius = ModifyTerrainRadius(terrainOp.m_settings.m_smoothRadius, delta);
			}
			if (terrainOp.m_settings.m_paintCleared)
			{
				terrainOp.m_settings.m_paintRadius = ModifyTerrainRadius(terrainOp.m_settings.m_paintRadius, delta);
			}
		}
	}

	private static float ModifyTerrainRadius(float radius, float delta)
	{
		return Mathf.Clamp(radius + delta, 0.5f, 20f);
	}

	private static void RefreshRadiusGhostScale(Player player)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		if (_radiusToolActive && !((Object)(object)player == (Object)null))
		{
			SetPlacementGhostScale(player, _radiusGhostScale);
		}
	}

	private static void SetPlacementGhostScale(Player player, Vector3 scale)
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null || _placementGhostField == null)
		{
			return;
		}
		try
		{
			object? value = _placementGhostField.GetValue(player);
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform val2 = val.transform.Find("_GhostOnly");
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = val.transform;
			}
			Component[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Component>(true);
			foreach (Component val3 in componentsInChildren)
			{
				if (!((Object)(object)val3 == (Object)null) && string.Equals(((object)val3).GetType().Name, "ParticleSystem", StringComparison.Ordinal))
				{
					val3.transform.localScale = scale;
				}
			}
		}
		catch
		{
		}
	}

	private static bool ShortcutIsDown(KeyboardShortcut shortcut)
	{
		//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_000b: 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_002a: 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)
		KeyCode mainKey = ((KeyboardShortcut)(ref shortcut)).MainKey;
		if ((int)mainKey == 0 || !Input.GetKeyDown(mainKey))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
		{
			if (!Input.GetKey(modifier))
			{
				return false;
			}
		}
		return true;
	}

	private void PatchMovementControls()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Expected O, but got Unknown
		try
		{
			_harmony = new Harmony("Flattenheim.Valheim");
			MethodInfo methodInfo = AccessTools.Method(typeof(FlattenheimPlugin), "PlayerSetControlsPrefix", (Type[])null, (Type[])null);
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			int num = 0;
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (methodInfo2 == null || methodInfo2.Name != "SetControls")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo2.GetParameters();
				bool flag = false;
				for (int j = 0; j < parameters.Length; j++)
				{
					if (parameters[j].Name == "movedir" && parameters[j].ParameterType == typeof(Vector3))
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					try
					{
						_harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
					}
					catch
					{
					}
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Flattenheim grid movement hooked to " + num + " Player.SetControls method(s)."));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not initialize grid movement: " + ex.Message));
		}
	}

	private static void PlayerSetControlsPrefix(Player __instance, ref Vector3 movedir)
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: 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_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: 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_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
		FlattenheimPlugin instance = _instance;
		if ((Object)(object)instance == (Object)null || instance._enabled == null || !instance._enabled.Value || instance._gridMovement == null || !instance._gridMovement.Value || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon();
		if (!IsPickaxe(currentWeapon))
		{
			return;
		}
		KeyboardShortcut shortcut = (KeyboardShortcut)((instance._flattenHold != null) ? instance._flattenHold.Value : new KeyboardShortcut((KeyCode)324, (KeyCode[])(object)new KeyCode[0]));
		if (!ShortcutIsHeld(shortcut))
		{
			return;
		}
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(movedir.x, movedir.z);
		float num = Mathf.Clamp01(((Vector2)(ref val)).magnitude);
		if (!(num < 0.001f))
		{
			Vector3 val2 = ((Character)__instance).GetLookDir();
			val2.y = 0f;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
			{
				val2 = ((Component)__instance).transform.forward;
				val2.y = 0f;
			}
			((Vector3)(ref val2)).Normalize();
			Vector3 val3 = Vector3.Cross(Vector3.up, val2);
			((Vector3)(ref val3)).Normalize();
			Vector3 val4 = val2 * movedir.z + val3 * movedir.x;
			val4.y = 0f;
			if (!(((Vector3)(ref val4)).sqrMagnitude < 0.001f))
			{
				((Vector3)(ref val4)).Normalize();
				float num2 = Mathf.Atan2(val4.x, val4.z) * 57.29578f;
				float num3 = Mathf.Round(num2 / 45f) * 45f;
				float num4 = num3 * ((float)Math.PI / 180f);
				Vector3 val5 = new Vector3(Mathf.Sin(num4), 0f, Mathf.Cos(num4)) * num;
				movedir.x = Vector3.Dot(val5, val3);
				movedir.z = Vector3.Dot(val5, val2);
				movedir.y = 0f;
			}
		}
	}

	private static void CacheTerrainMembers()
	{
		if (!(_fieldHmap != null) || !(_fieldLevelDelta != null) || !(_saveMethod != null))
		{
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			_fieldHmap = typeof(TerrainComp).GetField("m_hmap", bindingAttr);
			_fieldSize = typeof(TerrainComp).GetField("m_size", bindingAttr);
			_fieldLevelDelta = typeof(TerrainComp).GetField("m_levelDelta", bindingAttr);
			_fieldSmoothDelta = typeof(TerrainComp).GetField("m_smoothDelta", bindingAttr);
			_fieldModifiedHeight = typeof(TerrainComp).GetField("m_modifiedHeight", bindingAttr);
			_fieldPaintMask = typeof(TerrainComp).GetField("m_paintMask", bindingAttr);
			_fieldModifiedPaint = typeof(TerrainComp).GetField("m_modifiedPaint", bindingAttr);
			_fieldNview = typeof(TerrainComp).GetField("m_nview", bindingAttr);
			_saveMethod = typeof(TerrainComp).GetMethod("Save", bindingAttr, null, new Type[1] { typeof(bool) }, null);
		}
	}

	private void LogBackendError(string message)
	{
		if (!_loggedBackendError)
		{
			_loggedBackendError = true;
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Flattenheim terrain backend: " + message));
		}
	}

	private void CreatePreviewObjects()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Expected O, but got Unknown
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			_previewRoot = new GameObject("FlattenheimPreview");
			((Object)_previewRoot).hideFlags = (HideFlags)61;
			_previewLine = _previewRoot.AddComponent<LineRenderer>();
			_previewLine.useWorldSpace = true;
			_previewLine.loop = false;
			_previewLine.startWidth = 0.06f;
			_previewLine.endWidth = 0.06f;
			((Renderer)_previewLine).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_previewLine).receiveShadows = false;
			_previewLine.numCornerVertices = 2;
			_previewLine.numCapVertices = 0;
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Unlit/Color");
			}
			_previewMaterial = new Material(val);
			((Object)_previewMaterial).hideFlags = (HideFlags)61;
			_previewMaterial.color = new Color(1f, 0.95f, 0.6f, 0.95f);
			((Renderer)_previewLine).material = _previewMaterial;
			_previewLine.startColor = _previewMaterial.color;
			_previewLine.endColor = _previewMaterial.color;
			SetPreviewVisible(visible: false);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create preview objects: " + ex.Message));
		}
	}

	private void DestroyPreviewObjects()
	{
		if ((Object)(object)_previewMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)_previewMaterial);
			_previewMaterial = null;
		}
		if ((Object)(object)_previewRoot != (Object)null)
		{
			Object.Destroy((Object)(object)_previewRoot);
			_previewRoot = null;
			_previewLine = null;
		}
	}

	private void UpdatePreview(Vector3 snappedCenter, float size, FlattenShape shape)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_previewLine == (Object)null)
		{
			return;
		}
		float groundHeight = ZoneSystem.instance.GetGroundHeight(snappedCenter);
		float num = groundHeight + 0.08f;
		if (shape == FlattenShape.Square)
		{
			float num2 = size * 0.5f;
			_previewLine.positionCount = 5;
			_previewLine.SetPosition(0, new Vector3(snappedCenter.x - num2, num, snappedCenter.z - num2));
			_previewLine.SetPosition(1, new Vector3(snappedCenter.x - num2, num, snappedCenter.z + num2));
			_previewLine.SetPosition(2, new Vector3(snappedCenter.x + num2, num, snappedCenter.z + num2));
			_previewLine.SetPosition(3, new Vector3(snappedCenter.x + num2, num, snappedCenter.z - num2));
			_previewLine.SetPosition(4, new Vector3(snappedCenter.x - num2, num, snappedCenter.z - num2));
		}
		else
		{
			float num3 = size * 0.5f;
			_previewLine.positionCount = 49;
			for (int i = 0; i <= 48; i++)
			{
				float num4 = (float)i / 48f * (float)Math.PI * 2f;
				_previewLine.SetPosition(i, new Vector3(snappedCenter.x + Mathf.Cos(num4) * num3, num, snappedCenter.z + Mathf.Sin(num4) * num3));
			}
		}
		SetPreviewVisible(visible: true);
	}

	private void SetPreviewVisible(bool visible)
	{
		if ((Object)(object)_previewRoot != (Object)null && _previewRoot.activeSelf != visible)
		{
			_previewRoot.SetActive(visible);
		}
	}

	private static bool IsPickaxe(ItemData item)
	{
		//IL_0021: 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_001a: Invalid comparison between Unknown and I4
		if (item == null || item.m_shared == null)
		{
			return false;
		}
		try
		{
			return (int)item.m_shared.m_skillType == 12;
		}
		catch
		{
			try
			{
				return item.GetDamage().m_pickaxe > 0f;
			}
			catch
			{
				return false;
			}
		}
	}

	private static bool ShortcutIsHeld(KeyboardShortcut shortcut)
	{
		//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_0013: Invalid comparison between Unknown and I4
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Invalid comparison between Unknown and I4
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Invalid comparison between Unknown and I4
		//IL_0040: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		KeyCode mainKey = ((KeyboardShortcut)(ref shortcut)).MainKey;
		if ((int)mainKey == 0)
		{
			return false;
		}
		if (!(((int)mainKey == 324) ? Input.GetMouseButton(1) : (((int)mainKey == 323) ? Input.GetMouseButton(0) : (((int)mainKey != 325) ? Input.GetKey(mainKey) : Input.GetMouseButton(2)))))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
		{
			if (!Input.GetKey(modifier))
			{
				return false;
			}
		}
		return true;
	}

	private static Vector3 GetSnappedCenter(Vector3 playerPosition)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Round(playerPosition.x / 1f) * 1f;
		float num2 = Mathf.Round(playerPosition.z / 1f) * 1f;
		return new Vector3(num, playerPosition.y, num2);
	}

	private static float HorizontalDistance(Vector3 a, Vector3 b)
	{
		float num = a.x - b.x;
		float num2 = a.z - b.z;
		return Mathf.Sqrt(num * num + num2 * num2);
	}
}