Decompiled source of TerrainShaperPlus v1.0.15

plugins\TerrainShaperPlus.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TerrainShaperPlus.Farm;
using TerrainShaperPlus.Localization;
using TerrainShaperPlus.Patches;
using TerrainShaperPlus.Terrain;
using TerrainShaperPlus.Tools;
using TerrainShaperPlus.UI;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("PONEIS")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Terrain Shaper Plus for Valheim 1.0 — craftable workbench tool combining ValheimTooler + TerrainTools features")]
[assembly: AssemblyFileVersion("1.0.15.0")]
[assembly: AssemblyInformationalVersion("1.0.15+23e5840dc7b00833bb4c5e233e059a8db4612a41")]
[assembly: AssemblyProduct("TerrainShaperPlus")]
[assembly: AssemblyTitle("TerrainShaperPlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.15.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TerrainShaperPlus
{
	internal static class ModConfig
	{
		internal static ConfigEntry<string> Language;

		internal static ConfigEntry<bool> HoverInfo;

		internal static ConfigEntry<bool> EnableRadiusModifier;

		internal static ConfigEntry<KeyCode> RadiusModKey;

		internal static ConfigEntry<float> RadiusScrollScale;

		internal static ConfigEntry<float> MaxRadius;

		internal static ConfigEntry<bool> EnableSharpnessModifier;

		internal static ConfigEntry<KeyCode> SharpnessModKey;

		internal static ConfigEntry<float> SharpnessScrollScale;

		internal static ConfigEntry<bool> EnableHeightModifier;

		internal static ConfigEntry<KeyCode> HeightModKey;

		internal static ConfigEntry<float> HeightScrollStep;

		internal static ConfigEntry<float> MinHeightMeters;

		internal static ConfigEntry<float> MaxHeightMeters;

		internal static ConfigEntry<KeyCode> PanelToggleKey;

		internal static ConfigEntry<KeyCode> PanelModifierKey;

		internal static ConfigEntry<bool> EnableTool;

		internal static ConfigEntry<int> MinWorkbenchLevel;

		internal static ConfigEntry<int> RecipeWood;

		internal static ConfigEntry<int> RecipeStone;

		internal static ConfigEntry<float> MaxDurability;

		internal static ConfigEntry<float> DurabilityPerLevel;

		internal static ConfigEntry<float> DurabilityDrain;

		internal static ConfigEntry<bool> EnableGridSnap;

		internal static ConfigEntry<bool> GridSnapAlways;

		internal static ConfigEntry<KeyCode> GridSnapHoldKey;

		internal static ConfigEntry<bool> GridFollowPieceRotation;

		internal static ConfigEntry<float> GridRotationSnapDegrees;

		internal static ConfigEntry<bool> RequireWorkbenchToPlace;

		internal static ConfigEntry<bool> StaminaDrainEnabled;

		internal static ConfigEntry<float> StaminaDrainPerUse;

		internal static ConfigEntry<bool> SoftSquareEdges;

		internal static ConfigEntry<bool> SoftSquareEdgesAlways;

		internal static ConfigEntry<float> SoftSquareBevel;

		internal static ConfigEntry<bool> ShowBrushOutline;

		internal static ConfigEntry<bool> ShowBrushGrid;

		internal static ConfigEntry<bool> FarmGridEnabled;

		internal static ConfigEntry<bool> FarmShowGrid;

		internal static ConfigEntry<bool> FarmBlockOverlap;

		internal static ConfigEntry<float> FarmPlantSpacing;

		internal static ConfigEntry<int> FarmGridSections;

		internal static ConfigEntry<KeyCode> FarmSizeModKey;

		internal static ConfigEntry<int> FarmSizeScrollStep;

		internal static ConfigEntry<float> FarmGridYOffset;

		internal static ConfigEntry<Color> FarmGridColor;

		internal static ConfigEntry<int> FarmGridFixedRotation;

		internal static ConfigEntry<string> FarmPlantObjectMasks;

		internal static ConfigEntry<string> FarmCustomPlants;

		internal static readonly Dictionary<string, ConfigEntry<bool>> ToolToggles = new Dictionary<string, ConfigEntry<bool>>();

		internal static void Bind(ConfigFile config)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Expected O, but got Unknown
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected O, but got Unknown
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Expected O, but got Unknown
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Expected O, but got Unknown
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Expected O, but got Unknown
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Expected O, but got Unknown
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Expected O, but got Unknown
			//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ad: Expected O, but got Unknown
			//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Expected O, but got Unknown
			//IL_051a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0524: Expected O, but got Unknown
			//IL_0552: Unknown result type (might be due to invalid IL or missing references)
			//IL_055c: Expected O, but got Unknown
			//IL_0580: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ce: Expected O, but got Unknown
			//IL_07f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fc: Expected O, but got Unknown
			//IL_0820: Unknown result type (might be due to invalid IL or missing references)
			//IL_082a: Expected O, but got Unknown
			//IL_0858: Unknown result type (might be due to invalid IL or missing references)
			//IL_0862: Expected O, but got Unknown
			//IL_0890: Unknown result type (might be due to invalid IL or missing references)
			//IL_089a: Expected O, but got Unknown
			//IL_08c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d2: Expected O, but got Unknown
			Language = config.Bind<string>("Localization", "Language", "Auto", "Language for TerrainShaperPlus UI strings. Auto follows the game language. Values: Auto, English, Portuguese. JSON files live in BepInEx/config/TerrainShaperPlus/lang/");
			HoverInfo = config.Bind<bool>("Global", "HoverInfo", true, "Show terrain height while placing square / precision tools.");
			EnableRadiusModifier = config.Bind<bool>("Radius", "Enabled", true, "Allow changing tool radius with modifier key + scroll wheel.");
			RadiusModKey = config.Bind<KeyCode>("Radius", "ModifierKey", (KeyCode)304, "Key held while scrolling to change radius. Default Shift (Ctrl is used with Q/E to rotate).");
			RadiusScrollScale = config.Bind<float>("Radius", "ScrollScale", 0.1f, new ConfigDescription("Scroll sensitivity for radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), Array.Empty<object>()));
			MaxRadius = config.Bind<float>("Radius", "MaxRadius", 10f, new ConfigDescription("Maximum tool radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 50f), Array.Empty<object>()));
			EnableSharpnessModifier = config.Bind<bool>("Sharpness", "Enabled", true, "Allow changing tool hardness with modifier key + scroll wheel.");
			SharpnessModKey = config.Bind<KeyCode>("Sharpness", "ModifierKey", (KeyCode)306, "Key held while scrolling to change hardness.");
			SharpnessScrollScale = config.Bind<float>("Sharpness", "ScrollScale", 0.1f, new ConfigDescription("Scroll sensitivity for hardness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), Array.Empty<object>()));
			EnableHeightModifier = config.Bind<bool>("Height", "Enabled", true, "Allow changing raise/lower height in meters (like ValheimTooler Terrain Shaper depth).");
			HeightModKey = config.Bind<KeyCode>("Height", "ModifierKey", (KeyCode)0, "Optional extra key for height scroll. Default None = scroll alone on raise/lower (recommended). Do NOT use LeftShift — it conflicts with vanilla level aim.");
			HeightScrollStep = config.Bind<float>("Height", "ScrollStep", 0.5f, new ConfigDescription("Height change per scroll tick (meters). Use 0.5 or 1 for 1m/5m style steps.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>()));
			MinHeightMeters = config.Bind<float>("Height", "MinMeters", 0.5f, new ConfigDescription("Minimum raise/lower height in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 20f), Array.Empty<object>()));
			MaxHeightMeters = config.Bind<float>("Height", "MaxMeters", 8f, new ConfigDescription("Maximum raise/lower height in meters (game clamps ±8).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), Array.Empty<object>()));
			PanelToggleKey = config.Bind<KeyCode>("Panel", "ToggleKey", (KeyCode)103, "Main key for the Height × Width panel (used with ModifierKey).");
			PanelModifierKey = config.Bind<KeyCode>("Panel", "ModifierKey", (KeyCode)306, "Held with ToggleKey to open/close the panel. Default LeftControl → Ctrl+G. Set to None for a single key.");
			EnableGridSnap = config.Bind<bool>("Grid", "Enabled", true, "Allow Width-based grid snap for square placement (free aim by default).");
			GridSnapHoldKey = config.Bind<KeyCode>("Grid", "HoldKey", (KeyCode)308, "Hold this key while placing to snap to the tile grid. Free placement when not held. Set to None to always snap when Enabled.");
			GridSnapAlways = config.Bind<bool>("Grid", "Always", false, "Also snap circular brushes (not only square tools), when snap is active.");
			GridFollowPieceRotation = config.Bind<bool>("Grid", "FollowPieceRotation", true, "Square brush, snap grid and preview follow piece yaw (vanilla Q/E). Makes rotated basements easy.");
			GridRotationSnapDegrees = config.Bind<float>("Grid", "RotationSnapDegrees", 15f, new ConfigDescription("While placing square tools, snap ghost yaw to this step (0 = free rotation). 15 or 45 works well with builds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 90f), Array.Empty<object>()));
			RequireWorkbenchToPlace = config.Bind<bool>("Placement", "RequireWorkbench", false, "If true, TSP pieces need a nearby Workbench (vanilla Hoe raise style). Default false = usable from boats / shores.");
			StaminaDrainEnabled = config.Bind<bool>("Stamina", "Enabled", true, "Drain stamina when placing with Terrain Shaper Plus.");
			StaminaDrainPerUse = config.Bind<float>("Stamina", "DrainPerUse", -1f, new ConfigDescription("Stamina cost per place. -1 = use the tool's built-in attack stamina (Hoe clone). 0 = free. Typical Hoe is ~5–10.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 50f), Array.Empty<object>()));
			SoftSquareEdges = config.Bind<bool>("Terrain", "SoftSquareEdges", true, "Bevel square raise/lower edges so platforms don't create black void cliffs (limbo).");
			SoftSquareEdgesAlways = config.Bind<bool>("Terrain", "SoftSquareEdgesAlways", false, "Apply soft square edges to all terrain mods, not only Terrain Shaper Plus.");
			SoftSquareBevel = config.Bind<float>("Terrain", "SoftSquareBevel", 0.35f, new ConfigDescription("Edge bevel size as a fraction of brush radius (higher = softer ramp, less void).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.15f, 0.6f), Array.Empty<object>()));
			ShowBrushOutline = config.Bind<bool>("Preview", "ShowBrushOutline", true, "While placing a Terrain Shaper piece, draw a wireframe of Width (and Height for raise/lower).");
			ShowBrushGrid = config.Bind<bool>("Preview", "ShowBrushGrid", true, "Draw a light grid inside the brush footprint outline.");
			FarmGridEnabled = config.Bind<bool>("Farm", "Enabled", true, "Cultivator farm grid (FarmGrid-style): snap plants to spacing + optional visual grid. Disable FarmGrid mod to avoid double-patching.");
			FarmShowGrid = config.Bind<bool>("Farm", "ShowGrid", true, "Draw the plant spacing grid while placing with the Cultivator.");
			FarmBlockOverlap = config.Bind<bool>("Farm", "BlockOverlap", true, "Prevent placing plants that would overlap another plant.");
			FarmPlantSpacing = config.Bind<float>("Farm", "PlantSpacing", 0.01f, new ConfigDescription("Extra space between plants on top of growth radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			FarmGridSections = config.Bind<int>("Farm", "GridSections", 2, new ConfigDescription("Grid lines on each side of the axis (visual size). Adjust in-game with SizeModKey + scroll.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
			FarmSizeModKey = config.Bind<KeyCode>("Farm", "SizeModKey", (KeyCode)306, "Hold this key and scroll while placing plants with the Cultivator to change farm grid size (GridSections).");
			FarmSizeScrollStep = config.Bind<int>("Farm", "SizeScrollStep", 1, new ConfigDescription("How many grid sections to add/remove per scroll tick.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 2), Array.Empty<object>()));
			FarmGridYOffset = config.Bind<float>("Farm", "GridYOffset", 0.2f, new ConfigDescription("Grid height above ground.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			FarmGridColor = config.Bind<Color>("Farm", "GridColor", new Color(0.8f, 0.8f, 0.8f, 0.2f), "Color of the farm grid lines.");
			FarmGridFixedRotation = config.Bind<int>("Farm", "FixedRotationDegrees", 0, "Fixed grid rotation in degrees (0 = auto from nearby plants). Use 360 for a fixed 0° axis.");
			FarmPlantObjectMasks = config.Bind<string>("Farm", "PlantObjectMasks", "piece,piece_nonsolid", "Layer masks for plant overlap detection. Planting Plus tip: piece,piece_nonsolid,item");
			FarmCustomPlants = config.Bind<string>("Farm", "CustomPlants", "", "Non-Plant objects treated as plants: Name:size, Name:size (see FarmGrid/Planting Plus docs).");
			FarmGridEnabled.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmShowGrid.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmPlantSpacing.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmGridSections.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmGridYOffset.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmGridColor.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmGridFixedRotation.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmPlantObjectMasks.SettingChanged += delegate
			{
				RefreshFarm();
			};
			FarmCustomPlants.SettingChanged += delegate
			{
				RefreshFarm();
			};
			RefreshFarm();
			RequireWorkbenchToPlace.SettingChanged += delegate
			{
				PieceFactory.ApplyPlacementRules();
			};
			EnableTool = config.Bind<bool>("Crafting", "EnableRecipe", true, "Allow crafting Terrain Shaper Plus at the Workbench.");
			MinWorkbenchLevel = config.Bind<int>("Crafting", "MinWorkbenchLevel", 1, new ConfigDescription("Minimum Workbench level required to craft Terrain Shaper Plus. Default 1 (basic Workbench).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
			RecipeWood = config.Bind<int>("Crafting", "WoodCost", 10, new ConfigDescription("Wood required.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			RecipeStone = config.Bind<int>("Crafting", "StoneCost", 10, new ConfigDescription("Stone required.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
			MaxDurability = config.Bind<float>("Durability", "MaxDurability", 800f, new ConfigDescription("Maximum durability of Terrain Shaper Plus (Hoe vanilla is ~200).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 10000f), Array.Empty<object>()));
			DurabilityPerLevel = config.Bind<float>("Durability", "PerQualityLevel", 100f, new ConfigDescription("Extra durability per quality level above 1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2000f), Array.Empty<object>()));
			DurabilityDrain = config.Bind<float>("Durability", "DrainPerUse", 0.5f, new ConfigDescription("Durability lost per use (1 = vanilla Hoe). Lower lasts longer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>()));
			foreach (string allId in ToolDefs.AllIds)
			{
				ToolToggles[allId] = config.Bind<bool>("Tools", allId, true, "Enable piece '" + allId + "' on the Terrain Shaper Plus.");
			}
			Language.SettingChanged += delegate
			{
				Loc.ApplyLanguagePreference();
			};
			static void RefreshFarm()
			{
				FarmGridPatch.ApplyConfig();
			}
		}

		internal static bool IsToolEnabled(string id)
		{
			if (ToolToggles.TryGetValue(id, out var value))
			{
				return value.Value;
			}
			return false;
		}

		internal static bool IsPanelToggleDown()
		{
			//IL_0005: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			if ((int)PanelToggleKey.Value == 0)
			{
				return false;
			}
			if (!Input.GetKeyDown(PanelToggleKey.Value))
			{
				return false;
			}
			return IsModifierHeld(PanelModifierKey.Value);
		}

		internal static bool IsGridSnapActive()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!EnableGridSnap.Value)
			{
				return false;
			}
			if ((int)GridSnapHoldKey.Value == 0)
			{
				return true;
			}
			return IsModifierHeld(GridSnapHoldKey.Value);
		}

		internal static string FormatPanelHotkey()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((int)PanelToggleKey.Value == 0)
			{
				return "—";
			}
			if ((int)PanelModifierKey.Value == 0)
			{
				return ShortKey(PanelToggleKey.Value);
			}
			return ShortKey(PanelModifierKey.Value) + "+" + ShortKey(PanelToggleKey.Value);
		}

		internal static string FormatGridSnapHotkey()
		{
			//IL_0017: 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)
			if (!EnableGridSnap.Value)
			{
				return "off";
			}
			if ((int)GridSnapHoldKey.Value == 0)
			{
				return "always";
			}
			return ShortKey(GridSnapHoldKey.Value);
		}

		internal static string FormatRadiusHotkey()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!EnableRadiusModifier.Value)
			{
				return "off";
			}
			return ShortKey(RadiusModKey.Value) + "+scroll";
		}

		internal static string FormatFarmSizeHotkey()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!FarmGridEnabled.Value)
			{
				return "off";
			}
			return ShortKey(FarmSizeModKey.Value) + "+scroll";
		}

		internal static bool IsKeyHeld(KeyCode mod)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return IsModifierHeld(mod);
		}

		private static bool IsModifierHeld(KeyCode mod)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Invalid comparison between Unknown and I4
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if ((int)mod == 0)
			{
				return true;
			}
			if ((int)mod == 306 || (int)mod == 305)
			{
				if (!Input.GetKey((KeyCode)306))
				{
					return Input.GetKey((KeyCode)305);
				}
				return true;
			}
			if ((int)mod == 308 || (int)mod == 307)
			{
				if (!Input.GetKey((KeyCode)308))
				{
					return Input.GetKey((KeyCode)307);
				}
				return true;
			}
			if ((int)mod == 304 || (int)mod == 303)
			{
				if (!Input.GetKey((KeyCode)304))
				{
					return Input.GetKey((KeyCode)303);
				}
				return true;
			}
			return Input.GetKey(mod);
		}

		private unsafe static string ShortKey(KeyCode key)
		{
			//IL_0000: 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_0024: Expected I4, but got Unknown
			switch (key - 303)
			{
			case 2:
			case 3:
				return "Ctrl";
			case 4:
			case 5:
				return "Alt";
			case 0:
			case 1:
				return "Shift";
			default:
				return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			}
		}
	}
	[BepInPlugin("poneis.valheim.TerrainShaperPlus", "TerrainShaperPlus", "1.0.15")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "poneis.valheim.TerrainShaperPlus";

		public const string PluginName = "TerrainShaperPlus";

		public const string PluginVersion = "1.0.15";

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			Loc.Init();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "poneis.valheim.TerrainShaperPlus");
			PrefabManager.OnVanillaPrefabsAvailable += ShaperItem.Create;
			PieceManager.OnPiecesRegistered += PieceFactory.InitPieces;
			((Component)this).gameObject.AddComponent<ShapePanel>();
			Log.LogInfo((object)"TerrainShaperPlus 1.0.15 loaded.");
		}
	}
	internal static class ShapeSettings
	{
		internal const float MaxMeters = 8f;

		internal const float MinMeters = 0.5f;

		internal static float Height = 1f;

		internal static float Width = 2f;

		internal static bool Square = true;

		internal static void Clamp()
		{
			Height = Mathf.Clamp(Height, 0.5f, 8f);
			Width = Mathf.Clamp(Width, 0.5f, 8f);
		}

		internal static void ApplyToTerrainOp(TerrainOp op, bool isLower)
		{
			if ((Object)(object)op == (Object)null)
			{
				return;
			}
			Clamp();
			Settings settings = op.m_settings;
			if (settings.m_raise)
			{
				settings.m_raiseDelta = (isLower ? (0f - Height) : Height);
				settings.m_raiseRadius = Width;
				settings.m_square = Square;
				if (Square)
				{
					settings.m_raisePower = ((Height >= 3f) ? 1.2f : 1.5f);
				}
				else if (Height >= 3f)
				{
					settings.m_raisePower = Mathf.Lerp(2.2f, 1.15f, Mathf.InverseLerp(3f, 8f, Height));
				}
			}
			if (settings.m_level)
			{
				settings.m_levelRadius = Width;
				settings.m_square = Square;
			}
			if (settings.m_smooth)
			{
				settings.m_smoothRadius = Width;
				settings.m_square = Square;
			}
			if (settings.m_paintCleared || (!settings.m_level && !settings.m_raise && !settings.m_smooth))
			{
				settings.m_paintRadius = Width;
				settings.m_square = Square;
			}
		}

		internal static void ApplyToAllRegisteredPieces()
		{
			Clamp();
			foreach (KeyValuePair<string, GameObject> prefab in PieceFactory.Prefabs)
			{
				GameObject value = prefab.Value;
				if (!((Object)(object)value == (Object)null))
				{
					TerrainOp componentInChildren = value.GetComponentInChildren<TerrainOp>(true);
					if (!((Object)(object)componentInChildren == (Object)null))
					{
						bool isLower = (Object)(object)value.GetComponent<LowerTerrainMarker>() != (Object)null;
						ApplyToTerrainOp(componentInChildren, isLower);
					}
				}
			}
			HeightDeltaModifier.CurrentHeightMeters = Height;
			Plugin.Log.LogInfo((object)$"ShapeSettings applied: {Height:0.##}m high × {Width:0.##}m wide, square={Square}");
		}

		internal static void ApplyToSelectedPiece(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			Piece selectedPiece = player.GetSelectedPiece();
			if (!((Object)(object)selectedPiece == (Object)null))
			{
				TerrainOp componentInChildren = ((Component)selectedPiece).GetComponentInChildren<TerrainOp>(true);
				if (!((Object)(object)componentInChildren == (Object)null))
				{
					bool isLower = (Object)(object)((Component)selectedPiece).GetComponent<LowerTerrainMarker>() != (Object)null;
					ApplyToTerrainOp(componentInChildren, isLower);
				}
			}
		}
	}
}
namespace TerrainShaperPlus.UI
{
	internal static class BrushOutlinePreview
	{
		private const int CircleSegments = 48;

		private static GameObject _root;

		private static LineRenderer _footprint;

		private static LineRenderer _top;

		private static readonly List<LineRenderer> Segments = new List<LineRenderer>();

		private static Material _mat;

		private static int _segUsed;

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

		internal static void Show(Vector3 center, float width, float height, bool square, bool showHeightVolume, bool lower, float yawDegrees = 0f)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.ShowBrushOutline.Value)
			{
				Hide();
				return;
			}
			Ensure();
			_root.SetActive(true);
			_segUsed = 0;
			float num = Mathf.Max(0.25f, width);
			float num2 = SampleY(center.x, center.z, center.y);
			float num3 = 0.08f;
			float y = num2 + num3;
			bool rotate = square && ModConfig.GridFollowPieceRotation.Value && Mathf.Abs(Mathf.DeltaAngle(0f, yawDegrees)) > 0.5f;
			if (square)
			{
				DrawLoop(_footprint, SquarePoints(center.x, center.z, num, y, yawDegrees, rotate), new Color(0.25f, 0.95f, 1f, 0.95f), 0.045f);
			}
			else
			{
				DrawLoop(_footprint, CirclePoints(center.x, center.z, num, y), new Color(0.25f, 0.95f, 1f, 0.95f), 0.045f);
			}
			if (ModConfig.ShowBrushGrid.Value)
			{
				DrawInnerGrid(center.x, center.z, num, y, square, yawDegrees, rotate);
			}
			if (showHeightVolume && height > 0.05f)
			{
				float topY = (lower ? (num2 - height) : (num2 + height));
				DrawHeightVolume(center.x, center.z, num, num2, topY, square, yawDegrees, rotate);
				((Renderer)_top).enabled = true;
			}
			else
			{
				((Renderer)_top).enabled = false;
			}
			DisableExtraSegments();
		}

		private static void DrawInnerGrid(float cx, float cz, float half, float y, bool square, float yaw, bool rotate)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			Color c = default(Color);
			((Color)(ref c))..ctor(0.35f, 0.75f, 0.95f, 0.4f);
			if (square)
			{
				float num = Mathf.Clamp(half / 2f, 0.5f, 2f);
				for (float num2 = 0f - half + num; num2 < half - 0.01f; num2 += num)
				{
					Vector3 a = LocalToWorld(cx, cz, y, num2, 0f - half, yaw, rotate);
					Vector3 b = LocalToWorld(cx, cz, y, num2, half, yaw, rotate);
					AddSegment(a, b, c, 0.02f);
				}
				for (float num3 = 0f - half + num; num3 < half - 0.01f; num3 += num)
				{
					Vector3 a2 = LocalToWorld(cx, cz, y, 0f - half, num3, yaw, rotate);
					Vector3 b2 = LocalToWorld(cx, cz, y, half, num3, yaw, rotate);
					AddSegment(a2, b2, c, 0.02f);
				}
			}
			else
			{
				AddSegment(new Vector3(cx - half, y, cz), new Vector3(cx + half, y, cz), c, 0.02f);
				AddSegment(new Vector3(cx, y, cz - half), new Vector3(cx, y, cz + half), c, 0.02f);
				DrawLoop(NextSegment(), CirclePoints(cx, cz, half * 0.5f, y), c, 0.02f);
			}
		}

		private static void DrawHeightVolume(float cx, float cz, float half, float groundY, float topY, bool square, float yaw, bool rotate)
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			Color c = default(Color);
			((Color)(ref c))..ctor(1f, 0.85f, 0.25f, 0.9f);
			if (square)
			{
				float[] array = new float[4]
				{
					0f - half,
					half,
					half,
					0f - half
				};
				float[] array2 = new float[4]
				{
					0f - half,
					0f - half,
					half,
					half
				};
				for (int i = 0; i < 4; i++)
				{
					Vector3 val = LocalToWorld(cx, cz, groundY, array[i], array2[i], yaw, rotate);
					float num = SampleY(val.x, val.z, groundY) + 0.05f;
					AddSegment(new Vector3(val.x, num, val.z), new Vector3(val.x, topY, val.z), c, 0.035f);
				}
				DrawLoop(_top, SquarePoints(cx, cz, half, topY, yaw, rotate), c, 0.035f);
			}
			else
			{
				for (int j = 0; j < 4; j++)
				{
					float num2 = (float)j * (float)Math.PI * 0.5f;
					float num3 = cx + Mathf.Cos(num2) * half;
					float num4 = cz + Mathf.Sin(num2) * half;
					float num5 = SampleY(num3, num4, groundY) + 0.05f;
					AddSegment(new Vector3(num3, num5, num4), new Vector3(num3, topY, num4), c, 0.035f);
				}
				DrawLoop(_top, CirclePoints(cx, cz, half, topY), c, 0.035f);
			}
		}

		private static Vector3[] SquarePoints(float cx, float cz, float half, float y, float yaw = 0f, bool rotate = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			return (Vector3[])(object)new Vector3[4]
			{
				LocalToWorld(cx, cz, y, 0f - half, 0f - half, yaw, rotate),
				LocalToWorld(cx, cz, y, half, 0f - half, yaw, rotate),
				LocalToWorld(cx, cz, y, half, half, yaw, rotate),
				LocalToWorld(cx, cz, y, 0f - half, half, yaw, rotate)
			};
		}

		private static Vector3 LocalToWorld(float cx, float cz, float y, float lx, float lz, float yaw, bool rotate)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (!rotate)
			{
				return new Vector3(cx + lx, y, cz + lz);
			}
			float num = yaw * ((float)Math.PI / 180f);
			float num2 = Mathf.Cos(num);
			float num3 = Mathf.Sin(num);
			return new Vector3(cx + lx * num2 - lz * num3, y, cz + lx * num3 + lz * num2);
		}

		private static Vector3[] CirclePoints(float cx, float cz, float radius, float y)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[48];
			for (int i = 0; i < 48; i++)
			{
				float num = (float)i / 48f * (float)Math.PI * 2f;
				array[i] = new Vector3(cx + Mathf.Cos(num) * radius, y, cz + Mathf.Sin(num) * radius);
			}
			return array;
		}

		private static void DrawLoop(LineRenderer lr, Vector3[] pts, Color c, float width)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			((Renderer)lr).enabled = true;
			lr.loop = true;
			lr.positionCount = pts.Length;
			for (int i = 0; i < pts.Length; i++)
			{
				lr.SetPosition(i, pts[i]);
			}
			lr.widthMultiplier = width;
			lr.startColor = c;
			lr.endColor = c;
		}

		private static void AddSegment(Vector3 a, Vector3 b, Color c, float width)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			LineRenderer obj = NextSegment();
			obj.loop = false;
			obj.positionCount = 2;
			obj.SetPosition(0, a);
			obj.SetPosition(1, b);
			obj.widthMultiplier = width;
			obj.startColor = c;
			obj.endColor = c;
		}

		private static LineRenderer NextSegment()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			while (Segments.Count <= _segUsed)
			{
				GameObject val = new GameObject("Seg_" + Segments.Count);
				val.transform.SetParent(_root.transform, false);
				LineRenderer val2 = val.AddComponent<LineRenderer>();
				((Renderer)val2).sharedMaterial = _mat;
				val2.useWorldSpace = true;
				((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val2).receiveShadows = false;
				val2.alignment = (LineAlignment)0;
				Segments.Add(val2);
			}
			LineRenderer obj = Segments[_segUsed++];
			((Component)obj).gameObject.SetActive(true);
			((Renderer)obj).enabled = true;
			return obj;
		}

		private static void DisableExtraSegments()
		{
			for (int i = _segUsed; i < Segments.Count; i++)
			{
				((Renderer)Segments[i]).enabled = false;
				((Component)Segments[i]).gameObject.SetActive(false);
			}
		}

		private static float SampleY(float x, float z, float fallback)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			float result = default(float);
			if (Heightmap.GetHeight(new Vector3(x, fallback, z), ref result))
			{
				return result;
			}
			return fallback;
		}

		private static void Ensure()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)_root != (Object)null))
			{
				_root = new GameObject("TerrainShaperPlus_BrushOutline");
				Object.DontDestroyOnLoad((Object)(object)_root);
				_mat = CreateMat();
				_footprint = CreateLr("Footprint");
				_top = CreateLr("Top");
				_root.SetActive(false);
			}
		}

		private static LineRenderer CreateLr(string name)
		{
			//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)
			GameObject val = new GameObject(name);
			val.transform.SetParent(_root.transform, false);
			LineRenderer obj = val.AddComponent<LineRenderer>();
			((Renderer)obj).sharedMaterial = _mat;
			obj.useWorldSpace = true;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			obj.numCapVertices = 2;
			obj.alignment = (LineAlignment)0;
			return obj;
		}

		private static Material CreateMat()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			return new Material(Shader.Find("Sprites/Default") ?? Shader.Find("UI/Default") ?? Shader.Find("Hidden/Internal-Colored") ?? Shader.Find("Standard"))
			{
				color = Color.cyan
			};
		}
	}
	internal class ShapePanel : MonoBehaviour
	{
		private bool _visible;

		private string _heightStr = "1";

		private string _widthStr = "2";

		private Rect _win = new Rect(40f, 120f, 320f, 240f);

		private int _winId = 718273;

		internal static ShapePanel Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			_heightStr = ShapeSettings.Height.ToString("0.##");
			_widthStr = ShapeSettings.Width.ToString("0.##");
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !ShaperItem.IsEquipped(localPlayer))
			{
				_visible = false;
				return;
			}
			if (ModConfig.IsPanelToggleDown())
			{
				_visible = !_visible;
				if (_visible)
				{
					_heightStr = ShapeSettings.Height.ToString("0.##");
					_widthStr = ShapeSettings.Width.ToString("0.##");
				}
			}
			if (!_visible && ShaperItem.IsEquipped(localPlayer) && Time.frameCount % 30 == 0)
			{
				ShapeSettings.ApplyToSelectedPiece(localPlayer);
			}
		}

		private void OnGUI()
		{
			//IL_00d5: 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_00f5: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && ShaperItem.IsEquipped(localPlayer))
			{
				if (!_visible)
				{
					float num = Mathf.Max(8f, (float)Screen.height - 200f);
					Rect val = new Rect(16f, num, Mathf.Min(920f, (float)Screen.width - 32f), 28f);
					Color color = GUI.color;
					GUI.color = new Color(0f, 0f, 0f, 0.45f);
					GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture);
					GUI.color = color;
					GUI.Label(val, "  " + Loc.Tf("tsp_panel_hint", ModConfig.FormatPanelHotkey(), ModConfig.FormatGridSnapHotkey(), ModConfig.FormatRadiusHotkey()));
				}
				else
				{
					_win = GUI.Window(_winId, _win, new WindowFunction(DrawWindow), Loc.T("tsp_panel_title"));
				}
			}
		}

		private void DrawWindow(int id)
		{
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Space(4f);
			GUILayout.Label(Loc.T("tsp_panel_subtitle"), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(Loc.T("tsp_panel_height"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
			_heightStr = GUILayout.TextField(_heightStr, 8, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			GUILayout.Label("m", Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(Loc.T("tsp_panel_width"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
			_widthStr = GUILayout.TextField(_widthStr, 8, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			GUILayout.Label("m", Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			ShapeSettings.Square = GUILayout.Toggle(ShapeSettings.Square, Loc.T("tsp_panel_square"), Array.Empty<GUILayoutOption>());
			GUILayout.Label(Loc.Tf("tsp_panel_preview", ParseOr(ShapeSettings.Height, _heightStr), ParseOr(ShapeSettings.Width, _widthStr)), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(Loc.T("tsp_panel_apply"), Array.Empty<GUILayoutOption>()))
			{
				ApplyFromFields();
			}
			if (GUILayout.Button("1×2", Array.Empty<GUILayoutOption>()))
			{
				SetPreset(1f, 2f);
			}
			if (GUILayout.Button("5×2", Array.Empty<GUILayoutOption>()))
			{
				SetPreset(5f, 2f);
			}
			if (GUILayout.Button("5×3", Array.Empty<GUILayoutOption>()))
			{
				SetPreset(5f, 3f);
			}
			if (GUILayout.Button("8×3", Array.Empty<GUILayoutOption>()))
			{
				SetPreset(8f, 3f);
			}
			GUILayout.EndHorizontal();
			GUILayout.Label(Loc.T("tsp_panel_help"), Array.Empty<GUILayoutOption>());
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
		}

		private void ApplyFromFields()
		{
			if (float.TryParse(_heightStr.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				ShapeSettings.Height = result;
			}
			if (float.TryParse(_widthStr.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
			{
				ShapeSettings.Width = result2;
			}
			ShapeSettings.Clamp();
			_heightStr = ShapeSettings.Height.ToString("0.##");
			_widthStr = ShapeSettings.Width.ToString("0.##");
			ShapeSettings.ApplyToAllRegisteredPieces();
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, Loc.Tf("tsp_panel_applied", ShapeSettings.Height, ShapeSettings.Width), 0, (Sprite)null, false);
			}
		}

		private void SetPreset(float h, float w)
		{
			ShapeSettings.Height = h;
			ShapeSettings.Width = w;
			ShapeSettings.Square = true;
			ShapeSettings.Clamp();
			_heightStr = ShapeSettings.Height.ToString("0.##");
			_widthStr = ShapeSettings.Width.ToString("0.##");
			ShapeSettings.ApplyToAllRegisteredPieces();
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, Loc.Tf("tsp_panel_applied", ShapeSettings.Height, ShapeSettings.Width), 0, (Sprite)null, false);
			}
		}

		private static float ParseOr(float fallback, string s)
		{
			if (float.TryParse(s.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return Mathf.Clamp(result, 0.5f, 8f);
			}
			return fallback;
		}
	}
}
namespace TerrainShaperPlus.Tools
{
	internal static class PieceFactory
	{
		private static bool _initialized;

		internal static readonly Dictionary<string, GameObject> Prefabs = new Dictionary<string, GameObject>();

		internal static void InitPieces()
		{
			if (_initialized)
			{
				return;
			}
			Loc.ApplyLanguagePreference();
			foreach (ToolDef item in ToolDefs.All)
			{
				try
				{
					GameObject val = MakePiece(item);
					if (!((Object)(object)val == (Object)null))
					{
						Prefabs[item.Id] = val;
						if (ModConfig.IsToolEnabled(item.Id))
						{
							RegisterInTable(val);
						}
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Failed to create piece " + item.Id + ": " + ex.Message));
				}
			}
			_initialized = true;
			Plugin.Log.LogInfo((object)$"Registered {Prefabs.Count} Terrain Shaper Plus pieces.");
			ApplyPlacementRules();
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				ObjectDBTerrainOpPatch.RegisterTerrainOps(ObjectDB.instance);
			}
			ShapeSettings.ApplyToAllRegisteredPieces();
		}

		private static GameObject MakePiece(ToolDef def)
		{
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			if (PieceManager.Instance.GetPiece(def.Id) != null)
			{
				return null;
			}
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(def.Id, def.BasePrefab);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Missing base prefab " + def.BasePrefab + " for " + def.Id));
				return null;
			}
			((Object)val).name = def.Id;
			Piece component = val.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_name = Loc.Token(def.NameToken);
				component.m_description = Loc.Token(def.DescToken);
				component.m_resources = Array.Empty<Requirement>();
				component.m_icon = ToolIcons.Create(def.Icon);
				component.m_canRotate = true;
				ApplyWorkbenchRequirement(component);
			}
			TerrainOp componentInChildren = val.GetComponentInChildren<TerrainOp>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				if ((Object)(object)((Component)componentInChildren).gameObject != (Object)(object)val)
				{
					((Object)((Component)componentInChildren).gameObject).name = def.Id;
				}
				Settings settings = componentInChildren.m_settings;
				if (def.Level.HasValue)
				{
					settings.m_level = def.Level.Value;
				}
				if (def.LevelRadius.HasValue)
				{
					settings.m_levelRadius = def.LevelRadius.Value;
				}
				if (def.Raise.HasValue)
				{
					settings.m_raise = def.Raise.Value;
				}
				if (def.RaiseRadius.HasValue)
				{
					settings.m_raiseRadius = def.RaiseRadius.Value;
				}
				if (def.RaisePower.HasValue)
				{
					settings.m_raisePower = def.RaisePower.Value;
				}
				if (def.RaiseDelta.HasValue)
				{
					settings.m_raiseDelta = def.RaiseDelta.Value;
				}
				if (def.Smooth.HasValue)
				{
					settings.m_smooth = def.Smooth.Value;
				}
				if (def.SmoothRadius.HasValue)
				{
					settings.m_smoothRadius = def.SmoothRadius.Value;
				}
				if (def.SmoothPower.HasValue)
				{
					settings.m_smoothPower = def.SmoothPower.Value;
				}
				if (def.PaintCleared.HasValue)
				{
					settings.m_paintCleared = def.PaintCleared.Value;
				}
				if (def.PaintRadius.HasValue)
				{
					settings.m_paintRadius = def.PaintRadius.Value;
				}
				settings.m_square = def.Square;
				if (def.IsReset)
				{
					settings.m_level = false;
					settings.m_smooth = false;
					settings.m_raise = false;
					settings.m_paintCleared = false;
				}
			}
			else
			{
				Plugin.Log.LogWarning((object)("No TerrainOp on " + def.Id + " (base " + def.BasePrefab + ")"));
			}
			if (def.InvertGhost)
			{
				Transform val2 = val.transform.Find("_GhostOnly");
				if ((Object)(object)val2 != (Object)null)
				{
					val2.localRotation = Quaternion.Euler(270f, 0f, 0f);
					val2.localPosition += new Vector3(0f, 2f, 0f);
				}
			}
			if (def.IsReset)
			{
				val.AddComponent<ResetTerrainMarker>();
			}
			if (def.IsLower)
			{
				val.AddComponent<LowerTerrainMarker>();
			}
			if (def.Square)
			{
				val.AddComponent<SquareToolMarker>();
			}
			if (def.Raise == true)
			{
				val.AddComponent<HeightToolMarker>();
			}
			return val;
		}

		private static void RegisterInTable(GameObject prefab)
		{
			PieceTable pieceTable = PieceManager.Instance.GetPieceTable("_TSP_PieceTable");
			if ((Object)(object)pieceTable == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Piece table _TSP_PieceTable not found.");
			}
			else if (!pieceTable.m_pieces.Contains(prefab))
			{
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					PrefabManager.Instance.RegisterToZNetScene(prefab);
				}
				pieceTable.m_pieces.Add(prefab);
			}
		}

		internal static void ApplyPlacementRules()
		{
			foreach (GameObject value in Prefabs.Values)
			{
				if (!((Object)(object)value == (Object)null))
				{
					Piece component = value.GetComponent<Piece>();
					if (!((Object)(object)component == (Object)null))
					{
						component.m_canRotate = true;
						ApplyWorkbenchRequirement(component);
					}
				}
			}
			Plugin.Log.LogInfo((object)$"Placement rules: RequireWorkbench={ModConfig.RequireWorkbenchToPlace.Value}, canRotate=true");
		}

		private static void ApplyWorkbenchRequirement(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return;
			}
			if (!ModConfig.RequireWorkbenchToPlace.Value)
			{
				piece.m_craftingStation = null;
				return;
			}
			CraftingStation val = FindWorkbenchStation();
			if ((Object)(object)val != (Object)null)
			{
				piece.m_craftingStation = val;
			}
		}

		private static CraftingStation FindWorkbenchStation()
		{
			GameObject val = null;
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				val = ZNetScene.instance.GetPrefab("piece_workbench");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = PrefabManager.Instance.GetPrefab("piece_workbench");
			}
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<CraftingStation>();
		}
	}
	internal class ResetTerrainMarker : MonoBehaviour
	{
	}
	internal class LowerTerrainMarker : MonoBehaviour
	{
	}
	internal class SquareToolMarker : MonoBehaviour
	{
	}
	internal class HeightToolMarker : MonoBehaviour
	{
	}
	internal class PreciseRaiseMarker : MonoBehaviour
	{
	}
	internal static class ShaperItem
	{
		internal const string PrefabName = "TSP_TerrainShaperPlus";

		internal const string ItemNameToken = "$tsp_item_name";

		private static bool _created;

		internal static void Create()
		{
			if (!_created)
			{
				CreatePieceTable();
				CreateItem();
				ItemManager.OnItemsRegistered += EnsureRepairable;
				_created = true;
			}
		}

		private static void CreatePieceTable()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_001b: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			PieceTableConfig val = new PieceTableConfig
			{
				CanRemovePieces = false,
				UseCategories = false,
				UseCustomCategories = false
			};
			PieceManager.Instance.AddPieceTable(new CustomPieceTable("_TSP_PieceTable", val));
		}

		private static void CreateItem()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("TSP_TerrainShaperPlus", "Hoe");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"Failed to clone Hoe for Terrain Shaper Plus.");
				return;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if (component?.m_itemData?.m_shared != null)
			{
				ApplyDurability(component.m_itemData.m_shared);
				component.m_itemData.m_dropPrefab = val;
			}
			List<RequirementConfig> list = new List<RequirementConfig>
			{
				new RequirementConfig("Wood", ModConfig.RecipeWood.Value, 0, true),
				new RequirementConfig("Stone", ModConfig.RecipeStone.Value, 0, true)
			};
			ItemConfig val2 = new ItemConfig
			{
				Name = Loc.Token("tsp_item_name"),
				Description = Loc.Token("tsp_item_desc"),
				CraftingStation = CraftingStations.Workbench,
				RepairStation = CraftingStations.Workbench,
				MinStationLevel = ModConfig.MinWorkbenchLevel.Value,
				PieceTable = "_TSP_PieceTable",
				Requirements = list.ToArray()
			};
			CustomItem val3 = new CustomItem(val, true, val2);
			CustomRecipe recipe = val3.Recipe;
			if ((Object)(object)((recipe != null) ? recipe.Recipe : null) != (Object)null)
			{
				val3.Recipe.Recipe.m_enabled = ModConfig.EnableTool.Value;
			}
			ItemManager.Instance.AddItem(val3);
			Plugin.Log.LogInfo((object)string.Format("Registered craftable/repairable item {0} at Workbench (min level {1}).", "TSP_TerrainShaperPlus", ModConfig.MinWorkbenchLevel.Value));
		}

		private static void EnsureRepairable()
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("TSP_TerrainShaperPlus") : null);
			if ((Object)(object)val == (Object)null)
			{
				val = PrefabManager.Instance.GetPrefab("TSP_TerrainShaperPlus");
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"EnsureRepairable: prefab not found.");
				return;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if (component?.m_itemData?.m_shared == null)
			{
				return;
			}
			component.m_itemData.m_shared.m_name = "$tsp_item_name";
			ApplyDurability(component.m_itemData.m_shared);
			component.m_itemData.m_dropPrefab = val;
			CraftingStation val2 = FindWorkbenchStation();
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"EnsureRepairable: piece_workbench CraftingStation not found.");
				return;
			}
			Recipe val3 = null;
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				foreach (Recipe recipe in ObjectDB.instance.m_recipes)
				{
					if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null) && ((Object)(object)recipe.m_item == (Object)(object)component || ((Object)recipe).name == "Recipe_TSP_TerrainShaperPlus" || (recipe.m_item.m_itemData?.m_shared != null && recipe.m_item.m_itemData.m_shared.m_name == "$tsp_item_name")))
					{
						val3 = recipe;
						break;
					}
				}
			}
			if ((Object)(object)val3 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"EnsureRepairable: recipe not found in ObjectDB.");
				return;
			}
			val3.m_item = component;
			val3.m_craftingStation = val2;
			val3.m_repairStation = val2;
			val3.m_enabled = ModConfig.EnableTool.Value;
			val3.m_minStationLevel = Mathf.Clamp(ModConfig.MinWorkbenchLevel.Value, 1, 5);
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				ObjectDBTerrainOpPatch.RegisterTerrainOps(ObjectDB.instance);
			}
			ManualLogSource log = Plugin.Log;
			string[] obj = new string[8]
			{
				"EnsureRepairable OK: recipe=",
				((Object)val3).name,
				", craft=",
				null,
				null,
				null,
				null,
				null
			};
			CraftingStation craftingStation = val3.m_craftingStation;
			obj[3] = ((craftingStation != null) ? ((Object)craftingStation).name : null);
			obj[4] = ", ";
			CraftingStation repairStation = val3.m_repairStation;
			obj[5] = $"repair={((repairStation != null) ? ((Object)repairStation).name : null)}, minLevel={val3.m_minStationLevel}, ";
			obj[6] = $"durability={component.m_itemData.m_shared.m_maxDurability:0} ";
			obj[7] = $"(drain={component.m_itemData.m_shared.m_useDurabilityDrain:0.##})";
			log.LogInfo((object)string.Concat(obj));
		}

		internal static void ApplyDurability(SharedData shared)
		{
			if (shared != null)
			{
				shared.m_canBeReparied = true;
				shared.m_useDurability = true;
				shared.m_maxDurability = Mathf.Clamp(ModConfig.MaxDurability.Value, 50f, 10000f);
				shared.m_durabilityPerLevel = Mathf.Clamp(ModConfig.DurabilityPerLevel.Value, 0f, 2000f);
				shared.m_useDurabilityDrain = Mathf.Clamp(ModConfig.DurabilityDrain.Value, 0.05f, 5f);
			}
		}

		private static CraftingStation FindWorkbenchStation()
		{
			GameObject val = null;
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				val = ZNetScene.instance.GetPrefab("piece_workbench");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = PrefabManager.Instance.GetPrefab("piece_workbench");
			}
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<CraftingStation>();
		}

		internal static bool IsOurItem(ItemData item)
		{
			if (item?.m_shared == null)
			{
				return false;
			}
			if (item.m_shared.m_name == "$tsp_item_name")
			{
				return true;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null && Utils.GetPrefabName(((Object)item.m_dropPrefab).name) == "TSP_TerrainShaperPlus")
			{
				return true;
			}
			return false;
		}

		internal static bool IsEquipped(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			ItemData rightItem = ((Humanoid)player).GetRightItem();
			if (rightItem == null)
			{
				return false;
			}
			if (IsOurItem(rightItem))
			{
				return true;
			}
			if ((Object)(object)rightItem.m_dropPrefab != (Object)null)
			{
				string prefabName = Utils.GetPrefabName(((Object)rightItem.m_dropPrefab).name);
				if (prefabName == "TSP_TerrainShaperPlus" || prefabName.StartsWith("TSP_"))
				{
					return true;
				}
			}
			if (rightItem.m_shared != null && (Object)(object)rightItem.m_shared.m_buildPieces != (Object)null && ((Object)rightItem.m_shared.m_buildPieces).name != null)
			{
				return ((Object)rightItem.m_shared.m_buildPieces).name.IndexOf("TSP_", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}
	}
	internal sealed class ToolDef
	{
		public string Id;

		public string BasePrefab;

		public string NameToken;

		public string DescToken;

		public bool? Level;

		public float? LevelRadius;

		public bool? Raise;

		public float? RaiseRadius;

		public float? RaisePower;

		public float? RaiseDelta;

		public bool? Smooth;

		public float? SmoothRadius;

		public float? SmoothPower;

		public bool? PaintCleared;

		public float? PaintRadius;

		public bool Square;

		public bool InvertGhost;

		public bool IsReset;

		public bool IsLower;

		public IconStyle Icon;
	}
	internal enum IconStyle
	{
		Default,
		Raise,
		Lower,
		Smooth,
		Reset,
		Paint
	}
	internal static class ToolDefs
	{
		internal const string PieceTable = "_TSP_PieceTable";

		internal static readonly List<ToolDef> All = new List<ToolDef>
		{
			new ToolDef
			{
				Id = "TSP_level",
				BasePrefab = "mud_road_v2",
				NameToken = "tsp_piece_level",
				DescToken = "tsp_piece_level_desc",
				Level = true,
				Smooth = false,
				Raise = false,
				Icon = IconStyle.Default
			},
			new ToolDef
			{
				Id = "TSP_level_sq",
				BasePrefab = "mud_road_v2",
				NameToken = "tsp_piece_level_sq",
				DescToken = "tsp_piece_level_sq_desc",
				Level = true,
				Smooth = false,
				Raise = false,
				Square = true,
				Icon = IconStyle.Default
			},
			new ToolDef
			{
				Id = "TSP_raise",
				BasePrefab = "raise_v2",
				NameToken = "tsp_piece_raise",
				DescToken = "tsp_piece_raise_desc",
				Raise = true,
				RaiseDelta = 1f,
				RaisePower = 0.5f,
				Icon = IconStyle.Raise
			},
			new ToolDef
			{
				Id = "TSP_raise_sq",
				BasePrefab = "raise_v2",
				NameToken = "tsp_piece_raise_sq",
				DescToken = "tsp_piece_raise_sq_desc",
				Raise = true,
				RaiseDelta = 1f,
				RaisePower = 0.5f,
				Square = true,
				Icon = IconStyle.Raise
			},
			new ToolDef
			{
				Id = "TSP_lower",
				BasePrefab = "raise_v2",
				NameToken = "tsp_piece_lower",
				DescToken = "tsp_piece_lower_desc",
				Raise = true,
				RaiseDelta = -1f,
				RaisePower = 0.5f,
				RaiseRadius = 1.5f,
				InvertGhost = true,
				IsLower = true,
				Icon = IconStyle.Lower
			},
			new ToolDef
			{
				Id = "TSP_lower_sq",
				BasePrefab = "raise_v2",
				NameToken = "tsp_piece_lower_sq",
				DescToken = "tsp_piece_lower_sq_desc",
				Raise = true,
				RaiseDelta = -1f,
				RaisePower = 0.5f,
				RaiseRadius = 1.5f,
				InvertGhost = true,
				IsLower = true,
				Square = true,
				Icon = IconStyle.Lower
			},
			new ToolDef
			{
				Id = "TSP_smooth",
				BasePrefab = "mud_road_v2",
				NameToken = "tsp_piece_smooth",
				DescToken = "tsp_piece_smooth_desc",
				Level = false,
				Smooth = true,
				Raise = false,
				SmoothPower = 3f,
				Icon = IconStyle.Smooth
			},
			new ToolDef
			{
				Id = "TSP_reset",
				BasePrefab = "mud_road_v2",
				NameToken = "tsp_piece_reset",
				DescToken = "tsp_piece_reset_desc",
				Level = false,
				Smooth = false,
				Raise = false,
				PaintCleared = false,
				IsReset = true,
				Icon = IconStyle.Reset
			},
			new ToolDef
			{
				Id = "TSP_paint_dirt",
				BasePrefab = "path_v2",
				NameToken = "tsp_piece_paint_dirt",
				DescToken = "tsp_piece_paint_dirt_desc",
				Level = false,
				Smooth = false,
				Raise = false,
				Icon = IconStyle.Paint
			},
			new ToolDef
			{
				Id = "TSP_paint_paved",
				BasePrefab = "paved_road_v2",
				NameToken = "tsp_piece_paint_paved",
				DescToken = "tsp_piece_paint_paved_desc",
				Level = false,
				Smooth = false,
				Raise = false,
				Icon = IconStyle.Paint
			},
			new ToolDef
			{
				Id = "TSP_paint_cultivate",
				BasePrefab = "cultivate_v2",
				NameToken = "tsp_piece_paint_cultivate",
				DescToken = "tsp_piece_paint_cultivate_desc",
				Level = false,
				Smooth = false,
				Raise = false,
				Icon = IconStyle.Paint
			},
			new ToolDef
			{
				Id = "TSP_paint_reset",
				BasePrefab = "replant_v2",
				NameToken = "tsp_piece_paint_reset",
				DescToken = "tsp_piece_paint_reset_desc",
				Level = false,
				Smooth = false,
				Raise = false,
				Icon = IconStyle.Paint
			}
		};

		internal static IEnumerable<string> AllIds
		{
			get
			{
				foreach (ToolDef item in All)
				{
					yield return item.Id;
				}
			}
		}
	}
	internal static class ToolIcons
	{
		internal static Sprite Create(IconStyle style)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: 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_01c0: 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_019f: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			new Color(0f, 0f, 0f, 0f);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.18f, 0.14f, 0.1f, 0.92f);
			Color val3 = (Color)(style switch
			{
				IconStyle.Raise => new Color(0.35f, 0.85f, 0.35f, 1f), 
				IconStyle.Lower => new Color(0.95f, 0.45f, 0.2f, 1f), 
				IconStyle.Smooth => new Color(0.35f, 0.65f, 0.95f, 1f), 
				IconStyle.Reset => new Color(0.95f, 0.3f, 0.3f, 1f), 
				IconStyle.Paint => new Color(0.85f, 0.7f, 0.3f, 1f), 
				_ => new Color(0.75f, 0.7f, 0.55f, 1f), 
			});
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					val.SetPixel(j, i, val2);
				}
			}
			FillCircle(val, 32, 32, 30, val3 * 0.25f);
			switch (style)
			{
			case IconStyle.Raise:
				DrawArrow(val, up: true, val3);
				break;
			case IconStyle.Lower:
				DrawArrow(val, up: false, val3);
				break;
			case IconStyle.Smooth:
				DrawWave(val, val3);
				break;
			case IconStyle.Reset:
				DrawX(val, val3);
				break;
			case IconStyle.Paint:
				DrawBrush(val, val3);
				break;
			default:
				DrawFlat(val, val3);
				break;
			}
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
		}

		private static void FillCircle(Texture2D tex, int cx, int cy, int r, Color c)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			int num = r * r;
			for (int i = cy - r; i <= cy + r; i++)
			{
				for (int j = cx - r; j <= cx + r; j++)
				{
					if (j >= 0 && i >= 0 && j < ((Texture)tex).width && i < ((Texture)tex).height)
					{
						int num2 = j - cx;
						int num3 = i - cy;
						if (num2 * num2 + num3 * num3 <= num)
						{
							tex.SetPixel(j, i, c);
						}
					}
				}
			}
		}

		private static void DrawArrow(Texture2D tex, bool up, Color c)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			int num = ((Texture)tex).width / 2;
			for (int i = 18; i <= 46; i++)
			{
				for (int j = num - 4; j <= num + 4; j++)
				{
					tex.SetPixel(j, i, c);
				}
			}
			if (up)
			{
				for (int k = 0; k < 16; k++)
				{
					for (int l = num - k; l <= num + k; l++)
					{
						tex.SetPixel(l, 46 + (16 - k) / 2, c);
					}
				}
				return;
			}
			for (int m = 0; m < 16; m++)
			{
				for (int n = num - m; n <= num + m; n++)
				{
					tex.SetPixel(n, 18 - (16 - m) / 2, c);
				}
			}
		}

		private static void DrawWave(Texture2D tex, Color c)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 10; i < ((Texture)tex).width - 10; i++)
			{
				int num = ((Texture)tex).height / 2 + (int)(Mathf.Sin((float)i * 0.35f) * 10f);
				for (int j = -2; j <= 2; j++)
				{
					tex.SetPixel(i, num + j, c);
				}
			}
		}

		private static void DrawX(Texture2D tex, Color c)
		{
			//IL_0008: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 14; i < 50; i++)
			{
				tex.SetPixel(i, i, c);
				tex.SetPixel(i + 1, i, c);
				tex.SetPixel(i, 63 - i, c);
				tex.SetPixel(i + 1, 63 - i, c);
			}
		}

		private static void DrawBrush(Texture2D tex, Color c)
		{
			//IL_002c: 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)
			for (int i = 12; i < 40; i++)
			{
				for (int j = 28; j < 36; j++)
				{
					tex.SetPixel(j, i, c);
				}
			}
			FillCircle(tex, 32, 48, 10, c);
		}

		private static void DrawFlat(Texture2D tex, Color c)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 28; i <= 36; i++)
			{
				for (int j = 12; j < 52; j++)
				{
					tex.SetPixel(j, i, c);
				}
			}
		}
	}
}
namespace TerrainShaperPlus.Terrain
{
	internal static class ResetTerrain
	{
		internal static void Apply(Vector3 position, float radiusMeters, bool square, float yawDegrees = 0f)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			radiusMeters = Mathf.Clamp(radiusMeters, 0.5f, ModConfig.MaxRadius.Value);
			bool rotate = square && ModConfig.GridFollowPieceRotation.Value && Mathf.Abs(Mathf.DeltaAngle(0f, yawDegrees)) > 0.5f;
			Plugin.Log.LogInfo((object)$"ResetTerrain.Apply at {position}, radius={radiusMeters:0.##}m square={square} yaw={yawDegrees:0.#}");
			int num = 0;
			foreach (TerrainModifier allInstance in TerrainModifier.GetAllInstances())
			{
				if (!((Object)(object)allInstance == (Object)null) && InBrush(position, ((Component)allInstance).transform.position, radiusMeters, square, yawDegrees, rotate))
				{
					ZNetView component = ((Component)allInstance).GetComponent<ZNetView>();
					if (!((Object)(object)component == (Object)null))
					{
						component.ClaimOwnership();
						component.Destroy();
						num++;
					}
				}
			}
			List<Heightmap> list = new List<Heightmap>();
			Heightmap.FindHeightmap(position, radiusMeters + 50f, list);
			bool flag = false;
			int num2 = 0;
			int cx = default(int);
			int cy = default(int);
			foreach (Heightmap item in list)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				TerrainComp val = TerrainComp.FindTerrainCompiler(((Component)item).transform.position);
				if ((Object)(object)val == (Object)null || !val.m_initialized)
				{
					continue;
				}
				if (!val.IsOwner())
				{
					ZNetView component2 = ((Component)val).GetComponent<ZNetView>();
					if (component2 != null)
					{
						component2.ClaimOwnership();
					}
				}
				item.WorldToVertex(position, ref cx, ref cy);
				float num3 = Mathf.Max(0.01f, item.m_scale);
				float vertexRadius = radiusMeters / num3;
				int width = val.m_width;
				float[] levelDelta = val.m_levelDelta;
				float[] smoothDelta = val.m_smoothDelta;
				bool[] modifiedHeight = val.m_modifiedHeight;
				Color[] paintMask = val.m_paintMask;
				bool[] modifiedPaint = val.m_modifiedPaint;
				if (levelDelta == null || modifiedHeight == null)
				{
					continue;
				}
				bool flag2 = false;
				for (int i = 0; i <= width; i++)
				{
					for (int j = 0; j <= width; j++)
					{
						if (!InBrushVertex(cx, cy, j, i, vertexRadius, square, item.m_scale, yawDegrees, rotate))
						{
							continue;
						}
						int num4 = j + i * (width + 1);
						if (num4 >= 0 && num4 < modifiedHeight.Length && modifiedHeight[num4])
						{
							modifiedHeight[num4] = false;
							levelDelta[num4] = 0f;
							if (smoothDelta != null && num4 < smoothDelta.Length)
							{
								smoothDelta[num4] = 0f;
							}
							flag2 = true;
							flag = true;
						}
						if (i < width && j < width && modifiedPaint != null && paintMask != null)
						{
							int num5 = j + i * width;
							if (num5 >= 0 && num5 < modifiedPaint.Length && modifiedPaint[num5])
							{
								modifiedPaint[num5] = false;
								paintMask[num5] = Color.clear;
								flag2 = true;
								flag = true;
							}
						}
					}
				}
				if (flag2)
				{
					num2++;
					val.m_levelDelta = levelDelta;
					val.m_smoothDelta = smoothDelta;
					val.m_modifiedHeight = modifiedHeight;
					val.m_paintMask = paintMask;
					val.m_modifiedPaint = modifiedPaint;
					val.Save(false);
					item.Poke(0, false);
					ZNetView component3 = ((Component)val).GetComponent<ZNetView>();
					ZDO val2 = ((component3 != null) ? component3.GetZDO() : null);
					if (val2 != null)
					{
						ZDOMan.instance.ForceSendZDO(val2.m_uid);
					}
				}
			}
			if ((Object)(object)ClutterSystem.instance != (Object)null && flag)
			{
				ClutterSystem.instance.ResetGrass(position, radiusMeters);
			}
			Plugin.Log.LogInfo((object)$"ResetTerrain done: modifiersRemoved={num}, heightmapsTouched={num2}");
		}

		private static bool InBrush(Vector3 center, Vector3 point, float radius, bool square, float yaw, bool rotate)
		{
			//IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			float num = point.x - center.x;
			float num2 = point.z - center.z;
			if (square)
			{
				if (rotate)
				{
					RotatedBrush.ToLocal(num, num2, yaw, out var localX, out var localZ);
					return RotatedBrush.InSquareLocal(localX, localZ, radius);
				}
				return Mathf.Max(Mathf.Abs(num), Mathf.Abs(num2)) <= radius;
			}
			return num * num + num2 * num2 <= radius * radius;
		}

		private static bool InBrushVertex(int cx, int cy, int x, int y, float vertexRadius, bool square, float scale, float yaw, bool rotate)
		{
			float num = x - cx;
			float num2 = y - cy;
			if (square)
			{
				if (rotate)
				{
					float worldDx = num * scale;
					float worldDz = num2 * scale;
					RotatedBrush.ToLocal(worldDx, worldDz, yaw, out var localX, out var localZ);
					return Mathf.Max(Mathf.Abs(localX), Mathf.Abs(localZ)) / Mathf.Max(0.01f, scale) <= vertexRadius;
				}
				return Mathf.Max(Mathf.Abs(num), Mathf.Abs(num2)) <= vertexRadius;
			}
			return num * num + num2 * num2 <= vertexRadius * vertexRadius;
		}
	}
	internal static class RotatedBrush
	{
		internal static float NextYawDegrees;

		internal static bool HasYaw => Mathf.Abs(Mathf.DeltaAngle(0f, NextYawDegrees)) > 0.5f;

		internal static void Clear()
		{
			NextYawDegrees = 0f;
		}

		internal static void SetFromTransform(Transform t)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			NextYawDegrees = (((Object)(object)t != (Object)null) ? t.eulerAngles.y : 0f);
		}

		internal static void ToLocal(float worldDx, float worldDz, float yawDegrees, out float localX, out float localZ)
		{
			float num = (0f - yawDegrees) * ((float)Math.PI / 180f);
			float num2 = Mathf.Cos(num);
			float num3 = Mathf.Sin(num);
			localX = worldDx * num2 - worldDz * num3;
			localZ = worldDx * num3 + worldDz * num2;
		}

		internal static bool InSquareLocal(float localX, float localZ, float halfExtent)
		{
			return Mathf.Max(Mathf.Abs(localX), Mathf.Abs(localZ)) <= halfExtent;
		}

		internal static bool InCircleLocal(float localX, float localZ, float radius)
		{
			return localX * localX + localZ * localZ <= radius * radius;
		}

		internal static float SnapYaw(float yawDegrees, float stepDegrees)
		{
			if (stepDegrees <= 0.01f)
			{
				return yawDegrees;
			}
			return Mathf.Round(yawDegrees / stepDegrees) * stepDegrees;
		}
	}
}
namespace TerrainShaperPlus.Patches
{
	[HarmonyPatch]
	internal static class BrushOutlinePatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static void UpdatePlacementGhostPostfix(Player __instance)
		{
			//IL_016a: 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)
			if (!ModConfig.ShowBrushOutline.Value)
			{
				BrushOutlinePreview.Hide();
				RestoreGhostVisuals(__instance);
			}
			else
			{
				if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				if (!ShaperItem.IsEquipped(__instance) || !((Character)__instance).InPlaceMode())
				{
					BrushOutlinePreview.Hide();
					return;
				}
				if ((Object)(object)__instance.m_placementGhost == (Object)null || !__instance.m_placementGhost.activeInHierarchy)
				{
					BrushOutlinePreview.Hide();
					return;
				}
				Piece selectedPiece = __instance.GetSelectedPiece();
				if ((Object)(object)selectedPiece == (Object)null || (Object)(object)((Component)selectedPiece).gameObject == (Object)null)
				{
					BrushOutlinePreview.Hide();
					RestoreGhostVisuals(__instance);
					return;
				}
				string prefabName = Utils.GetPrefabName(((Object)((Component)selectedPiece).gameObject).name);
				if (!prefabName.StartsWith("TSP_"))
				{
					BrushOutlinePreview.Hide();
					RestoreGhostVisuals(__instance);
					return;
				}
				bool flag = ShapeSettings.Square || (Object)(object)((Component)selectedPiece).gameObject.GetComponent<SquareToolMarker>() != (Object)null || prefabName.IndexOf("_sq", StringComparison.OrdinalIgnoreCase) >= 0;
				bool showHeightVolume = (Object)(object)((Component)selectedPiece).gameObject.GetComponent<HeightToolMarker>() != (Object)null || prefabName.IndexOf("raise", StringComparison.OrdinalIgnoreCase) >= 0 || prefabName.IndexOf("lower", StringComparison.OrdinalIgnoreCase) >= 0;
				bool lower = (Object)(object)((Component)selectedPiece).gameObject.GetComponent<LowerTerrainMarker>() != (Object)null || prefabName.IndexOf("lower", StringComparison.OrdinalIgnoreCase) >= 0;
				if (flag)
				{
					SetGhostVisuals(__instance, visible: false);
				}
				else
				{
					SetGhostVisuals(__instance, visible: true);
				}
				BrushOutlinePreview.Show(__instance.m_placementGhost.transform.position, yawDegrees: __instance.m_placementGhost.transform.eulerAngles.y, width: ShapeSettings.Width, height: ShapeSettings.Height, square: flag, showHeightVolume: showHeightVolume, lower: lower);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdatePostfix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && (!ShaperItem.IsEquipped(__instance) || !((Character)__instance).InPlaceMode()))
			{
				BrushOutlinePreview.Hide();
			}
		}

