Decompiled source of AdvancedTerrainModifiersCompatible v1.4.8

TerrainTools.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using TerrainTools.Configs;
using TerrainTools.Extensions;
using TerrainTools.Helpers;
using TerrainTools.Visualization;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TerrainTools")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TerrainTools")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.4.8")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.8.0")]
[module: UnverifiableCode]
namespace MVBP.Extensions
{
	internal static class GameObjectExtensions
	{
		internal static GameObject DeepCopy(this GameObject obj)
		{
			bool activeSelf = obj.activeSelf;
			obj.SetActive(false);
			GameObject result = Object.Instantiate<GameObject>(obj);
			obj.SetActive(activeSelf);
			return result;
		}

		public static bool HasAnyComponent(this GameObject gameObject, params Type[] components)
		{
			foreach (Type type in components)
			{
				if (Object.op_Implicit((Object)(object)gameObject.GetComponent(type)))
				{
					return true;
				}
			}
			return false;
		}

		public static bool HasAnyComponent(this GameObject gameObject, params string[] componentNames)
		{
			foreach (string text in componentNames)
			{
				if (Object.op_Implicit((Object)(object)gameObject.GetComponent(text)))
				{
					return true;
				}
			}
			return false;
		}

		public static bool HasAllComponents(this GameObject gameObject, params string[] componentNames)
		{
			foreach (string text in componentNames)
			{
				if (!Object.op_Implicit((Object)(object)gameObject.GetComponent(text)))
				{
					return false;
				}
			}
			return true;
		}

		public static bool HasAllComponents(this GameObject gameObject, params Type[] components)
		{
			foreach (Type type in components)
			{
				if (!Object.op_Implicit((Object)(object)gameObject.GetComponent(type)))
				{
					return false;
				}
			}
			return true;
		}