		private static void RestoreGhostVisuals(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				SetGhostVisuals(player, visible: true);
			}
		}

		private static void SetGhostVisuals(Player player, bool visible)
		{
			if ((Object)(object)player.m_placementGhost != (Object)null)
			{
				SetRenderers(player.m_placementGhost, visible);
			}
			if ((Object)(object)player.m_placementMarkerInstance != (Object)null)
			{
				SetRenderers(player.m_placementMarkerInstance, visible);
			}
		}

		private static void SetRenderers(GameObject go, bool visible)
		{
			if ((Object)(object)go == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null)
				{
					componentsInChildren[i].enabled = visible;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class CameraZoomBlockPatch
	{
		private static float _savedDistance;

		private static bool _restore;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void Prefix(GameCamera __instance)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			_restore = false;
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).InPlaceMode() && Input.mouseScrollDelta.y != 0f && (ShouldBlockZoomForShaper(localPlayer) || ShouldBlockZoomForFarm(localPlayer)))
			{
				_savedDistance = __instance.m_distance;
				_restore = true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void Postfix(GameCamera __instance)
		{
			if (_restore)
			{
				__instance.m_distance = _savedDistance;
			}
		}

		private static bool ShouldBlockZoomForShaper(Player player)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (!ShaperItem.IsEquipped(player))
			{
				return false;
			}
			Piece selectedPiece = player.GetSelectedPiece();
			bool flag = (Object)(object)selectedPiece != (Object)null && (Object)(object)((Component)selectedPiece).gameObject != (Object)null && (Object)(object)((Component)selectedPiece).gameObject.GetComponent<HeightToolMarker>() != (Object)null;
			if ((!ModConfig.EnableRadiusModifier.Value || !ModConfig.IsKeyHeld(ModConfig.RadiusModKey.Value)) && (!ModConfig.EnableSharpnessModifier.Value || !ModConfig.IsKeyHeld(ModConfig.SharpnessModKey.Value)))
			{
				if (ModConfig.EnableHeightModifier.Value && flag && !ModConfig.IsKeyHeld(ModConfig.RadiusModKey.Value))
				{
					return !ModConfig.IsKeyHeld(ModConfig.SharpnessModKey.Value);
				}
				return false;
			}
			return true;
		}

		private static bool ShouldBlockZoomForFarm(Player player)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.FarmGridEnabled.Value)
			{
				return false;
			}
			if (!ModConfig.IsKeyHeld(ModConfig.FarmSizeModKey.Value))
			{
				return false;
			}
			ItemData rightItem = ((Humanoid)player).GetRightItem();
			if (rightItem?.m_shared != null)
			{
				return rightItem.m_shared.m_name == "$item_cultivator";
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class GridSnapPatch
	{
		private static Vector3? _anchor;

		private static float _nextHint;

		private static float _nextOpsEnsure;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static void UpdatePlacementGhostPostfix(Player __instance)
		{
			//IL_0174: 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)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: 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_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !ShaperItem.IsEquipped(__instance) || !((Character)__instance).InPlaceMode())
			{
				return;
			}
			if (Time.time >= _nextOpsEnsure)
			{
				_nextOpsEnsure = Time.time + 2f;
				ObjectDBTerrainOpPatch.EnsureRegistered();
			}
			if ((Object)(object)__instance.m_placementGhost == (Object)null || !__instance.m_placementGhost.activeInHierarchy)
			{
				return;
			}
			Piece selectedPiece = __instance.GetSelectedPiece();
			if ((Object)(object)selectedPiece == (Object)null)
			{
				return;
			}
			bool flag = ShapeSettings.Square || (Object)(object)((Component)selectedPiece).gameObject.GetComponent<SquareToolMarker>() != (Object)null || Utils.GetPrefabName(((Object)((Component)selectedPiece).gameObject).name).IndexOf("_sq", StringComparison.OrdinalIgnoreCase) >= 0;
			if (ModConfig.GridFollowPieceRotation.Value && flag && !selectedPiece.m_canRotate)
			{
				selectedPiece.m_canRotate = true;
			}
			Transform transform = __instance.m_placementGhost.transform;
			if (flag && ModConfig.GridFollowPieceRotation.Value && ModConfig.GridRotationSnapDegrees.Value > 0.01f)
			{
				float y = transform.eulerAngles.y;
				float num = RotatedBrush.SnapYaw(y, ModConfig.GridRotationSnapDegrees.Value);
				if (Mathf.Abs(Mathf.DeltaAngle(y, num)) > 0.05f)
				{
					transform.rotation = Quaternion.Euler(0f, num, 0f);
				}
			}
			if (!ModConfig.IsGridSnapActive() || (!flag && !ModConfig.GridSnapAlways.Value))
			{
				return;
			}
			float num2 = Mathf.Max(0.5f, ShapeSettings.Width * 2f);
			Vector3 position = transform.position;
			float y2 = position.y;
			float num3 = (ModConfig.GridFollowPieceRotation.Value ? transform.eulerAngles.y : 0f);
			bool flag2 = Mathf.Abs(Mathf.DeltaAngle(0f, num3)) > 0.5f;
			Vector3 origin = (Vector3)(((??)_anchor) ?? SnapPoint(position, num2, num3, flag2));
			Vector3 val = SnapRelative(position, origin, num2, num3, flag2);
			val.y = y2;
			float num4 = Mathf.Clamp(num2 * 0.4f, 0.75f, 2.5f);
			if (!((val.x - position.x) * (val.x - position.x) + (val.z - position.z) * (val.z - position.z) > num4 * num4))
			{
				position.x = val.x;
				position.z = val.z;
				position.y = y2;
				transform.position = position;
				if ((Object)(object)__instance.m_placementMarkerInstance != (Object)null)
				{
					Vector3 position2 = __instance.m_placementMarkerInstance.transform.position;
					position2.x = position.x;
					position2.z = position.z;
					__instance.m_placementMarkerInstance.transform.position = position2;
				}
				if (Time.time >= _nextHint)
				{
					_nextHint = Time.time + 1.5f;
					string arg = (flag2 ? $", {num3:0}°" : "");
					((Character)__instance).Message((MessageType)1, $"Grid snap ({num2:0.##} m{arg})", 0, (Sprite)null, false);
				}
			}
		}

		private static Vector3 SnapPoint(Vector3 pos, float tile, float yaw, bool rotate)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!rotate)
			{
				return new Vector3(Mathf.Round(pos.x / tile) * tile, 0f, Mathf.Round(pos.z / tile) * tile);
			}
			RotatedBrush.ToLocal(pos.x, pos.z, yaw, out var localX, out var localZ);
			localX = Mathf.Round(localX / tile) * tile;
			localZ = Mathf.Round(localZ / tile) * tile;
			float num = yaw * ((float)Math.PI / 180f);
			float num2 = Mathf.Cos(num);
			float num3 = Mathf.Sin(num);
			return new Vector3(localX * num2 - localZ * num3, 0f, localX * num3 + localZ * num2);
		}

		private static Vector3 SnapRelative(Vector3 pos, Vector3 origin, float tile, float yaw, bool rotate)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!rotate)
			{
				float num = pos.x - origin.x;
				float num2 = pos.z - origin.z;
				return new Vector3(origin.x + Mathf.Round(num / tile) * tile, pos.y, origin.z + Mathf.Round(num2 / tile) * tile);
			}
			RotatedBrush.ToLocal(pos.x - origin.x, pos.z - origin.z, yaw, out var localX, out var localZ);
			localX = Mathf.Round(localX / tile) * tile;
			localZ = Mathf.Round(localZ / tile) * tile;
			float num3 = yaw * ((float)Math.PI / 180f);
			float num4 = Mathf.Cos(num3);
			float num5 = Mathf.Sin(num3);
			return new Vector3(origin.x + localX * num4 - localZ * num5, pos.y, origin.z + localX * num5 + localZ * num4);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "PlacePiece", new Type[]
		{
			typeof(Piece),
			typeof(Vector3),
			typeof(Quaternion),
			typeof(bool),
			typeof(bool)
		})]
		private static void PlacePiecePostfix(Player __instance, Piece piece, Vector3 pos)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ShaperItem.IsEquipped(__instance) && !((Object)(object)piece == (Object)null) && Utils.GetPrefabName(((Object)((Component)piece).gameObject).name).StartsWith("TSP_"))
			{
				_anchor = pos;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdatePostfix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !ShaperItem.IsEquipped(__instance))
			{
				_anchor = null;
			}
		}
	}
	[HarmonyPatch]
	internal static class HeightDeltaModifier
	{
		internal static float CurrentHeightMeters = 1f;

		private static float _nextMsg;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdatePrefix(Player __instance)
		{
			//IL_0034: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !ShaperItem.IsEquipped(__instance) || !((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible() || ModConfig.IsKeyHeld(ModConfig.RadiusModKey.Value) || ModConfig.IsKeyHeld(ModConfig.SharpnessModKey.Value) || !ModConfig.EnableHeightModifier.Value || Input.mouseScrollDelta.y == 0f)
			{
				return;
			}
			Piece selectedPiece = __instance.GetSelectedPiece();
			if ((Object)(object)selectedPiece == (Object)null || (Object)(object)((Component)selectedPiece).gameObject == (Object)null || (Object)(object)((Component)selectedPiece).gameObject.GetComponent<HeightToolMarker>() == (Object)null)
			{
				return;
			}
			TerrainOp componentInChildren = ((Component)selectedPiece).gameObject.GetComponentInChildren<TerrainOp>(true);
			if (!((Object)(object)componentInChildren == (Object)null) && componentInChildren.m_settings.m_raise)
			{
				float value = ModConfig.HeightScrollStep.Value;
				float num = ((Input.mouseScrollDelta.y > 0f) ? value : (0f - value));
				CurrentHeightMeters = Mathf.Clamp(SnapHeight(CurrentHeightMeters + num), 0.5f, 8f);
				ShapeSettings.Height = CurrentHeightMeters;
				ShapeSettings.ApplyToSelectedPiece(__instance);
				ShapeSettings.ApplyToAllRegisteredPieces();
				if (Time.time >= _nextMsg)
				{
					_nextMsg = Time.time + 0.05f;
					string text = Loc.Tf("tsp_msg_height_meters", CurrentHeightMeters);
					((Character)__instance).Message((MessageType)2, text, 0, (Sprite)null, false);
					Plugin.Log.LogInfo((object)text);
				}
			}
		}

		internal static void ApplyHeightToPiece(Piece piece, TerrainOp op)
		{
			bool flag = (Object)(object)((Component)piece).gameObject.GetComponent<LowerTerrainMarker>() != (Object)null || Utils.GetPrefabName(((Object)((Component)piece).gameObject).name).IndexOf("lower", StringComparison.OrdinalIgnoreCase) >= 0;
			op.m_settings.m_raiseDelta = (flag ? (0f - CurrentHeightMeters) : CurrentHeightMeters);
		}

		private static float SnapHeight(float value)
		{
			float num = Mathf.Max(0.05f, ModConfig.HeightScrollStep.Value);
			return Mathf.Round(value / num) * num;
		}
	}
	[HarmonyPatch]
	internal static class HoverInfoPatch
	{
		private static float _nextHover;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static void UpdatePlacementGhostPostfix(Player __instance)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.HoverInfo.Value || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !ShaperItem.IsEquipped(__instance) || !((Character)__instance).InPlaceMode() || (Object)(object)__instance.m_placementGhost == (Object)null)
			{
				return;
			}
			Piece selectedPiece = __instance.GetSelectedPiece();
			if (!((Object)(object)selectedPiece == (Object)null) && !((Object)(object)((Component)selectedPiece).gameObject == (Object)null) && (!((Object)(object)((Component)selectedPiece).gameObject.GetComponent<SquareToolMarker>() == (Object)null) || !((Object)(object)((Component)selectedPiece).gameObject.GetComponent<HeightToolMarker>() == (Object)null)) && !(Time.time < _nextHover))
			{
				_nextHover = Time.time + 0.25f;
				Vector3 position = __instance.m_placementGhost.transform.position;
				float num = position.y;
				float num2 = default(float);
				if (Heightmap.GetHeight(positi