		public static bool HasAnyComponentInChildren(this GameObject gameObject, bool includeInactive = false, params Type[] components)
		{
			foreach (Type type in components)
			{
				if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren(type, includeInactive)))
				{
					return true;
				}
			}
			return false;
		}

		public static Transform FindDeepChild(this GameObject gameObject, string childName, IterativeSearchType searchType = (IterativeSearchType)1)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return gameObject.transform.FindDeepChild(childName, searchType);
		}

		public static void DestroyComponentsInChildren<T>(this GameObject gameObject, bool includeInactive = false) where T : Component
		{
			T[] componentsInChildren = gameObject.GetComponentsInChildren<T>(includeInactive);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
		}
	}
	internal static class StringExtensions
	{
		internal static bool ContainsAny(this string str, params string[] substrings)
		{
			foreach (string value in substrings)
			{
				if (str.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool EndsWithAny(this string str, params string[] suffixes)
		{
			foreach (string value in suffixes)
			{
				if (str.EndsWith(value))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool StartsWithAny(this string str, params string[] suffixes)
		{
			foreach (string value in suffixes)
			{
				if (str.StartsWith(value))
				{
					return true;
				}
			}
			return false;
		}

		internal static string RemoveSuffix(this string s, string suffix)
		{
			if (s.EndsWith(suffix))
			{
				return s.Substring(0, s.Length - suffix.Length);
			}
			return s;
		}

		internal static string RemovePrefix(this string s, string prefix)
		{
			if (s.StartsWith(prefix))
			{
				return s.Substring(prefix.Length, s.Length - prefix.Length);
			}
			return s;
		}

		internal static string CapitalizeFirstLetter(this string s)
		{
			if (s.Length == 0)
			{
				return s;
			}
			if (s.Length == 1)
			{
				return $"{char.ToUpper(s[0])}";
			}
			return char.ToUpper(s[0]) + s.Substring(1);
		}
	}
	public static class TransformExtensions
	{
		public static Transform FindDeepChild(this Transform transform, string childName, IterativeSearchType searchType = (IterativeSearchType)1)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return Utils.FindChild(transform, childName, searchType);
		}
	}
}
namespace TerrainTools
{
	[BepInPlugin("Searica.Valheim.TerrainTools", "AdvancedTerrainModifiers", "1.4.8")]
	[BepInDependency("com.jotunn.jotunn", "2.30.0")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	internal sealed class TerrainTools : BaseUnityPlugin
	{
		internal const string Author = "Searica";

		public const string PluginName = "AdvancedTerrainModifiers";

		public const string PluginGUID = "Searica.Valheim.TerrainTools";

		public const string PluginVersion = "1.4.8";

		private static readonly string MainSection = ConfigManager.SetStringPriority("Global", 10);

		private static readonly string RadiusSection = ConfigManager.SetStringPriority("Radius", 8);

		private static readonly string HardnessSection = ConfigManager.SetStringPriority("Hardness", 6);

		private static readonly string ShovelSection = ConfigManager.SetStringPriority("Shovel", 4);

		private static readonly string HoeSection = ConfigManager.SetStringPriority("Hoe", 2);

		private static readonly string CultivatorSection = ConfigManager.SetStringPriority("Cultivator", 0);

		internal static bool UpdatePlugin = false;

		private static ConfigEntry<bool> hoverInfoEnabled;

		private static readonly Dictionary<string, ConfigEntry<bool>> ToolConfigEntries = new Dictionary<string, ConfigEntry<bool>>();

		private static ConfigEntry<bool> enableRadiusModifier;

		private static ConfigEntry<KeyCode> radiusModKey;

		private static ConfigEntry<float> radiusScrollScale;

		private static ConfigEntry<float> maxRadius;

		private static ConfigEntry<bool> enableHardnessModifier;

		private static ConfigEntry<KeyCode> hardnessModKey;

		private static ConfigEntry<float> hardnessScrollScale;

		private static ConfigEntry<bool> enableShovel;

		internal static bool IsHoverInforEnabled => hoverInfoEnabled.Value;

		internal static bool IsEnableRadiusModifier => enableRadiusModifier.Value;

		internal static float MaxRadius => maxRadius.Value;

		internal static KeyCode RadiusKey => radiusModKey.Value;

		internal static float RadiusScrollScale => radiusScrollScale.Value;

		internal static bool IsEnableHardnessModifier => enableHardnessModifier.Value;

		internal static KeyCode HardnessKey => hardnessModKey.Value;

		internal static float HardnessScrollScale => hardnessScrollScale.Value;

		internal static bool IsShovelEnabled => enableShovel.Value;

		private static string GetSectionName(string pieceTable)
		{
			if (pieceTable == PieceTables.Hoe)
			{
				return HoeSection;
			}
			if (pieceTable == PieceTables.Cultivator)
			{
				return CultivatorSection;
			}
			if (pieceTable == "_ShovelPieceTable")
			{
				return ShovelSection;
			}
			return MainSection;
		}

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

		public void Awake()
		{
			Log.Init(((BaseUnityPlugin)this).Logger);
			ConfigManager.Init("Searica.Valheim.TerrainTools", ((BaseUnityPlugin)this).Config);
			SetUpConfigEntries();
			RegisterTranslations();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.TerrainTools");
			Game.isModded = true;
			PrefabManager.OnVanillaPrefabsAvailable += Shovel.CreateShovel;
			PieceManager.OnPiecesRegistered += InitManager.InitToolPieces;
			_ = GUIManager.Instance;
			ConfigManager.SetupWatcher();
			ConfigManager.CheckForConfigManager();
			ConfigManager.OnConfigFileReloaded += delegate
			{
				if (UpdatePlugin)
				{
					InitManager.UpdatePlugin();
					UpdatePlugin = false;
				}
			};
			ConfigManager.OnConfigWindowClosed += delegate
			{
				if (UpdatePlugin)
				{
					InitManager.UpdatePlugin();
				}
			};
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				if (UpdatePlugin)
				{
					InitManager.UpdatePlugin();
					UpdatePlugin = false;
				}
			};
		}

		private void RegisterTranslations()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			string[] array = new string[2] { "English", "Russian" };
			foreach (string text in array)
			{
				localization.AddJsonFile(text, AssetUtils.LoadTextFromResources("TerrainTools.Translations." + text + ".json", executingAssembly));
				if (string.IsNullOrEmpty(directoryName))
				{
					continue;
				}
				string text2 = Path.Combine(directoryName, "Translations", "TerrainTools", text, "translations.json");
				try
				{
					if (File.Exists(text2))
					{
						localization.AddFileByPath(text2, true);
					}
				}
				catch (Exception ex)
				{
					Log.LogWarning("Could not load external " + text + " translations: " + ex.Message);
				}
			}
		}

		private void Update()
		{
			RadiusModifier.Tick(Player.m_localPlayer);
			HardnessModifier.Tick(Player.m_localPlayer);
		}

		public void OnDestroy()
		{
			ConfigManager.Save();
		}

		internal static void SetUpConfigEntries()
		{
			Log.Verbosity = ConfigManager.BindConfig(MainSection, "Verbosity", LogLevel.Low, "Low will log basic information about the mod. Medium will log information that is useful for troubleshooting. High will log a lot of information, do not set it to this without good reason as it will slow Down your game.", null, synced: false);
			hoverInfoEnabled = ConfigManager.BindConfig(MainSection, "HoverInfo", value: true, "Set to true/enabled to show terrain height when using square terrain tools.");
			enableRadiusModifier = ConfigManager.BindConfig(RadiusSection, ConfigManager.SetStringPriority("RadiusModifier", 1), value: true, "Set to true/enabled to allow modifying the radius of terrain tools using the scroll wheel. Note: Radius cannot be changed on square tools except terrain restoration.");
			radiusModKey = ConfigManager.BindConfig<KeyCode>(RadiusSection, "RadiusModKey", (KeyCode)308, "Modifier key that must be held down when using scroll wheel to change the radius of terrain tools.", null, synced: false);
			radiusScrollScale = ConfigManager.BindConfig(RadiusSection, "RadiusScrollScale", 0.1f, "Scroll wheel change scale, larger magnitude means the radius will change faster and negative sign will reverse the direction you need to scroll to increase the radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), synced: false);
			maxRadius = ConfigManager.BindConfig(RadiusSection, "MaxRadius", 10f, "Maximum radius of terrain tools.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 20f));
			enableHardnessModifier = ConfigManager.BindConfig(HardnessSection, ConfigManager.SetStringPriority("HardnessModifier", 1), value: true, "Use the modifier key and scroll wheel to adjust round terrain-tool hardness and Precise Raise slopes.");
			hardnessModKey = ConfigManager.BindConfig<KeyCode>(HardnessSection, "HardnessModKey", (KeyCode)306, "Modifier key that must be held down when using scroll wheel to change the hardness of terrain tools.", null, synced: false);
			hardnessScrollScale = ConfigManager.BindConfig(HardnessSection, "HardnessScrollScale", 1f, "Scroll wheel change scale, larger magnitude means the hardness will change faster and negative sign will reverse the direction you need to scroll to increase the hardness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), synced: false);
			enableShovel = ConfigManager.BindConfig(ShovelSection, ConfigManager.SetStringPriority("Shovel", 1), value: true, "Set to true/enabled to allow crafting the shovel. Setting to false/disabled will prevent crafting new shovels but will not affect existing shovels in the world.");
			enableShovel.SettingChanged += SetUpdatePlugin;
			foreach (string key in ToolConfigs.ToolConfigsMap.Keys)
			{
				ConfigEntry<bool> val = ConfigManager.BindConfig(GetSectionName(ToolConfigs.ToolConfigsMap[key].pieceTable), key, value: true, "Set to true/enabled to add this terrain tool. Set to false/disabled to remove it.");
				val.SettingChanged += SetUpdatePlugin;
				ToolConfigEntries.Add(key, val);
			}
			ConfigManager.Save();
		}

		private static void SetUpdatePlugin(object obj, EventArgs e)
		{
			UpdatePlugin = true;
		}
	}
	internal enum LogLevel
	{
		Low,
		Medium,
		High
	}
	internal static class Log
	{
		private static ManualLogSource logSource;

		internal static ConfigEntry<LogLevel> Verbosity { get; set; }

		internal static LogLevel VerbosityLevel => Verbosity.Value;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void LogDebug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void LogError(object data)
		{
			logSource.LogError(data);
		}

		internal static void LogFatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void LogMessage(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void LogWarning(object data)
		{
			logSource.LogWarning(data);
		}

		internal static void LogInfo(object data, LogLevel level = LogLevel.Low)
		{
			if (Verbosity == null || VerbosityLevel >= level)
			{
				logSource.LogInfo(data);
			}
		}

		internal static void LogGameObject(GameObject prefab, bool includeChildren = false)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			LogInfo("***** " + ((Object)prefab).name + " *****");
			Component[] components = prefab.GetComponents<Component>();
			for (int i = 0; i < components.Length; i++)
			{
				LogComponent(components[i]);
			}
			if (!includeChildren)
			{
				return;
			}
			LogInfo("***** " + ((Object)prefab).name + " (children) *****");
			foreach (Transform item in prefab.transform)
			{
				Transform val = item;
				LogInfo(" - " + ((Object)((Component)val).gameObject).name);
				components = ((Component)val).gameObject.GetComponents<Component>();
				for (int i = 0; i < components.Length; i++)
				{
					LogComponent(components[i]);
				}
			}
		}

		internal static void LogComponent(Component compo)
		{
			LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---");
			PropertyInfo[] properties = ((object)compo).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
			foreach (PropertyInfo propertyInfo in properties)
			{
				LogInfo($" - {propertyInfo.Name} = {propertyInfo.GetValue(compo)}");
			}
			FieldInfo[] fields = ((object)compo).GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
			foreach (FieldInfo fieldInfo in fields)
			{
				LogInfo($" - {fieldInfo.Name} = {fieldInfo.GetValue(compo)}");
			}
		}
	}
}
namespace TerrainTools.Visualization
{
	public class HoverInfo
	{
		private readonly GameObject _gameObject;

		private readonly Transform _transform;

		private readonly TextMesh _textMesh;

		public string Text
		{
			get
			{
				return _textMesh.text;
			}
			set
			{
				_textMesh.text = value;
			}
		}

		public bool Enabled
		{
			get
			{
				return _gameObject.activeSelf;
			}
			set
			{
				_gameObject.SetActive(value);
			}
		}

		public Color Color
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return _textMesh.color;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				_textMesh.color = value;
			}
		}

		public HoverInfo(Transform parentTransform)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_004f: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			_gameObject = new GameObject();
			_gameObject.transform.parent = parentTransform;
			_transform = _gameObject.transform;
			_textMesh = _gameObject.AddComponent<TextMesh>();
			((Component)_textMesh).transform.localPosition = Vector3.zero;
			((Component)_textMesh).transform.localScale = new Vector3(0.1f / parentTransform.localScale.x, 0.1f / parentTransform.localScale.y, 0.1f / parentTransform.localScale.z);
			_textMesh.anchor = (TextAnchor)4;
			_textMesh.alignment = (TextAlignment)1;
			_textMesh.fontSize = 16;
		}

		public void RotateToPlayer()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(((Component)GameCamera.m_instance).transform.position.x, _transform.position.y, ((Component)GameCamera.m_instance).transform.position.z);
			_transform.LookAt(val, Vector3.up);
			_transform.Rotate(90f, 180f, 0f);
		}
	}
	internal static class IconCache
	{
		private static Texture2D _remove;

		private static Texture2D _cross;

		private static Texture2D _undo;

		private static Texture2D _redo;

		private static Texture2D _box;

		private static Texture2D _pavedRoadSquare;

		private static Texture2D _pavedRoadPath;

		private static Texture2D _pavedRoadPathSquare;

		private static Texture2D _mudRoadSquare;

		private static Texture2D _mudRoadPathSquare;

		private static Texture2D _replantSquare;

		private static Texture2D _cultivateSquare;

		private static Texture2D _cultivatePath;

		private static Texture2D _cultivatePathSquare;

		private static Texture2D _raiseSquare;

		private static Texture2D _lower;

		private static Texture2D _shovel;

		internal static Texture2D Shovel
		{
			get
			{
				if ((Object)(object)_shovel == (Object)null)
				{
					_shovel = LoadTextureFromResources("ShovelIcon.png");
				}
				return _shovel;
			}
		}

		internal static Texture2D Lower
		{
			get
			{
				if ((Object)(object)_lower == (Object)null)
				{
					_lower = LoadTextureFromResources("lower_v2.png");
				}
				return _lower;
			}
		}

		internal static Texture2D CultivateSquare
		{
			get
			{
				if ((Object)(object)_cultivateSquare == (Object)null)
				{
					_cultivateSquare = LoadTextureFromResources("cultivate_v2_square.png");
				}
				return _cultivateSquare;
			}
		}

		internal static Texture2D CultivatePathSquare
		{
			get
			{
				if ((Object)(object)_cultivatePathSquare == (Object)null)
				{
					_cultivatePathSquare = LoadTextureFromResources("cultivate_v2_path_square.png");
				}
				return _cultivatePathSquare;
			}
		}

		internal static Texture2D CultivatePath
		{
			get
			{
				if ((Object)(object)_cultivatePath == (Object)null)
				{
					_cultivatePath = LoadTextureFromResources("cultivate_v2_path.png");
				}
				return _cultivatePath;
			}
		}

		internal static Texture2D ReplantSquare
		{
			get
			{
				if ((Object)(object)_replantSquare == (Object)null)
				{
					_replantSquare = LoadTextureFromResources("replant_v2_square.png");
				}
				return _replantSquare;
			}
		}

		internal static Texture2D RaiseSquare
		{
			get
			{
				if ((Object)(object)_raiseSquare == (Object)null)
				{
					_raiseSquare = LoadTextureFromResources("raise_v2_square.png");
				}
				return _raiseSquare;
			}
		}

		internal static Texture2D MudRoadPathSquare
		{
			get
			{
				if ((Object)(object)_mudRoadPathSquare == (Object)null)
				{
					_mudRoadPathSquare = LoadTextureFromResources("path_v2_square.png");
				}
				return _mudRoadPathSquare;
			}
		}

		internal static Texture2D MudRoadSquare
		{
			get
			{
				if ((Object)(object)_mudRoadSquare == (Object)null)
				{
					_mudRoadSquare = LoadTextureFromResources("mud_road_v2_square.png");
				}
				return _mudRoadSquare;
			}
		}

		internal static Texture2D PavedRoadPath
		{
			get
			{
				if ((Object)(object)_pavedRoadPath == (Object)null)
				{
					_pavedRoadPath = LoadTextureFromResources("paved_road_v2_path.png");
				}
				return _pavedRoadPath;
			}
		}

		internal static Texture2D PavedRoadPathSquare
		{
			get
			{
				if ((Object)(object)_pavedRoadPathSquare == (Object)null)
				{
					_pavedRoadPathSquare = LoadTextureFromResources("paved_road_v2_path_square.png");
				}
				return _pavedRoadPathSquare;
			}
		}

		internal static Texture2D PavedRoadSquare
		{
			get
			{
				if ((Object)(object)_pavedRoadSquare == (Object)null)
				{
					_pavedRoadSquare = LoadTextureFromResources("paved_road_v2_square.png");
				}
				return _pavedRoadSquare;
			}
		}

		internal static Texture2D Remove
		{
			get
			{
				if ((Object)(object)_remove == (Object)null)
				{
					_remove = LoadTextureFromResources("remove.png");
				}
				return _remove;
			}
		}

		internal static Texture2D Cross
		{
			get
			{
				if ((Object)(object)_cross == (Object)null)
				{
					_cross = LoadTextureFromResources("cross.png");
				}
				return _cross;
			}
		}

		internal static Texture2D Undo
		{
			get
			{
				if ((Object)(object)_undo == (Object)null)
				{
					_undo = LoadTextureFromResources("undo.png");
				}
				return _undo;
			}
		}

		internal static Texture2D Redo
		{
			get
			{
				if ((Object)(object)_redo == (Object)null)
				{
					_redo = LoadTextureFromResources("redo.png");
				}
				return _redo;
			}
		}

		internal static Texture2D Box
		{
			get
			{
				if ((Object)(object)_box == (Object)null)
				{
					_box = LoadTextureFromResources("box.png");
				}
				return _box;
			}
		}

		internal static Sprite LoadEmbeddedTextureAsSprite(string fileName)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadTextureFromResources(fileName);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			float num = 100f;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), val2, num);
		}

		internal static Texture2D LoadTextureFromResources(string fileName)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			string text = Path.GetExtension(fileName).ToLower();
			if (text != ".png" && text != ".jpg")
			{
				Log.LogWarning("LoadTextureFromResources can only load png or jpg textures");
				return null;
			}
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text2 = (from name in executingAssembly.GetManifestResourceNames()
				where name.EndsWith("." + fileName, StringComparison.OrdinalIgnoreCase)
				select name).FirstOrDefault();
			if (text2 == null)
			{
				Log.LogWarning("Embedded texture not found: " + fileName);
				return null;
			}
			using Stream stream = executingAssembly.GetManifestResourceStream(text2);
			if (stream == null)
			{
				Log.LogWarning("Could not open embedded texture: " + text2);
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			Texture2D val = new Texture2D(0, 0);
			object obj = ((Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule") ?? (from assembly in AppDomain.CurrentDomain.GetAssemblies()
				select assembly.GetType("UnityEngine.ImageConversion")).FirstOrDefault((Type type) => type != null))?.GetMethod("LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}))?.Invoke(null, new object[2]
			{
				val,
				memoryStream.ToArray()
			});
			if (!(obj is bool) || !(bool)obj)
			{
				Log.LogWarning("Could not decode embedded texture: " + text2);
				return null;
			}
			return val;
		}
	}
	public class Overlay
	{
		private Particle[] particles = (Particle[])(object)new Particle[2];

		private GameObject GameObject { get; }

		private Transform Transform { get; }

		public ParticleSystem ps { get; }

		public ParticleSystemRenderer psr { get; }

		public MainModule psm { get; }

		public bool Enabled
		{
			get
			{
				return GameObject.activeSelf;
			}
			set
			{
				GameObject.SetActive(value);
			}
		}

		public Vector3 Position
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return Transform.position;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				Transform.position = value;
			}
		}

		public Vector3 LocalPosition
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return Transform.localPosition;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				Transform.localPosition = value;
			}
		}

		public Quaternion Rotation
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return Transform.rotation;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				Transform.rotation = value;
			}
		}

		public Color Color
		{
			get
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				int num = ps.GetParticles(particles, particles.Length);
				if (num <= 0)
				{
					return StartColor;
				}
				return Color32.op_Implicit(((Particle)(ref particles[Mathf.Min(1, num - 1)])).GetCurrentColor(ps));
			}
		}

		public Color StartColor
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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_0011: Unknown result type (might be due to invalid IL or missing references)
				MainModule val = psm;
				MinMaxGradient startColor = ((MainModule)(ref val)).startColor;
				return ((MinMaxGradient)(ref startColor)).color;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				MainModule val = psm;
				((MainModule)(ref val)).startColor = MinMaxGradient.op_Implicit(value);
			}
		}

		public Vector3 LocalScale
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return Transform.localScale;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				Transform.localScale = value;
			}
		}

		public float StartSize
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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)
				MainModule val = psm;
				MinMaxCurve startSize = ((MainModule)(ref val)).startSize;
				return ((MinMaxCurve)(ref startSize)).constant;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				MainModule val = psm;
				MinMaxCurve startSize = ((MainModule)(ref val)).startSize;
				if (!Mathf.Approximately(((MinMaxCurve)(ref startSize)).constant, value))
				{
					MainModule main = ps.main;
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(value);
					if (particles.Length < ps.particleCount)
					{
						particles = (Particle[])(object)new Particle[ps.particleCount];
					}
					int num = ps.GetParticles(particles, particles.Length);
					for (int i = 0; i < num; i++)
					{
						((Particle)(ref particles[i])).startSize = value;
					}
					if (num > 0)
					{
						ps.SetParticles(particles, num);
					}
				}
			}
		}

		public float StartSpeed
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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)
				MainModule val = psm;
				MinMaxCurve startSpeed = ((MainModule)(ref val)).startSpeed;
				return ((MinMaxCurve)(ref startSpeed)).constant;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				MainModule main = ps.main;
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(value);
			}
		}

		public float StartLifetime
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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)
				MainModule val = psm;
				MinMaxCurve startLifetime = ((MainModule)(ref val)).startLifetime;
				return ((MinMaxCurve)(ref startLifetime)).constant;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				MainModule main = ps.main;
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(value);
			}
		}

		public bool SizeOverLifetimeEnabled
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime;
				return ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime;
				((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = value;
			}
		}

		public MinMaxCurve SizeOverLifetime
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime;
				return ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size;
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime;
				((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = value;
			}
		}

		public Overlay(Transform transform)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			Transform = transform;
			GameObject = ((Component)transform).gameObject;
			ps = ((Component)transform).GetComponentInChildren<ParticleSystem>();
			psr = ((Component)transform).GetComponentInChildren<ParticleSystemRenderer>();
			psm = ps.main;
		}
	}
	public abstract class OverlayVisualizer : MonoBehaviour
	{
		protected Overlay primary;

		protected Overlay secondary;

		protected Overlay tertiary;

		protected HoverInfo hoverInfo;

		private readonly List<Heightmap> heightmaps = new List<Heightmap>();

		internal static readonly Vector3 VerticalOffset = new Vector3(0f, 0.075f, 0f);

		internal void Refresh()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (primary == null)
			{
				Transform val = ((Component)this).transform.Find("_GhostOnly");
				Transform val2 = Object.Instantiate<Transform>(val, ((Component)this).transform);
				Transform transform = Object.Instantiate<Transform>(val2, ((Component)this).transform);
				primary = new Overlay(val);
				secondary = new Overlay(val2);
				tertiary = new Overlay(transform);
				hoverInfo = new HoverInfo(val2);
				tertiary.StartColor = Color.white;
				primary.Enabled = false;
				secondary.Enabled = false;
				tertiary.Enabled = false;
				Initialize();
			}
			OnRefresh();
		}

		protected abstract void Initialize();

		protected abstract void OnRefresh();

		protected void SpeedUp(Overlay overlay)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			AnimationCurve val = new AnimationCurve();
			val.AddKey(0f, 0f);
			val.AddKey(0.5f, 1f);
			MinMaxCurve sizeOverLifetime = default(MinMaxCurve);
			((MinMaxCurve)(ref sizeOverLifetime))..ctor(1f, val);
			overlay.StartLifetime = 2f;
			overlay.SizeOverLifetime = sizeOverLifetime;
		}

		protected void Freeze(Overlay overlay)
		{
			overlay.StartSpeed = 0f;
			overlay.SizeOverLifetimeEnabled = false;
		}

		protected void VisualizeTerraformingBounds(Overlay overlay)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			overlay.StartSize = 3f;
			((Renderer)overlay.psr).material.mainTexture = (Texture)(object)IconCache.Box;
			overlay.LocalPosition = VerticalOffset;
		}

		protected void VisualizeIconInsideTerraformingBounds(Overlay overlay, Texture iconTexture)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			overlay.StartSize = 2.5f;
			((Renderer)overlay.psr).material.mainTexture = iconTexture;
			overlay.LocalPosition = VerticalOffset;
		}

		protected void VisualizeRecoloringBounds(Overlay overlay)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			overlay.StartSize = 3f;
			((Renderer)overlay.psr).material.mainTexture = (Texture)(object)IconCache.Box;
			overlay.LocalPosition = VerticalOffset;
		}

		protected void SnapToPaintGrid(Overlay core, Overlay feather)
		{
			//IL_0011: 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_003f: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: 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_0140: 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)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			heightmaps.Clear();
			Heightmap.FindHeightmap(((Component)this).transform.position, 1f, heightmaps);
			if (heightmaps.Count == 0)
			{
				core.LocalPosition = VerticalOffset;
				feather.LocalPosition = VerticalOffset;
				return;
			}
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(float.PositiveInfinity, float.PositiveInfinity);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(float.NegativeInfinity, float.NegativeInfinity);
			float num = 0f;
			foreach (Heightmap heightmap in heightmaps)
			{
				if (PreciseTerrainModifier.TryGetPaintMaskWorldBounds(heightmap, ((Component)this).transform.position, 1, out var min, out var max))
				{
					val = Vector2.Min(val, min);
					val2 = Vector2.Max(val2, max);
					num = Mathf.Max(num, heightmap.m_scale);
				}
			}
			if (float.IsPositiveInfinity(val.x))
			{
				core.LocalPosition = VerticalOffset;
				feather.LocalPosition = VerticalOffset;
			}
			else
			{
				SetBounds(core, val - Vector2.one * num, val2 + Vector2.one * num);
				SetBounds(feather, val - Vector2.one * num * 2f, val2 + Vector2.one * num * 2f);
			}
		}

		private void SetBounds(Overlay overlay, Vector2 min, Vector2 max)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = max - min;
			float num = (overlay.StartSize = Mathf.Max(val.x, val.y));
			overlay.LocalScale = new Vector3(val.x / num, 1f, val.y / num);
			overlay.Position = new Vector3((min.x + max.x) * 0.5f, ((Component)this).transform.position.y + VerticalOffset.y, (min.y + max.y) * 0.5f);
		}

		protected void VisualizeIconInsideRecoloringBounds(Overlay overlay, Texture iconTexture)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			overlay.StartSize = 2.5f;
			((Renderer)overlay.psr).material.mainTexture = iconTexture;
			overlay.Position = ((Component)this).transform.position + VerticalOffset;
		}
	}
	public abstract class HoverInfoEnabled : OverlayVisualizer
	{
		protected override void Initialize()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			hoverInfo.Color = secondary.StartColor;
		}

		protected override void OnRefresh()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			hoverInfo.Enabled = TerrainTools.IsHoverInforEnabled;
			if (hoverInfo.Enabled)
			{
				hoverInfo.RotateToPlayer();
				Vector3 position = ((Component)this).transform.position;
				hoverInfo.Text = $"x: {position.x:0}, y: {position.y:0.000}, z: {position.z:0}";
			}
		}
	}
	[HarmonyPatch(typeof(Piece), "SetInvalidPlacementHeightlight")]
	public static class OverlayVisualizationRedshiftHeigthlightBlocker
	{
		private static bool Prefix(Piece __instance)
		{
			return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponentInChildren<OverlayVisualizer>());
		}
	}
	public class LevelGroundOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			base.Initialize();
			Freeze(secondary);
			Freeze(tertiary);
			VisualizeRecoloringBounds(secondary);
			VisualizeRecoloringBounds(tertiary);
			tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f);
		}

		protected override void OnRefresh()
		{
			SnapToPaintGrid(secondary, tertiary);
			base.OnRefresh();
			primary.Enabled = false;
			secondary.Enabled = true;
			tertiary.Enabled = true;
		}
	}
	public class RaiseGroundOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			//IL_003c: 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)
			base.Initialize();
			Freeze(secondary);
			Freeze(tertiary);
			VisualizeTerraformingBounds(secondary);
			VisualizeTerraformingBounds(tertiary);
			secondary.LocalScale = Vector3.one;
			tertiary.LocalScale = Vector3.one;
		}

		protected override void OnRefresh()
		{
			//IL_0006: 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)
			//IL_00a0: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: 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_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			Heightmap val = Heightmap.FindHeightmap(((Component)this).transform.position);
			float num = (Object.op_Implicit((Object)(object)val) ? val.m_scale : 1f);
			float num2 = PreciseRaiseMath.SlopePivot(HardnessModifier.CurrentRaisePower(((Component)this).GetComponent<TerrainOp>().m_settings.m_raisePower));
			secondary.StartSize = Mathf.Max(0.1f, 2f * num2 * num);
			tertiary.StartSize = 4f * num;
			base.OnRefresh();
			primary.Enabled = false;
			secondary.Enabled = true;
			GroundLevelSpinner.Refresh();
			Vector3 localPosition = secondary.LocalPosition;
			localPosition.y = OverlayVisualizer.VerticalOffset.y + GroundLevelSpinner.Value;
			secondary.LocalPosition = localPosition;
			Vector3 val2 = secondary.Position - OverlayVisualizer.VerticalOffset;
			if (GroundLevelSpinner.Value > 0f)
			{
				float value = GroundLevelSpinner.Value;
				hoverInfo.Text = $"x: {val2.x:0}, y: {val2.y - value:0.000}, z: {val2.z:0}\n\nh: +{value:0.000}";
			}
			else
			{
				hoverInfo.Text = $"x: {val2.x:0}, y: {val2.y:0.000}, z: {val2.z:0}";
			}
			tertiary.Enabled = true;
		}
	}
	public class SquarePathOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			base.Initialize();
			Freeze(secondary);
			Freeze(tertiary);
			VisualizeRecoloringBounds(secondary);
			VisualizeRecoloringBounds(tertiary);
			tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f);
		}

		protected override void OnRefresh()
		{
			SnapToPaintGrid(secondary, tertiary);
			base.OnRefresh();
			primary.Enabled = false;
			secondary.Enabled = true;
			tertiary.Enabled = true;
		}
	}
	public class CultivateOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			base.Initialize();
			Freeze(secondary);
			Freeze(tertiary);
			VisualizeRecoloringBounds(secondary);
			VisualizeRecoloringBounds(tertiary);
			tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f);
		}

		protected override void OnRefresh()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			SnapToPaintGrid(secondary, tertiary);
			base.OnRefresh();
			primary.Enabled = false;
			secondary.Enabled = true;
			tertiary.Enabled = true;
			hoverInfo.Color = secondary.Color;
		}
	}
	public class SeedGrassOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			//IL_0050: 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)
			base.Initialize();
			Freeze(secondary);
			Freeze(tertiary);
			VisualizeRecoloringBounds(secondary);
			VisualizeRecoloringBounds(tertiary);
			tertiary.StartColor = new Color(1f, 1f, 1f, 0.3f);
			primary.StartSize = 4f;
			primary.LocalPosition = new Vector3(0f, 2.5f, 0f);
		}

		protected override void OnRefresh()
		{
			SnapToPaintGrid(secondary, tertiary);
			base.OnRefresh();
			primary.Enabled = true;
			secondary.Enabled = true;
			tertiary.Enabled = true;
		}
	}
	public class RemoveModificationsOverlayVisualizer : OverlayVisualizer
	{
		internal void SetScale(Vector3 scale)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (primary != null && !(scale == Vector3.zero))
			{
				primary.LocalScale = scale;
				secondary.LocalScale = scale;
			}
		}

		protected override void Initialize()
		{
			Freeze(primary);
			SpeedUp(secondary);
			VisualizeTerraformingBounds(primary);
			VisualizeIconInsideTerraformingBounds(secondary, (Texture)(object)IconCache.Cross);
			primary.StartSize = 2f;
			secondary.StartSize = 1.5f;
		}

		protected override void OnRefresh()
		{
			primary.Enabled = true;
			secondary.Enabled = true;
		}
	}
	public abstract class UndoRedoModificationsOverlayVisualizer : OverlayVisualizer
	{
		protected override void Initialize()
		{
			Freeze(primary);
			Freeze(secondary);
			VisualizeRecoloringBounds(primary);
			VisualizeIconInsideRecoloringBounds(secondary, (Texture)(object)Icon());
		}

		protected override void OnRefresh()
		{
			primary.Enabled = true;
			secondary.Enabled = true;
		}

		protected abstract Texture2D Icon();
	}
	public class UndoModificationsOverlayVisualizer : UndoRedoModificationsOverlayVisualizer
	{
		protected override Texture2D Icon()
		{
			return IconCache.Undo;
		}
	}
	public class RedoModificationsOverlayVisualizer : UndoRedoModificationsOverlayVisualizer
	{
		protected override Texture2D Icon()
		{
			return IconCache.Redo;
		}
	}
}
namespace TerrainTools.Patches
{
	[HarmonyPatch(typeof(GameCamera))]
	internal static class GameCameraPatch
	{
		[HarmonyTranspiler]
		[HarmonyPatch("UpdateCamera")]
		private static IEnumerable<CodeInstruction> UpdateCameraTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo target = AccessTools.Method(typeof(Player), "CanRotatePiece", (Type[])null, (Type[])null);
			List<(CodeInstruction, int)> list2 = (from item in list.Select((CodeInstruction instruction, int index) => (instruction: instruction, index: index))
				where item.instruction.opcode == OpCodes.Callvirt && object.Equals(item.instruction.operand, target)
				select item).ToList();
			if (list2.Count != 1)
			{
				Log.LogWarning($"GameCamera.UpdateCamera patch skipped: expected one CanRotatePiece call, found {list2.Count}");
				return list;
			}
			CodeInstruction val = Transpilers.EmitDelegate<Func<Player, bool>>((Func<Player, bool>)UpdateCamera_BlockScroll_Delegate);
			val.labels.AddRange(list2[0].Item1.labels);
			val.blocks.AddRange(list2[0].Item1.blocks);
			list[list2[0].Item2] = val;
			return list;
		}

		private static bool UpdateCamera_BlockScroll_Delegate(Player localPlayer)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			Piece val = ((localPlayer != null) ? localPlayer.GetSelectedPiece() : null);
			if ((Object)(object)((val != null) ? ((Component)val).gameObject : null) != (Object)null && (Object.op_Implicit((Object)(object)((Component)val).gameObject.GetComponentInChildren<RaiseGroundOverlayVisualizer>()) || (TerrainTools.IsEnableRadiusModifier && Input.GetKey(TerrainTools.RadiusKey)) || (TerrainTools.IsEnableHardnessModifier && Input.GetKey(TerrainTools.HardnessKey))))
			{
				return true;
			}
			return localPlayer.CanRotatePiece();
		}
	}
	[HarmonyPatch(typeof(Heightmap), "RebuildRenderMesh")]
	internal static class HeightmapPaintGridPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Heightmap __instance)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.m_isDistantLod || !Object.op_Implicit((Object)(object)__instance.m_renderMesh))
			{
				return;
			}
			int num = __instance.m_width + 1;
			List<Vector2> s_tempUVs = Heightmap.s_tempUVs;
			if (num <= 1 || __instance.m_renderMesh.vertexCount != num * num || s_tempUVs.Count != num * num)
			{
				Log.LogWarning("Paint grid UV alignment skipped: unexpected Heightmap mesh dimensions.");
				return;
			}
			for (int i = 0; i < s_tempUVs.Count; i++)
			{
				s_tempUVs[i] = new Vector2(PaintGridMath.TexelCenterUv(i % num, __instance.m_width), PaintGridMath.TexelCenterUv(i / num, __instance.m_width));
			}
			__instance.m_renderMesh.SetUVs(0, s_tempUVs);
		}
	}
	[HarmonyPatch]
	internal class PlayerPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static void UpdatePlacementGhostPostfix(Player __instance)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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)
			if (!Object.op_Implicit((Object)(object)__instance) || !((Character)__instance).InPlaceMode() || ((Character)__instance).IsDead() || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)__instance.m_placementGhost) || !__instance.m_placementGhost.activeInHierarchy)
			{
				return;
			}
			OverlayVisualizer component = __instance.m_placementGhost.GetComponent<OverlayVisualizer>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			Vector3 position = __instance.m_placementGhost.transform.position;
			Heightmap val = Heightmap.FindHeightmap(position);
			if (Object.op_Implicit((Object)(object)val))
			{
				int num = default(int);
				int num2 = default(int);
				val.WorldToVertex(position, ref num, ref num2);
				position.x = ((Component)val).transform.position.x + (float)(num - val.m_width / 2) * val.m_scale;
				position.z = ((Component)val).transform.position.z + (float)(num2 - val.m_width / 2) * val.m_scale;
				__instance.m_placementGhost.transform.position = position;
				TerrainOp component2 = __instance.m_placementGhost.GetComponent<TerrainOp>();
				if (Object.op_Implicit((Object)(object)component2) && !PreciseTerrainModifier.HasAreaAccess(component2, position, flash: false))
				{
					__instance.m_placementStatus = (PlacementStatus)4;
				}
				component.Refresh();
				RadiusModifier.RefreshGhostScale(__instance);
			}
		}
	}
}
namespace TerrainTools.Helpers
{
	public static class GroundLevelSpinner
	{
		public const string MouseScrollWheel = "Mouse ScrollWheel";

		public const float ScrollPrecision = 0.05f;

		public const float SuperiorScrollPrecisionMultiplier = 0.2f;

		public const float MaxSpinner = 1f;

		public const float MinSpinner = 0f;

		private static int lastRefreshFrame = -1;

		public static float Value { get; private set; } = 1f;

		public static void Refresh()
		{
			if (lastRefreshFrame != Time.frameCount)
			{
				lastRefreshFrame = Time.frameCount;
				float num = ScrollDelta();
				if (num > 0f)
				{
					Up(num);
				}
				if (num < 0f)
				{
					Down(num);
				}
			}
		}

		private static float ScrollDelta()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (TerrainTools.IsEnableHardnessModifier && Input.GetKey(TerrainTools.HardnessKey))
			{
				return 0f;
			}
			float num = Input.GetAxis("Mouse ScrollWheel");
			if (num != 0f)
			{
				num = ((num > 0f) ? 0.05f : (-0.05f));
			}
			return num;
		}

		private static void Up(float scrollDelta)
		{
			if (Value + scrollDelta > 1f)
			{
				Value = 1f;
			}
			else
			{
				Value = Mathf.Round((Value + scrollDelta) * 100f) / 100f;
			}
		}

		private static void Down(float scrollDelta)
		{
			if (Value + scrollDelta < 0f)
			{
				Value = 0f;
			}
			else
			{
				Value = Mathf.Round((Value + scrollDelta) * 100f) / 100f;
			}
		}
	}
	[HarmonyPatch]
	internal static class HardnessModifier
	{
		private static bool SmoothToolIsInUse;

		private static float lastModdedSmoothPwr;

		private static float lastTotalSmoothDelta;

		private const float MinSmoothPwr = 1f;

		private const float MaxSmoothPwr = 30f;

		private static bool RaiseToolIsInUse;

		private static TerrainOp activeRaiseTool;

		private static float lastModdedRaisePwr;

		private static float lastTotalRaiseDelta;

		private const float MinRaisePwr = 0.05f;

		private const float MaxRaisePwr = 1f;

		private const float DisplayThreshold = 0.9f;

		private static float lastDisplayedSmoothHardness;

		private static float lastDisplayedRaiseHardness;

		internal static void Tick(Player __instance)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if (!((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible())
			{
				if (SmoothToolIsInUse)
				{
					SmoothToolIsInUse = false;
					lastModdedSmoothPwr = 0f;
					lastTotalSmoothDelta = 0f;
					lastDisplayedSmoothHardness = -1f;
				}
				SelectRaiseTool(null);
			}
			else
			{
				Piece selectedPiece = __instance.GetSelectedPiece();
				TerrainOp val = ((Object.op_Implicit((Object)(object)selectedPiece) && Object.op_Implicit((Object)(object)((Component)selectedPiece).gameObject)) ? ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>() : null);
				SelectRaiseTool((Object.op_Implicit((Object)(object)val) && val.m_settings.m_raise) ? val : null);
				if (ShouldModifyHardness())
				{
					SetPower(__instance, Input.mouseScrollDelta.y * TerrainTools.HardnessScrollScale);
				}
			}
		}

		internal static bool ShouldModifyHardness()
		{
			//IL_0007: 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)
			if (TerrainTools.IsEnableHardnessModifier && Input.GetKey(TerrainTools.HardnessKey))
			{
				return Input.mouseScrollDelta.y != 0f;
			}
			return false;
		}

		internal static float CurrentRaisePower(float defaultPower)
		{
			if (!RaiseToolIsInUse)
			{
				return ModifyRaisePower(defaultPower, 0f);
			}
			return lastModdedRaisePwr;
		}

		private static void SelectRaiseTool(TerrainOp terrainOp)
		{
			if (!((Object)(object)activeRaiseTool == (Object)(object)terrainOp))
			{
				activeRaiseTool = terrainOp;
				RaiseToolIsInUse = false;
				lastModdedRaisePwr = 0f;
				lastTotalRaiseDelta = 0f;
				lastDisplayedRaiseHardness = -1f;
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(600)]
		[HarmonyPatch(typeof(TerrainOp), "Awake")]
		private static void AwakePrefix(TerrainOp __instance)
		{
			if (!Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)((Component)__instance).gameObject))
			{
				return;
			}
			OverlayVisualizer component = ((Component)__instance).gameObject.GetComponent<OverlayVisualizer>();
			if (!Object.op_Implicit((Object)(object)component) || component is RaiseGroundOverlayVisualizer)
			{
				if (lastTotalRaiseDelta != 0f || lastTotalSmoothDelta != 0f)
				{
					PreciseTerrainModifier.EnsureRuntimeSettings(__instance, isReset: false, (Object)(object)component != (Object)null);
				}
				if (__instance.m_settings.m_raise)
				{
					__instance.m_settings.m_raisePower = ModifyRaisePower(__instance.m_settings.m_raisePower, lastTotalRaiseDelta);
					Log.LogInfo($"Applying raise Power {__instance.m_settings.m_raisePower}", LogLevel.Medium);
				}
				if (__instance.m_settings.m_smooth)
				{
					__instance.m_settings.m_smoothPower = ModifySmoothPower(__instance.m_settings.m_smoothPower, lastTotalSmoothDelta);
					Log.LogInfo($"Applying smooth Power {__instance.m_settings.m_smoothPower}", LogLevel.Medium);
				}
			}
		}

		private static void SetPower(Player player, float delta)
		{
			Piece selectedPiece = player.GetSelectedPiece();
			if (!Object.op_Implicit((Object)(object)selectedPiece) || !Object.op_Implicit((Object)(object)((Component)selectedPiece).gameObject))
			{
				return;
			}
			OverlayVisualizer component = ((Component)selectedPiece).gameObject.GetComponent<OverlayVisualizer>();
			if (Object.op_Implicit((Object)(object)component) && !(component is RaiseGroundOverlayVisualizer))
			{
				return;
			}
			TerrainOp component2 = ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>();
			if (!Object.op_Implicit((Object)(object)component2))
			{
				return;
			}
			SetSmoothPower(component2, delta);
			SetRaisePower(component2, delta);
			List<string> list = new List<string>();
			if (SmoothToolIsInUse)
			{
				float smoothPowerDisplayValue = GetSmoothPowerDisplayValue(lastModdedSmoothPwr);
				if (Mathf.Abs(smoothPowerDisplayValue - lastDisplayedSmoothHardness) > 0.9f)
				{
					lastDisplayedSmoothHardness = Mathf.Round(smoothPowerDisplayValue);
					list.Add(string.Format("{0} {1:0}%", Localization.instance.Localize("$atmc_smoothing_hardness"), smoothPowerDisplayValue));
				}
			}
			if (RaiseToolIsInUse)
			{
				float raisePowerDisplayValue = GetRaisePowerDisplayValue(lastModdedRaisePwr);
				if (Mathf.Abs(raisePowerDisplayValue - lastDisplayedRaiseHardness) > 0.9f)
				{
					lastDisplayedRaiseHardness = Mathf.Round(raisePowerDisplayValue);
					list.Add(string.Format("{0} {1:0}%", Localization.instance.Localize("$atmc_raise_hardness"), raisePowerDisplayValue));
				}
			}
			if (SmoothToolIsInUse || RaiseToolIsInUse)
			{
				Piece val = (Object.op_Implicit((Object)(object)player.m_placementGhost) ? player.m_placementGhost.GetComponent<Piece>() : null);
				Sprite val2 = (Object.op_Implicit((Object)(object)val) ? val.m_icon : null);
				if ((Object)(object)val2 != (Object)null && list.Count > 0)
				{
					((Character)player).Message((MessageType)2, string.Join("\n", list.ToArray()), 0, val2, false);
				}
			}
		}

		private static void SetSmoothPower(TerrainOp terrainOp, float delta)
		{
			if (terrainOp.m_settings.m_smooth)
			{
				Log.LogInfo($"Adjusting Smooth Power by {delta}", LogLevel.High);
				float num = (SmoothToolIsInUse ? lastModdedSmoothPwr : terrainOp.m_settings.m_smoothPower);
				SmoothToolIsInUse = true;
				lastModdedSmoothPwr = ModifySmoothPower(num, delta);
				lastTotalSmoothDelta += lastModdedSmoothPwr - num;
				Log.LogInfo($"Total smooth power delta {lastTotalSmoothDelta}", LogLevel.High);
			}
		}

		private static void SetRaisePower(TerrainOp terrainOp, float delta)
		{
			if (terrainOp.m_settings.m_raise)
			{
				SelectRaiseTool(terrainOp);
				delta = ConvertSmoothDeltaToRaiseDelta(delta);
				Log.LogInfo($"Adjusting Raise Power by {delta}", LogLevel.High);
				float num = (RaiseToolIsInUse ? lastModdedRaisePwr : terrainOp.m_settings.m_raisePower);
				RaiseToolIsInUse = true;
				lastModdedRaisePwr = ModifyRaisePower(num, delta);
				lastTotalRaiseDelta += lastModdedRaisePwr - num;
				Log.LogInfo($"Total raise power delta {lastTotalRaiseDelta}", LogLevel.High);
			}
		}

		private static float ConvertSmoothDeltaToRaiseDelta(float delta)
		{
			float num = delta / 29f;
			return -1f * num * 0.95f;
		}

		private static float GetSmoothPowerDisplayValue(float power)
		{
			return (power - 1f) / 29f * 100f;
		}

		private static float GetRaisePowerDisplayValue(float power)
		{
			return (1f - power) / 0.95f * 100f;
		}

		private static float ModifySmoothPower(float power, float delta)
		{
			return Mathf.Clamp(power + delta, 1f, 30f);
		}

		private static float ModifyRaisePower(float power, float delta)
		{
			return Mathf.Clamp(power + delta, 0.05f, 1f);
		}
	}
	internal static class InitManager
	{
		private static bool HasInitialized = false;

		private static bool HasLoggedTerrainOpFallback = false;

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

		private static readonly Dictionary<string, List<int>> InsertionIndexes = new Dictionary<string, List<int>>();

		internal static bool IsCustomTool(GameObject gameObject)
		{
			if (Object.op_Implicit((Object)(object)gameObject))
			{
				return ToolConfigs.ToolConfigsMap.ContainsKey(((Object)gameObject).name.Replace("(Clone)", ""));
			}
			return false;
		}

		internal static void InitToolPieces()
		{
			if (HasInitialized)
			{
				RefreshTerrainOpRegistrations();
				return;
			}
			FixVanillaToolDescriptions();
			foreach (string key in ToolConfigs.ToolConfigsMap.Keys)
			{
				try
				{
					ToolDB toolDB = ToolConfigs.ToolConfigsMap[key];
					toolDB.prefab = MakeToolPiece(toolDB);
				}
				catch (Exception arg)
				{
					Log.LogWarning($"Failed to create {key}: {arg}");
				}
			}
			HasInitialized = true;
			UpdateTools();
		}

		internal static void RefreshTerrainOpRegistrations()
		{
			foreach (ToolDB value in ToolConfigs.ToolConfigsMap.Values)
			{
				if (Object.op_Implicit((Object)(object)value.prefab))
				{
					EnsureTerrainOpRegistered(value.prefab);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")]
		private static void ObjectDBUpdateRegistersPostfix()
		{
			if (HasInitialized)
			{
				RefreshTerrainOpRegistrations();
			}
		}

		internal static void FixVanillaToolDescriptions()
		{
			SetDescription("mud_road_v2", "$atmc_vanilla_level_desc");
			SetDescription("raise_v2", "$atmc_vanilla_raise_desc");
			SetDescription("path_v2", "$atmc_vanilla_path_desc");
			SetDescription("paved_road_v2", "$atmc_vanilla_paved_desc");
			SetDescription("cultivate_v2", "$atmc_vanilla_cultivate_desc");
			SetDescription("replant_v2", "$atmc_vanilla_replant_desc");
		}

		private static void SetDescription(string prefabName, string description)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName);
			Piece val = ((prefab != null) ? prefab.GetComponent<Piece>() : null);
			if ((Object)(object)val != (Object)null)
			{
				val.m_description = description;
			}
			else
			{
				Log.LogWarning("Could not set description for: " + prefabName);
			}
		}

		internal static void UpdatePlugin()
		{
			UpdateTools();
			UpdateShovelRecipe();
			ConfigManager.Save();
			TerrainTools.UpdatePlugin = false;
		}

		private static void UpdateTools()
		{
			if (!HasInitialized)
			{
				return;
			}
			ForceUnequipTerrainTools();
			foreach (ToolDB value in ToolConfigs.ToolConfigsMap.Values)
			{
				RemovePieceInPieceTable(value);
			}
			foreach (string key in ToolConfigs.ToolConfigsMap.Keys)
			{
				if (TerrainTools.IsToolEnabled(key))
				{
					ToolDB toolDB = ToolConfigs.ToolConfigsMap[key];
					if (!Object.op_Implicit((Object)(object)toolDB.prefab))
					{
						Log.LogWarning("Skipping unavailable terrain tool: " + key);
					}
					else
					{
						RegisterPieceInPieceTable(toolDB.prefab, toolDB.pieceTable, toolDB.insertIndex);
					}
				}
			}
		}

		internal static void UpdatePieceTables()
		{
			foreach (string key in ToolConfigs.ToolConfigsMap.Keys)
			{
				try
				{
					ToolDB toolDB = ToolConfigs.ToolConfigsMap[key];
					toolDB.prefab = MakeToolPiece(toolDB);
					RegisterPieceInPieceTable(toolDB.prefab, toolDB.pieceTable, toolDB.insertIndex);
				}
				catch (Exception arg)
				{
					Log.LogWarning($"Failed to create {key}: {arg}");
				}
			}
		}

		private static void UpdateShovelRecipe()
		{
			if (Shovel.TryGetShovel(out var shovel))
			{
				shovel.Recipe.Recipe.m_enabled = TerrainTools.IsShovelEnabled;
			}
		}

		private static void ForceUnequipTerrainTools()
		{
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return;
			}
			ItemData rightItem = ((Humanoid)Player.m_localPlayer).GetRightItem();
			if (rightItem != null)
			{
				if (rightItem.m_shared.m_name == "$item_cultivator")
				{
					Log.LogWarning("AdvancedTerrainModifiers updated through config change, unequipping cultivator");
					((Humanoid)Player.m_localPlayer).HideHandItems(false, true);
				}
				if (rightItem.m_shared.m_name == "$item_hoe")
				{
					Log.LogWarning("AdvancedTerrainModifiers updated through config change, unequipping hoe");
					((Humanoid)Player.m_localPlayer).HideHandItems(false, true);
				}
			}
		}

		internal static GameObject MakeToolPiece(ToolDB toolDB)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: 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)
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(toolDB.name, toolDB.basePrefab);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Piece component = val.GetComponent<Piece>();
			component.m_icon = Sprite.Create(toolDB.icon, new Rect(0f, 0f, (float)((Texture)toolDB.icon).width, (float)((Texture)toolDB.icon).height), Vector2.zero);
			component.m_name = toolDB.pieceName;
			component.m_description = toolDB.pieceDesc;
			if (toolDB.requirements != null)
			{
				component.m_resources = toolDB.requirements;
			}
			PreciseTerrainModifier.RuntimeSettings runtimeSettings = PreciseTerrainModifier.EnsureRuntimeSettings(val.GetComponent<TerrainOp>(), toolDB.overlayType == typeof(RemoveModificationsOverlayVisualizer), toolDB.overlayType != null);
			((Settings)runtimeSettings).m_level = UpdateValueIfNeeded(((Settings)runtimeSettings).m_level, toolDB.level);
			((Settings)runtimeSettings).m_levelRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_levelRadius, toolDB.levelRadius);
			((Settings)runtimeSettings).m_raise = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raise, toolDB.raise);
			((Settings)runtimeSettings).m_raiseRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raiseRadius, toolDB.raiseRadius);
			((Settings)runtimeSettings).m_raisePower = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raisePower, toolDB.raisePower);
			((Settings)runtimeSettings).m_raiseDelta = UpdateValueIfNeeded(((Settings)runtimeSettings).m_raiseDelta, toolDB.raiseDelta);
			((Settings)runtimeSettings).m_smooth = UpdateValueIfNeeded(((Settings)runtimeSettings).m_smooth, toolDB.smooth);
			((Settings)runtimeSettings).m_smoothRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_smoothRadius, toolDB.smoothRadius);
			((Settings)runtimeSettings).m_smoothPower = UpdateValueIfNeeded(((Settings)runtimeSettings).m_smoothPower, toolDB.smoothPower);
			((Settings)runtimeSettings).m_paintCleared = UpdateValueIfNeeded(((Settings)runtimeSettings).m_paintCleared, toolDB.clearPaint);
			((Settings)runtimeSettings).m_paintRadius = UpdateValueIfNeeded(((Settings)runtimeSettings).m_paintRadius, toolDB.paintRadius);
			if (toolDB.overlayType != null)
			{
				val.AddComponent(toolDB.overlayType);
			}
			if (toolDB.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);
				}
			}
			return val;
		}

		private static T UpdateValueIfNeeded<T>(T source, T? newValue) where T : struct
		{
			if (!newValue.HasValue)
			{
				return source;
			}
			return newValue.Value;
		}

		private static T UpdateValueIfNeeded<T>(T source, T newValue)
		{
			if (newValue == null)
			{
				return source;
			}
			return newValue;
		}

		private static void RegisterPieceInPieceTable(GameObject prefab, string pieceTable, int position = -1)
		{
			Piece component = prefab.GetComponent<Piece>();
			if ((Object)(object)component == (Object)null)
			{
				throw new Exception("Prefab " + ((Object)prefab).name + " has no Piece component attached");
			}
			PieceTable pieceTable2 = PieceManager.Instance.GetPieceTable(pieceTable);
			if ((Object)(object)pieceTable2 == (Object)null)
			{
				throw new Exception("Could not find PieceTable " + pieceTable);
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
			if ((Object)(object)ZNetScene.instance != (Object)null && !ZNetScene.instance.m_namedPrefabs.ContainsKey(stableHashCode))
			{
				PrefabManager.Instance.RegisterToZNetScene(prefab);
			}
			EnsureTerrainOpRegistered(prefab);
			if (pieceTable2.m_pieces.Contains(prefab))
			{
				Log.LogDebug("Already added piece " + ((Object)prefab).name);
				return;
			}
			if (!InsertionIndexes.ContainsKey(pieceTable))
			{
				InsertionIndexes[pieceTable] = new List<int>();
			}
			int num = 0;
			if (position >= 0)
			{
				num = position + InsertionIndexes[pieceTable].Where((int x) => x <= position).Count();
			}
			else if (num >= pieceTable2.m_pieces.Count && pieceTable2.m_pieces.Count != 0)
			{
				Log.LogWarning("Piece insertion index is out of bounds");
			}
			if (position >= 0 && num < pieceTable2.m_pieces.Count)
			{
				pieceTable2.m_pieces.Insert(num, prefab);
				InsertionIndexes[pieceTable].Add(position);
			}
			else
			{
				pieceTable2.m_pieces.Add(prefab);
				InsertionIndexes[pieceTable].Add(pieceTable2.m_pieces.Count - 1);
			}
			Log.LogDebug("Added piece " + ((Object)prefab).name + " | Token: " + PieceExtension.TokenName(component));
		}

		internal static void EnsureTerrainOpRegistered(GameObject prefab)
		{
			ObjectDB instance = ObjectDB.instance;
			TerrainOp val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<TerrainOp>() : null);
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			int prefabHash = instance.GetPrefabHash(prefab);
			if (instance.m_terrainOpsByHash.TryGetValue(prefabHash, out var value))
			{
				if ((Object)(object)value != (Object)(object)val)
				{
					Log.LogWarning($"TerrainOp prefab hash collision for {((Object)prefab).name} ({prefabHash}); keeping the registered prefab");
				}
				return;
			}
			if (!instance.m_terrainOps.Contains(val))
			{
				instance.m_terrainOps.Add(val);
			}
			instance.m_terrainOpsByHash.Add(prefabHash, val);
			if (!HasLoggedTerrainOpFallback)
			{
				HasLoggedTerrainOpFallback = true;
				Log.LogInfo("Installed Jotunn did not register custom TerrainOps; using the AdvancedTerrainModifiers fallback");
			}
			Log.LogDebug("Registered TerrainOp " + ((Object)prefab).name + " in ObjectDB");
		}

		private static void RemovePieceInPieceTable(ToolDB toolDB)
		{
			GameObject prefab = toolDB.prefab;
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return;
			}
			PieceTable pieceTable = PieceManager.Instance.GetPieceTable(toolDB.pieceTable);
			if ((Object)(object)pieceTable == (Object)null)
			{
				throw new Exception("Could not find PieceTable " + toolDB.pieceTable);
			}
			int num = pieceTable.m_pieces.IndexOf(prefab);
			if (num < 0)
			{
				return;
			}
			pieceTable.m_pieces.Remove(prefab);
			Log.LogDebug("Removed piece " + ((Object)prefab).name);
			List<int> list = InsertionIndexes[toolDB.pieceTable];
			if (!list.Contains(num))
			{
				return;
			}
			list.Remove(num);
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i] > num)
				{
					list[i]--;
				}
			}
		}
	}
	internal static class PaintGridMath
	{
		internal static float TexelCenterUv(int index, int terrainWidth)
		{
			return ((float)index + 0.5f) / ((float)terrainWidth + 1f);
		}

		internal static void GetAxisIndices(int terrainWidth, int centerIndex, int radius, out int first, out int last)
		{
			first = Math.Max(0, centerIndex - radius);
			last = Math.Min(terrainWidth, centerIndex + radius);
		}

		internal static bool TryGetAxisBounds(int terrainWidth, float vertexScale, float zoneCenter, int firstPaintedTexel, int lastPaintedTexel, out float min, out float max)
		{
			if (firstPaintedTexel > lastPaintedTexel)
			{
				min = 0f;
				max = 0f;
				return false;
			}
			float num = (float)terrainWidth * vertexScale * 0.5f;
			float num2 = zoneCenter - num;
			min = num2 + (float)firstPaintedTexel * vertexScale;
			max = num2 + (float)lastPaintedTexel * vertexScale;
			return true;
		}
	}
	internal static class PreciseRaiseMath
	{
		internal const int ModifiedRadius = 1;

		internal const int InfluenceRadius = 2;

		internal const float MinPower = 0.05f;

		internal const float MaxPower = 1f;

		internal static bool TryGetTargetHeight(float tileHeight, float refHeight, float delta, float weight, out float targetHeight)
		{
			targetHeight = refHeight + delta;
			if (delta < 0f && targetHeight > tileHeight)
			{
				return false;
			}
			if (delta >= 0f)
			{
				if (targetHeight < tileHeight)
				{
					return false;
				}
				if (targetHeight > tileHeight + delta)
				{
					targetHeight = tileHeight + delta;
				}
			}
			if (weight < 1f)
			{
				targetHeight = tileHeight + (targetHeight - tileHeight) * weight;
			}
			return true;
		}

		internal static float Weight(int dx, int dz, float power)
		{
			int num = Math.Max(Math.Abs(dx), Math.Abs(dz));
			if (num >= 2)
			{
				return 0f;
			}
			float num2 = SlopePivot(power);
			if ((float)num <= num2)
			{
				return 1f;
			}
			return (float)(2 - num) / (2f - num2);
		}

		internal static float SlopePivot(float power)
		{
			power = (float.IsNaN(power) ? 1f : Math.Max(0.05f, Math.Min(1f, power)));
			float num = (1f - power) / 0.95f;
			return 1f * num;
		}
	}
	[HarmonyPatch]
	public static class PreciseTerrainModifier
	{
		internal sealed class RuntimeSettings : Settings
		{
			internal bool IsReset;

			internal bool HasOverlay;
		}

		public const int FixedRadius = 1;

		public const int FixedPaintRadius = 1;

		private const int SettingsPayloadMagic = 1096043859;

		private const int SettingsPayloadVersion = 1;

		private const float MinRadius = 0.5f;

		private const float MaxSmoothPower = 30f;

		internal static RuntimeSettings EnsureRuntimeSettings(TerrainOp terrainOp, bool isReset = false, bool hasOverlay = false)
		{
			if (terrainOp.m_settings is RuntimeSettings runtimeSettings)
			{
				runtimeSettings.IsReset |= isReset;
				runtimeSettings.HasOverlay |= hasOverlay;
				return runtimeSettings;
			}
			return (RuntimeSettings)(object)(terrainOp.m_settings = (Settings)(object)CopySettings(terrainOp.m_settings, isReset, hasOverlay));
		}

		public static bool IsPrecisionModifier(float radius)
		{
			return radius == float.NegativeInfinity;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ClutterSystem), "ResetGrass")]
		private static void ResetGrassPrefix(ClutterSystem __instance, Vector3 center, ref float radius)
		{
			if (IsPrecisionModifier(radius))
			{
				radius = 1f;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp), "ApplyOperation")]
		private static bool ApplyOperationPrefix(TerrainComp __instance, TerrainOp modifier)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)modifier) || !Object.op_Implicit((Object)(object)((Component)modifier).gameObject))
			{
				return true;
			}
			OverlayVisualizer componentInChildren = ((Component)modifier).gameObject.GetComponentInChildren<OverlayVisualizer>();
			RuntimeSettings runtimeSettings = modifier.m_settings as RuntimeSettings;
			if (runtimeSettings == null && (Object.op_Implicit((Object)(object)componentInChildren) || InitManager.IsCustomTool(((Component)modifier).gameObject)))
			{
				runtimeSettings = EnsureRuntimeSettings(modifier, componentInChildren is RemoveModificationsOverlayVisualizer, (Object)(object)componentInChildren != (Object)null);
			}
			if (runtimeSettings == null)
			{
				return true;
			}
			if (!HasAreaAccess(modifier, ((Component)modifier).transform.position, flash: false))
			{
				Log.LogWarning("Blocked a terrain operation whose brush intersects a protected area");
				return false;
			}
			if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.IsValid() && !__instance.m_nview.IsOwner())
			{
				__instance.m_nview.ClaimOwnership();
			}
			if (runtimeSettings.HasOverlay)
			{
				if (((Settings)runtimeSettings).m_smooth)
				{
					((Settings)runtimeSettings).m_smoothRadius = float.NegativeInfinity;
				}
				if (((Settings)runtimeSettings).m_raise && ((Settings)runtimeSettings).m_raiseDelta >= 0f)
				{
					((Settings)runtimeSettings).m_raiseRadius = float.NegativeInfinity;
					((Settings)runtimeSettings).m_raiseDelta = GroundLevelSpinner.Value;
				}
				if (((Settings)runtimeSettings).m_paintCleared)
				{
					((Settings)runtimeSettings).m_paintRadius = float.NegativeInfinity;
				}
			}
			return true;
		}

		internal static bool HasAreaAccess(TerrainOp modifier, Vector3 position, bool flash)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)modifier))
			{
				return true;
			}
			float num = modifier.GetRadius();
			if (!IsFinite(num) || num < 0f)
			{
				return false;
			}
			RuntimeSettings runtimeSettings = modifier.m_settings as RuntimeSettings;
			if (modifier.m_settings.m_square || (runtimeSettings != null && runtimeSettings.HasOverlay) || (runtimeSettings != null && runtimeSettings.IsReset))
			{
				num *= 1.414214f;
			}
			return PrivateArea.CheckAccess(position, num, flash, true);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TerrainOp), "GetRadius")]
		private static void GetRadiusPostfix(TerrainOp __instance, ref float __result)
		{
			if (Object.op_Implicit((Object)(object)__instance))
			{
				OverlayVisualizer component = ((Component)__instance).gameObject.GetComponent<OverlayVisualizer>();
				if (component is RemoveModificationsOverlayVisualizer)
				{
					__result = Mathf.Max(__result, __instance.m_settings.m_levelRadius + 1f);
				}
				else if (component is RaiseGroundOverlayVisualizer)
				{
					__result = Mathf.Max(__result, 2f);
				}
				else if (Object.op_Implicit((Object)(object)component) && __instance.m_settings.m_paintCleared)
				{
					__result = Mathf.Max(__result, 1f);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Settings), "GetRadius")]
		private static void GetSettingsRadiusPostfix(Settings __instance, ref float __result)
		{
			if (__instance.m_raise && IsPrecisionModifier(__instance.m_raiseRadius))
			{
				__result = Mathf.Max(__result, 2f);
			}
			if ((__instance.m_smooth && IsPrecisionModifier(__instance.m_smoothRadius)) || (__instance.m_paintCleared && IsPrecisionModifier(__instance.m_paintRadius)))
			{
				__result = Mathf.Max(__result, 1f);
			}
		}

		private static void RemoveLegacyTerrainModifiers(Vector3 position, float radius)
		{
			//IL_0006: 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)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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)
			List<TerrainModifier> list = new List<TerrainModifier>();
			TerrainModifier.GetModifiers(position, radius + 1f, list, (TerrainModifier)null);
			foreach (TerrainModifier item in list)
			{
				float num = (Object.op_Implicit((Object)(object)item) ? item.GetRadius() : 0f);
				if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.m_nview) && item.m_nview.IsValid() && item.m_playerModifiction && !Object.op_Implicit((Object)(object)((Component)item).GetComponentInParent<Piece>()) && !Object.op_Implicit((Object)(object)((Component)item).GetComponentInParent<WearNTear>()) && !(Mathf.Abs(((Component)item).transform.position.x - position.x) + num > radius) && !(Mathf.Abs(((Component)item).transform.position.z - position.z) + num > radius) && (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || PrivateArea.CheckAccess(((Component)item).transform.position, num, false, true)))
				{
					item.m_nview.ClaimOwnership();
					if (Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						ZNetScene.instance.Destroy(((Component)item).gameObject);
					}
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Settings), "Serialize")]
		private static void SerializeSettingsPostfix(Settings __instance, ZPackage pkg)
		{
			if (__instance is RuntimeSettings runtimeSettings && pkg != null)
			{
				pkg.Write(1096043859);
				pkg.Write(1);
				pkg.Write(((Settings)runtimeSettings).m_levelRadius);
				pkg.Write(((Settings)runtimeSettings).m_raiseRadius);
				pkg.Write(((Settings)runtimeSettings).m_raisePower);
				pkg.Write(((Settings)runtimeSettings).m_raiseDelta);
				pkg.Write(((Settings)runtimeSettings).m_smoothRadius);
				pkg.Write(((Settings)runtimeSettings).m_smoothPower);
				pkg.Write(((Settings)runtimeSettings).m_paintRadius);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Settings), "Deserialize")]
		private static void DeserializeSettingsPostfix(ZPackage pkg, ref Settings __result)
		{
			if (__result == null || pkg == null || pkg.Size() - pkg.GetPos() < 4)
			{
				return;
			}
			int pos = pkg.GetPos();
			if (pkg.ReadInt() != 1096043859)
			{
				pkg.SetPos(pos);
				return;
			}
			if (pkg.Size() - pos < 36 || pkg.ReadInt() != 1)
			{
				Log.LogWarning("Rejected incomplete or unsupported terrain-operation settings");
				__result = null;
				return;
			}
			RuntimeSettings obj = __result as RuntimeSettings;
			bool isReset = obj?.IsReset ?? false;
			bool hasOverlay = obj?.HasOverlay ?? false;
			RuntimeSettings runtimeSettings = CopySettings(__result, isReset, hasOverlay);
			((Settings)runtimeSettings).m_levelRadius = pkg.ReadSingle();
			((Settings)runtimeSettings).m_raiseRadius = pkg.ReadSingle();
			((Settings)runtimeSettings).m_raisePower = pkg.ReadSingle();
			((Settings)runtimeSettings).m_raiseDelta = pkg.ReadSingle();
			((Settings)runtimeSettings).m_smoothRadius = pkg.ReadSingle();
			((Settings)runtimeSettings).m_smoothPower = pkg.ReadSingle();
			((Settings)runtimeSettings).m_paintRadius = pkg.ReadSingle();
			if (!IsValid(runtimeSettings))
			{
				Log.LogWarning("Rejected invalid network terrain-operation settings");
				__result = null;
			}
			else
			{
				__result = (Settings)(object)runtimeSettings;
			}
		}

		private static RuntimeSettings CopySettings(Settings source, bool isReset, bool hasOverlay)
		{
			//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)
			return new RuntimeSettings
			{
				IsReset = isReset,
				HasOverlay = hasOverlay,
				m_levelOffset = source.m_levelOffset,
				m_level = source.m_level,
				m_levelRadius = source.m_levelRadius,
				m_square = source.m_square,
				m_raise = source.m_raise,
				m_raiseRadius = source.m_raiseRadius,
				m_raisePower = source.m_raisePower,
				m_raiseDelta = source.m_raiseDelta,
				m_smooth = source.m_smooth,
				m_smoothRadius = source.m_smoothRadius,
				m_smoothPower = source.m_smoothPower,
				m_paintCleared = source.m_paintCleared,
				m_paintHeightCheck = source.m_paintHeightCheck,
				m_paintType = source.m_paintType,
				m_paintRadius = source.m_paintRadius,
				m_paintStrength = source.m_paintStrength,
				m_paintExp = source.m_paintExp,
				m_paintCurve = source.m_paintCurve,
				m_rotation = source.m_rotation,
				m_sides = source.m_sides,
				m_addMedianMax = source.m_addMedianMax,
				m_centerMultiplicationFactor = source.m_centerMultiplicationFactor,
				m_pointMultiplicationFactor = source.m_pointMultiplicationFactor,
				m_halfOffset = source.m_halfOffset
			};
		}

		private static bool IsValid(RuntimeSettings settings)
		{
			if (!IsRadius(((Settings)settings).m_levelRadius, settings.IsReset ? 1f : 0.5f))
			{
				return false;
			}
			if (((Settings)settings).m_raise && !IsPrecisionRadius(((Settings)settings).m_raiseRadius, settings.HasOverlay))
			{
				return false;
			}
			if (((Settings)settings).m_smooth && !IsPrecisionRadius(((Settings)settings).m_smoothRadius, settings.HasOverlay))
			{
				return false;
			}
			if (((Settings)settings).m_paintCleared && !IsPrecisionRadius(((Settings)settings).m_paintRadius, settings.HasOverlay))
			{
				return false;
			}
			if (((Settings)settings).m_raise && (!IsFinite(((Settings)settings).m_raisePower) || ((Settings)settings).m_raisePower < 0.05f || ((Settings)settings).m_raisePower > 1f))
			{
				return false;
			}
			if (((Settings)settings).m_raise && (!IsFinite(((Settings)settings).m_raiseDelta) || ((Settings)settings).m_raiseDelta < -1f || ((Settings)settings).m_raiseDelta > 1f))
			{
				return false;
			}
			if (((Settings)settings).m_smooth && (!IsFinite(((Settings)settings).m_smoothPower) || ((Settings)settings).m_smoothPower < 1f || ((Settings)settings).m_smoothPower > 30f))
			{
				return false;
			}
			return true;
		}

		private static bool IsPrecisionRadius(float value, bool allowPrecision)
		{
			if (!allowPrecision || !IsPrecisionModifier(value))
			{
				return IsRadius(value, 0.5f);
			}
			return true;
		}

		private static bool IsRadius(float value, float minimum)
		{
			if (IsFinite(value) && value >= minimum)
			{
				return value <= TerrainTools.MaxRadius;
			}
			return false;
		}

		private static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp), "InternalDoOperation")]
		private static bool InternalDoOperationPrefix(TerrainComp __instance, Vector3 pos, Settings modifier)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (modifier is RuntimeSettings { IsReset: not false })
			{
				int num = Mathf.Clamp(Mathf.RoundToInt(modifier.m_levelRadius), 1, Mathf.CeilToInt(TerrainTools.MaxRadius));
				RemoveLegacyTerrainModifiers(pos, num);
				RemoveTerrainModifications(__instance, pos, num);
				PreciseRecolorTerrain(__instance, pos, (PaintType)3, heightCheck: false, num);
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TerrainComp), "InternalDoOperation")]
		private static void InternalDoOperationPostfix(TerrainComp __instance)
		{
			if (IsPrecisionModifier(__instance.m_lastOpRadius))
			{
				__instance.m_lastOpRadius = 1f;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp), "SmoothTerrain")]
		private static bool PreciseSmoothTerrian(TerrainComp __instance, Vector3 worldPos, float radius)
		{
			//IL_0024: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (!IsPrecisionModifier(radius))
			{
				return true;
			}
			Log.LogInfo("PreciseSmoothTerrain", LogLevel.Medium);
			int num = __instance.m_width + 1;
			int num2 = default(int);
			int num3 = default(int);
			__instance.m_hmap.WorldToVertex(worldPos, ref num2, ref num3);
			float num4 = worldPos.y - ((Component)__instance).transform.position.y;
			Log.LogInfo($"worldPos: {worldPos}, xPos: {num2}, yPos: {num3}, referenceH: {num4}", LogLevel.Medium);
			FindExtrema(num2, num, out var xMin, out var xMax);
			FindExtrema(num3, num, out var xMin2, out var xMax2);
			for (int i = xMin; i <= xMax; i++)
			{
				for (int j = xMin2; j <= xMax2; j++)
				{
					int num5 = j * num + i;
					float height = __instance.m_hmap.GetHeight(i, j);
					float num6 = num4 - height;
					float num7 = __instance.m_smoothDelta[num5];
					__instance.m_smoothDelta[num5] = Mathf.Clamp(num7 + num6, -1f, 1f);
					__instance.m_modifiedHeight[num5] = true;
					Log.LogInfo($"tilePos: ({i}, {j}), tileH: {height}, deltaH: {num6}, prevSmoothDelta: {num7}, newSmoothDelta {__instance.m_smoothDelta[num5]}", LogLevel.Medium);
				}
			}
			Log.LogInfo("[SUCCESS] Smooth Terrain Modification", LogLevel.Medium);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp), "RaiseTerrain")]
		private static bool RaiseTerrainPrefix(TerrainComp __instance, Vector3 worldPos, float radius, float delta, float power)
		{
			//IL_0024: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (!IsPrecisionModifier(radius))
			{
				return true;
			}
			Log.LogInfo("[INIT] Raise Terrain Modification", LogLevel.Medium);
			int num = __instance.m_width + 1;
			int num2 = default(int);
			int num3 = default(int);
			__instance.m_hmap.WorldToVertex(worldPos, ref num2, ref num3);
			float num4 = worldPos.y - ((Component)__instance).transform.position.y;
			Log.LogInfo($"worldPos: {worldPos}, xPos: {num2}, yPos: {num3}, delta: {delta}, refHeight: {num4}", LogLevel.Medium);
			FindExtrema(num2, num, 1, out var xMin, out var xMax);
			FindExtrema(num3, num, 1, out var xMin2, out var xMax2);
			for (int i = xMin; i <= xMax; i++)
			{
				for (int j = xMin2; j <= xMax2; j++)
				{
					float height = __instance.m_hmap.GetHeight(i, j);
					float weight = PreciseRaiseMath.Weight(i - num2, j - num3, power);
					if (PreciseRaiseMath.TryGetTargetHeight(height, num4, delta, weight, out var targetHeight))
					{
						int num5 = j * num + i;
						float num6 = targetHeight - height + __instance.m_smoothDelta[num5];
						__instance.m_smoothDelta[num5] = 0f;
						__instance.m_levelDelta[num5] += num6;
						__instance.m_levelDelta[num5] = Mathf.Clamp(__instance.m_levelDelta[num5], -8f, 8f);
						__instance.m_modifiedHeight[num5] = true;
					}
				}
			}
			Log.LogInfo("[SUCCESS] Raise Terrain Modification", LogLevel.Medium);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp), "PaintCleared")]
		private static bool PaintClearedPrefix(TerrainComp __instance, Vector3 worldPos, Settings settings)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!IsPrecisionModifier(settings.m_paintRadius))
			{
				return true;
			}
			PreciseRecolorTerrain(__instance, worldPos, settings.m_paintType, settings.m_paintHeightCheck);
			return false;
		}

		public static void RemoveTerrainModifications(TerrainComp comp, Vector3 worldPos, int radius = 1)
		{
			//IL_001a: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			Log.LogInfo("[INIT] Remove Terrain Modifications", LogLevel.Medium);
			int num = comp.m_width + 1;
			int num2 = default(int);
			int num3 = default(int);
			comp.m_hmap.WorldToVertex(worldPos, ref num2, ref num3);
			Log.LogInfo($"worldPos: {worldPos}, vertexPos: ({num2}, {num3})", LogLevel.Medium);
			FindExtrema(num2, num, radius, out var xMin, out var xMax);
			FindExtrema(num3, num, radius, out var xMin2, out var xMax2);
			Log.LogInfo($"Reset chunk {((Component)comp).transform.position}: radius={radius}, vertices=({xMin}..{xMax}, {xMin2}..{xMax2}), " + $"edge={xMin == 0 || xMin2 == 0 || xMax == num - 1 || xMax2 == num - 1}");
			for (int i = xMin; i <= xMax; i++)
			{
				for (int j = xMin2; j <= xMax2; j++)
				{
					int num4 = j * num + i;
					comp.m_levelDelta[num4] = 0f;
					comp.m_smoothDelta[num4] = 0f;
					comp.m_modifiedHeight[num4] = false;
					Log.LogInfo($"tilePos: ({i}, {j}), tileIndex: {num4}", LogLevel.Medium);
				}
			}
			Log.LogInfo("[SUCCESS] Remove Terrain Modifications", LogLevel.Medium);
		}

		public static void PreciseRecolorTerrain(TerrainComp comp, Vector3 worldPos, PaintType paintType, bool heightCheck = false, int radius = 1)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			Log.LogInfo("[INIT] PreciseRecolorTerrain", LogLevel.Medium);
			Color val = ResolveColor(paintType);
			GetPaintMaskBounds(comp.m_hmap, worldPos, radius, out var xStart, out var xMax, out var yStart, out var yMax);
			int num = comp.m_width + 1;
			for (int i = xStart; i <= xMax; i++)
			{
				for (int j = yStart; j <= yMax; j++)
				{
					val.a = comp.m_hmap.GetPaintMask(i, j).a;
					int num2 = j * num + i;
					comp.m_paintMask[num2] = val;
					comp.m_modifiedPaint[num2] = true;
					Log.LogInfo($"tilePos: ({i}, {j}), tileIndex: {num2}, tileColor: {val}", LogLevel.Medium);
				}
			}
			Log.LogInfo("[SUCCESS] Color Terrain Modification", LogLevel.Medium);
		}

		public static void GetPaintMaskBounds(Heightmap heightmap, Vector3 worldPos, int radius, out int xStart, out int xMax, out int yStart, out int yMax)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			int centerIndex = default(int);
			int centerIndex2 = default(int);
			heightmap.WorldToVertex(worldPos, ref centerIndex, ref centerIndex2);
			PaintGridMath.GetAxisIndices(heightmap.m_width, centerIndex, radius, out xStart, out xMax);
			PaintGridMath.GetAxisIndices(heightmap.m_width, centerIndex2, radius, out yStart, out yMax);
		}

		public static bool TryGetPaintMaskWorldBounds(Heightmap heightmap, Vector3 worldPos, int radius, out Vector2 min, out Vector2 max)
		{
			//IL_0001: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid