Decompiled source of TerrainTools v1.1.0

TerrainTools.dll

Decompiled 6 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
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.Managers;
using Jotunn.Utils;
using TerrainTools.Configs;
using TerrainTools.Extensions;
using TerrainTools.Helpers;
using TerrainTools.Properties;
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.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
namespace TerrainTools
{
	[BepInPlugin("Searica.Valheim.TerrainTools", "TerrainTools", "1.1.0")]
	[BepInDependency("com.jotunn.jotunn", "2.14.6")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class TerrainTools : BaseUnityPlugin
	{
		internal const string Author = "Searica";

		public const string PluginName = "TerrainTools";

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

		public const string PluginVersion = "1.1.0";

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

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

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

		private static readonly string ToolsSection = ConfigManager.SetStringPriority("Tools", 0);

		private static ConfigEntry<bool> hoverInfoEnabled;

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

		private static bool UpdateTools = false;

		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;

		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 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_008f: 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;
			}
			fileName = Path.GetFileNameWithoutExtension(fileName);
			object? @object = Resources.ResourceManager.GetObject(fileName);
			Bitmap val = (Bitmap)((@object is Bitmap) ? @object : null);
			using MemoryStream memoryStream = new MemoryStream();
			((Image)val).Save((Stream)memoryStream, ImageFormat.Png);
			byte[] array = new byte[memoryStream.Length];
			memoryStream.Position = 0L;
			memoryStream.Read(array, 0, array.Length);
			Texture2D val2 = new Texture2D(0, 0);
			ImageConversion.LoadImage(val2, array);
			return val2;
		}

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

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

		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);
			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 terraforming tools.");
			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.");
			radiusScrollScale = ConfigManager.BindConfig(RadiusSection, "RadiusScrollScale", 0.1f, "Scroll wheel change scale", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f));
			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, "Set to true/enabled to allow modifying the hardness of terrain tools using the scroll wheel. Note: Hardness cannot be changed on square terraforming tools and tools that do not alter ground height do not have a hardness.");
			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.");
			hardnessScrollScale = ConfigManager.BindConfig(HardnessSection, "HardnessScrollScale", 0.1f, "Scroll wheel change scale", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f));
			hoverInfoEnabled = ConfigManager.BindConfig(ToolsSection, ConfigManager.SetStringPriority("HoverInfo", 1), value: true, "Set to true/enabled to show terrain height when using square terrain tools.");
			foreach (string key in ToolConfigs.ToolConfigsMap.Keys)
			{
				ConfigEntry<bool> val = ConfigManager.BindConfig(ToolsSection, key, value: true, "Set to true/enabled to add this terrain tool. Set to false/disabled to remove it.");
				val.SettingChanged += delegate
				{
					UpdateTools = !UpdateTools || UpdateTools;
				};
				ToolConfigEntries.Add(key, val);
			}
			ConfigManager.Save();
		}
	}
	internal enum LogLevel
	{
		Low,
		Medium,
		High
	}
	internal static class Log
	{
		internal static ManualLogSource _logSource;

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

		internal static LogLevel VerbosityLevel => Verbosity.Value;

		internal static void Init(ManualLogSource logSource)
		{
			_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 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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		internal static Texture2D Box
		{
			get
			{
				if ((Object)(object)_box == (Object)null)
				{
					_box = TerrainTools.LoadTextureFromResources("box.png");
				}
				return _box;
			}
		}
	}
	public class Overlay
	{
		private GameObject GameObject { get; }

		private Particle[] Particles => (Particle[])(object)new Particle[2];

		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_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)
				ps.GetParticles(Particles, 2);
				return Color32.op_Implicit(((Particle)(ref Particles[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_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;
				((MinMaxGradient)(ref startColor)).color = 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_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)).startSize = MinMaxCurve.op_Implicit(value);
			}
		}

		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 startSize = ((MainModule)(ref val)).startSize;
				return ((MinMaxCurve)(ref startSize)).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)
		{
			Transform = transform;
			GameObject = ((Component)transform).gameObject;
			ps = ((Component)transform).GetComponentInChildren<ParticleSystem>();
			psr = ((Component)transform).GetComponentInChildren<ParticleSystemRenderer>();
		}
	}
	public abstract class OverlayVisualizer : MonoBehaviour
	{
		protected Overlay primary;

		protected Overlay secondary;

		protected Overlay tertiary;

		protected HoverInfo hoverInfo;

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

		private void Update()
		{
			//IL_007b: 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 = new Color(255f, 255f, 255f);
				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 = 4f;
			((Renderer)overlay.psr).material.mainTexture = (Texture)(object)IconCache.Box;
			overlay.LocalPosition = VerticalOffset;
		}

		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 = 3f;
			((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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			hoverInfo.Enabled = TerrainTools.IsHoverInforEnabled;
			if (hoverInfo.Enabled)
			{
				hoverInfo.RotateToPlayer();
				Vector3 val = secondary.Position - OverlayVisualizer.VerticalOffset;
				hoverInfo.Text = $"x: {val.x:0}, y: {val.y:0.000}, z: {val.z:0}";
			}
		}
	}
	[HarmonyPatch(typeof(Piece), "SetInvalidPlacementHeightlight")]
	public static class OverlayVisualizationRedshiftHeigthlightBlocker
	{
		private static bool Prefix(Piece __instance)
		{
			return (Object)(object)((Component)__instance).GetComponentInChildren<OverlayVisualizer>() == (Object)null;
		}
	}
	public class LevelGroundOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			base.Initialize();
			SpeedUp(secondary);
			VisualizeTerraformingBounds(secondary);
		}

		protected override void OnRefresh()
		{
			base.OnRefresh();
			primary.Enabled = false;
			secondary.Enabled = true;
		}
	}
	public class RaiseGroundOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			base.Initialize();
			Freeze(secondary);
			Freeze(tertiary);
			VisualizeTerraformingBounds(secondary);
			VisualizeTerraformingBounds(tertiary);
		}

		protected override void OnRefresh()
		{
			//IL_0038: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			base.OnRefresh();
			primary.Enabled = true;
			secondary.Enabled = true;
			GroundLevelSpinner.Refresh();
			secondary.LocalPosition = new Vector3(0f, GroundLevelSpinner.Value, 0f);
			Vector3 val = secondary.Position - OverlayVisualizer.VerticalOffset;
			if (GroundLevelSpinner.Value > 0f)
			{
				float y = secondary.LocalPosition.y;
				hoverInfo.Text = $"x: {val.x:0}, y: {val.y - y:0.000}, z: {val.z:0}\n\nh: +{y:0.000}";
			}
			else
			{
				hoverInfo.Text = $"x: {val.x:0}, y: {val.y:0.000}, z: {val.z:0}";
			}
			tertiary.Enabled = true;
		}
	}
	public class SquarePathOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			base.Initialize();
			SpeedUp(secondary);
			VisualizeRecoloringBounds(secondary);
		}

		protected override void OnRefresh()
		{
			base.OnRefresh();
			primary.Enabled = false;
			secondary.Enabled = true;
		}
	}
	public class CultivateOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			base.Initialize();
			SpeedUp(secondary);
			VisualizeRecoloringBounds(secondary);
		}

		protected override void OnRefresh()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			base.OnRefresh();
			primary.Enabled = false;
			secondary.Enabled = true;
			hoverInfo.Color = secondary.Color;
		}
	}
	public class SeedGrassOverlayVisualizer : HoverInfoEnabled
	{
		protected override void Initialize()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			base.Initialize();
			Freeze(secondary);
			VisualizeRecoloringBounds(secondary);
			primary.StartSize = 4f;
			primary.LocalPosition = new Vector3(0f, 2.5f, 0f);
		}

		protected override void OnRefresh()
		{
			base.OnRefresh();
			primary.Enabled = true;
			secondary.Enabled = true;
		}
	}
	public class RemoveModificationsOverlayVisualizer : OverlayVisualizer
	{
		protected override void Initialize()
		{
			Freeze(primary);
			SpeedUp(secondary);
			VisualizeTerraformingBounds(primary);
			VisualizeIconInsideTerraformingBounds(secondary, (Texture)(object)IconCache.Cross);
		}

		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.Properties
{
	[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
	[DebuggerNonUserCode]
	[CompilerGenerated]
	internal class Resources
	{
		private static ResourceManager resourceMan;

		private static CultureInfo resourceCulture;

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static ResourceManager ResourceManager
		{
			get
			{
				if (resourceMan == null)
				{
					resourceMan = new ResourceManager("TerrainTools.Properties.Resources", typeof(Resources).Assembly);
				}
				return resourceMan;
			}
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static CultureInfo Culture
		{
			get
			{
				return resourceCulture;
			}
			set
			{
				resourceCulture = value;
			}
		}

		internal static Bitmap box => (Bitmap)ResourceManager.GetObject("box", resourceCulture);

		internal static Bitmap cross => (Bitmap)ResourceManager.GetObject("cross", resourceCulture);

		internal static Bitmap cultivate_v2_path => (Bitmap)ResourceManager.GetObject("cultivate_v2_path", resourceCulture);

		internal static Bitmap cultivate_v2_path_square => (Bitmap)ResourceManager.GetObject("cultivate_v2_path_square", resourceCulture);

		internal static Bitmap cultivate_v2_square => (Bitmap)ResourceManager.GetObject("cultivate_v2_square", resourceCulture);

		internal static Bitmap mud_road_v2_square => (Bitmap)ResourceManager.GetObject("mud_road_v2_square", resourceCulture);

		internal static Bitmap path_v2_square => (Bitmap)ResourceManager.GetObject("path_v2_square", resourceCulture);

		internal static Bitmap paved_road_v2_path => (Bitmap)ResourceManager.GetObject("paved_road_v2_path", resourceCulture);

		internal static Bitmap paved_road_v2_path_square => (Bitmap)ResourceManager.GetObject("paved_road_v2_path_square", resourceCulture);

		internal static Bitmap paved_road_v2_square => (Bitmap)ResourceManager.GetObject("paved_road_v2_square", resourceCulture);

		internal static Bitmap raise => (Bitmap)ResourceManager.GetObject("raise", resourceCulture);

		internal static Bitmap raise_v2_square => (Bitmap)ResourceManager.GetObject("raise_v2_square", resourceCulture);

		internal static Bitmap redo => (Bitmap)ResourceManager.GetObject("redo", resourceCulture);

		internal static Bitmap remove => (Bitmap)ResourceManager.GetObject("remove", resourceCulture);

		internal static Bitmap replant_v2_square => (Bitmap)ResourceManager.GetObject("replant_v2_square", resourceCulture);

		internal static Bitmap smooth => (Bitmap)ResourceManager.GetObject("smooth", resourceCulture);

		internal static Bitmap undo => (Bitmap)ResourceManager.GetObject("undo", resourceCulture);

		internal Resources()
		{
		}
	}
}
namespace TerrainTools.Patches
{
	[HarmonyPatch(typeof(GameCamera))]
	internal class GameCameraPatch
	{
		[HarmonyTranspiler]
		[HarmonyPatch("UpdateCamera")]
		private static IEnumerable<CodeInstruction> UpdateCameraTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Player), "CanRotatePiece", (Type[])null, (Type[])null), (string)null)
			}).SetInstructionAndAdvance(Transpilers.EmitDelegate<Func<Player, bool>>((Func<Player, bool>)UpdateCamera_BlockScroll_Delegate)).InstructionEnumeration();
		}

		private static bool UpdateCamera_BlockScroll_Delegate(Player localPlayer)
		{
			Piece val = ((localPlayer != null) ? localPlayer.GetSelectedPiece() : null);
			if ((Object)(object)((val != null) ? ((Component)val).gameObject : null) != (Object)null && (((Component)val).gameObject.HasComponentInChildren<RaiseGroundOverlayVisualizer>(includeInactive: false) || RadiusModifier.ShouldModifyRadius() || HardnessModifier.ShouldModifyHardness()))
			{
				return true;
			}
			return localPlayer.CanRotatePiece();
		}
	}
	[HarmonyPatch(typeof(Player))]
	internal class RenamedNotice
	{
		[HarmonyPostfix]
		[HarmonyPatch("OnSpawned")]
		private static void OnSpawned(Player __instance)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null))
			{
				string text = "This mod has been renamed \"AdvancedTerrainModifiers\"\nPlease download that version instead!";
				MessageHud instance = MessageHud.m_instance;
				instance.m_messageCenterText.text = text;
				instance._crossFadeTextBuffer.Add(new CrossFadeText
				{
					text = instance.m_messageCenterText,
					alpha = 1f,
					time = 0f
				});
				instance._crossFadeTextBuffer.Add(new CrossFadeText
				{
					text = instance.m_messageCenterText,
					alpha = 0f,
					time = 15f
				});
			}
		}
	}
}
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;

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


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

		private static float ScrollDelta()
		{
			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 class HardnessModifier
	{
		[HarmonyPatch(typeof(Player))]
		internal class PlayerPatch
		{
			[HarmonyPrefix]
			[HarmonyPriority(300)]
			[HarmonyPatch("Update")]
			private static void UpdatePrefix(Player __instance)
			{
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || !((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible())
				{
					if (lastOriginalPower != 0f)
					{
						lastOriginalPower = 0f;
						lastModdedPower = 0f;
						lastTotalDelta = 0f;
						SetPower(__instance, 0f);
					}
				}
				else if (ShouldModifyHardness())
				{
					SetPower(__instance, Input.mouseScrollDelta.y * TerrainTools.RadiusScrollScale);
				}
			}
		}

		[HarmonyPatch(typeof(TerrainOp))]
		internal class TerrainOpPatch
		{
			[HarmonyPrefix]
			[HarmonyPriority(600)]
			[HarmonyPatch("Awake")]
			private static void AwakePrefix(TerrainOp __instance)
			{
				if (__instance != null && ((Component)__instance).gameObject != null && !((Component)__instance).gameObject.HasComponent<OverlayVisualizer>())
				{
					if (__instance.m_settings.m_raise)
					{
						__instance.m_settings.m_raisePower = ModifyPower(__instance.m_settings.m_raisePower, lastTotalDelta);
						Log.LogInfo($"Applying raise Power {__instance.m_settings.m_raisePower}", LogLevel.Medium);
					}
					if (__instance.m_settings.m_smooth)
					{
						__instance.m_settings.m_smoothPower = ModifyPower(__instance.m_settings.m_smoothPower, lastTotalDelta);
						Log.LogInfo($"Applying smooth Power {__instance.m_settings.m_smoothPower}", LogLevel.Medium);
					}
				}
			}
		}

		internal static float lastOriginalPower;

		internal static float lastModdedPower;

		internal static float lastTotalDelta;

		private static float lastDisplayedPower;

		private const float MinPower = 1f;

		private const float MaxPower = 30f;

		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;
		}

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

		private static void SetPower(Player player, float delta)
		{
			Piece selectedPiece = player.GetSelectedPiece();
			if (selectedPiece == null || ((Component)selectedPiece).gameObject == null || ((Component)selectedPiece).gameObject.HasComponent<OverlayVisualizer>())
			{
				return;
			}
			TerrainOp component = ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Log.LogInfo($"Adjusting Power by {delta}", LogLevel.Medium);
			float num = 0f;
			float num2 = ModifyPower(lastModdedPower, delta);
			lastTotalDelta += delta;
			if (lastOriginalPower == 0f)
			{
				if (component.m_settings.m_raise && num < component.m_settings.m_raisePower)
				{
					num = component.m_settings.m_raisePower;
					num2 = ModifyPower(component.m_settings.m_raisePower, delta);
				}
				if (component.m_settings.m_smooth && num < component.m_settings.m_smoothPower)
				{
					num = component.m_settings.m_smoothPower;
					num2 = ModifyPower(component.m_settings.m_smoothPower, delta);
				}
				lastOriginalPower = num;
			}
			lastModdedPower = num2;
			if (lastOriginalPower > 0f && Mathf.Abs(lastDisplayedPower - lastModdedPower) >= 1f)
			{
				Log.LogInfo($"total delta {lastTotalDelta}", LogLevel.Medium);
				GameObject placementGhost = player.m_placementGhost;
				Sprite val = ((placementGhost == null) ? null : placementGhost.GetComponent<Piece>()?.m_icon);
				if ((Object)(object)val != (Object)null)
				{
					lastDisplayedPower = Mathf.Round(num2);
					((Character)player).Message((MessageType)2, $"Terrain tool hardness: {lastDisplayedPower}", 0, val);
				}
			}
		}
	}
	internal class InitManager
	{
		private static bool HasInitialized = 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>>
		{
			{
				PieceTables.Hoe,
				new List<int>()
			},
			{
				PieceTables.Cultivator,
				new List<int>()
			}
		};

		internal static void InitToolPieces()
		{
			if (HasInitialized)
			{
				return;
			}
			FixVanillaToolDescriptions();
			foreach (string key in ToolConfigs.ToolConfigsMap.Keys)
			{
				try
				{
					ToolDB toolDB = ToolConfigs.ToolConfigsMap[key];
					GameObject val = MakeToolPiece(toolDB);
					RegisterPieceInPieceTable(val, toolDB.pieceTable, null, toolDB.insertIndex);
					ToolRefs.Add(key, val);
				}
				catch
				{
					Log.LogWarning("Failed to create: " + key);
				}
			}
			HasInitialized = true;
		}

		internal static void FixVanillaToolDescriptions()
		{
			SetDescription("mud_road_v2", "Levels ground. (Use shift + click to level ground based on where you are pointing)");
			SetDescription("raise_v2", "Raise ground based on player position. (Use shift + click to raise ground based on where you are pointing)");
			SetDescription("path_v2", "Creates a dirt path without affecting ground height.");
			SetDescription("paved_road_v2", "Creates a paved path and levels ground based on player position. (Use shift+click to level ground based on where you are pointing)");
			SetDescription("cultivate_v2", "Cultivates ground and levels ground based on player position. (Use shift + click to level ground based on where you are pointing)");
			SetDescription("replant_v2", "Replants terrain without affecting ground height.");
		}

		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()
		{
			if (!HasInitialized)
			{
				return;
			}
			ForceUnequipTerrainTools();
			foreach (string key in ToolRefs.Keys)
			{
				ToolRefs[key].GetComponent<Piece>().m_enabled = TerrainTools.IsToolEnabled(key);
			}
		}

		private static void ForceUnequipTerrainTools()
		{
			Player localPlayer = Player.m_localPlayer;
			if (((localPlayer == null) ? null : ((Humanoid)localPlayer).GetRightItem()?.m_shared.m_name) == "$item_cultivator")
			{
				Log.LogWarning("Terrain Tools updated through config change, unequipping cultivator");
				((Humanoid)Player.m_localPlayer).HideHandItems();
			}
			Player localPlayer2 = Player.m_localPlayer;
			if (((localPlayer2 == null) ? null : ((Humanoid)localPlayer2).GetRightItem()?.m_shared.m_name) == "$item_hoe")
			{
				Log.LogWarning("Terrain Tools updated through config change, unequipping hoe");
				((Humanoid)Player.m_localPlayer).HideHandItems();
			}
		}

		internal static GameObject MakeToolPiece(ToolDB toolDB)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (PieceManager.Instance.GetPiece(toolDB.pieceName) != null)
			{
				return null;
			}
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(toolDB.name, toolDB.basePrefab);
			if (toolDB == 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;
			Settings settings = val.GetComponent<TerrainOp>().m_settings;
			settings.m_level = (toolDB.level.HasValue ? toolDB.level.Value : settings.m_level);
			settings.m_raise = (toolDB.raise.HasValue ? toolDB.raise.Value : settings.m_raise);
			settings.m_smooth = (toolDB.smooth.HasValue ? toolDB.smooth.Value : settings.m_smooth);
			settings.m_paintCleared = (toolDB.clearPaint.HasValue ? toolDB.clearPaint.Value : settings.m_paintCleared);
			if (toolDB.overlayType != null)
			{
				val.AddComponent(toolDB.overlayType);
			}
			return val;
		}

		private static void RegisterPieceInPieceTable(GameObject prefab, string pieceTable, string category, int position = -1)
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			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);
			}
			if (pieceTable2.m_pieces.Contains(prefab))
			{
				Log.LogDebug("Already added piece " + ((Object)prefab).name);
				return;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
			if ((Object)(object)ZNetScene.instance != (Object)null && !ZNetScene.instance.m_namedPrefabs.ContainsKey(stableHashCode))
			{
				PrefabManager.Instance.RegisterToZNetScene(prefab);
			}
			if (!string.IsNullOrEmpty(category))
			{
				component.m_category = PieceManager.Instance.AddPieceCategory(pieceTable, category);
			}
			if (position < 0)
			{
				pieceTable2.m_pieces.Add(prefab);
				InsertionIndexes[pieceTable].Add(pieceTable2.m_pieces.Count - 1);
			}
			else
			{
				int index = position + InsertionIndexes[pieceTable].Where((int x) => x <= position).Count();
				pieceTable2.m_pieces.Insert(index, prefab);
				InsertionIndexes[pieceTable].Add(position);
			}
			Log.LogDebug("Added piece " + ((Object)prefab).name + " | Token: " + PieceExtension.TokenName(component));
		}
	}
	[HarmonyPatch(typeof(TerrainComp))]
	public static class PreciseTerrainModifier
	{
		public const int SizeInTiles = 1;

		[HarmonyPrefix]
		[HarmonyPatch("InternalDoOperation")]
		private static bool InternalDoOperationPrefix(TerrainComp __instance, Vector3 pos, Settings modifier)
		{
			//IL_0020: 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)
			if (!modifier.m_level && !modifier.m_raise && !modifier.m_smooth && !modifier.m_paintCleared)
			{
				RemoveTerrainModifications(pos, __instance.m_hmap, __instance.m_width, ref __instance.m_levelDelta, ref __instance.m_smoothDelta, ref __instance.m_modifiedHeight);
				RecolorTerrain(pos, (PaintType)3, __instance.m_hmap, __instance.m_width, ref __instance.m_paintMask, ref __instance.m_modifiedPaint);
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("SmoothTerrain")]
		private static bool SmoothTerrianPrefix(TerrainComp __instance, Vector3 worldPos, float radius)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (IsGridModeEnabled(radius))
			{
				SmoothenTerrain(__instance, worldPos, __instance.m_hmap, __instance.m_width, ref __instance.m_smoothDelta, ref __instance.m_modifiedHeight);
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("RaiseTerrain")]
		private static bool RaiseTerrainPrefix(TerrainComp __instance, Vector3 worldPos, float radius, float delta)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (IsGridModeEnabled(radius))
			{
				RaiseTerrain(__instance, worldPos, __instance.m_hmap, __instance.m_width, delta, ref __instance.m_levelDelta, ref __instance.m_smoothDelta, ref __instance.m_modifiedHeight);
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("PaintCleared")]
		private static bool PreciseColorModificaton(TerrainComp __instance, Vector3 worldPos, float radius, PaintType paintType)
		{
			//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)
			if (IsGridModeEnabled(radius))
			{
				RecolorTerrain(worldPos, paintType, __instance.m_hmap, __instance.m_width, ref __instance.m_paintMask, ref __instance.m_modifiedPaint);
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("ApplyOperation")]
		private static void ClientSideGridModeOverride(TerrainOp modifier)
		{
			if (!((Object)(object)((modifier != null) ? ((Component)modifier).gameObject : null) == (Object)null) && ((Component)modifier).gameObject.HasComponentInChildren<OverlayVisualizer>(includeInactive: false))
			{
				if (modifier.m_settings.m_smooth)
				{
					modifier.m_settings.m_smoothRadius = float.NegativeInfinity;
				}
				if (modifier.m_settings.m_raise && modifier.m_settings.m_raiseDelta >= 0f)
				{
					modifier.m_settings.m_raiseRadius = float.NegativeInfinity;
					modifier.m_settings.m_raiseDelta = GroundLevelSpinner.Value;
				}
				if (modifier.m_settings.m_paintCleared)
				{
					modifier.m_settings.m_paintRadius = float.NegativeInfinity;
				}
			}
		}

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

		public static void SmoothenTerrain(TerrainComp compiler, Vector3 worldPos, Heightmap hMap, int worldWidth, ref float[] smoothDelta, ref bool[] modifiedHeight)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			Log.LogInfo("[INIT] Smooth Terrain Modification", LogLevel.Medium);
			int num = worldWidth + 1;
			int num2 = default(int);
			int num3 = default(int);
			hMap.WorldToVertex(worldPos, ref num2, ref num3);
			float num4 = worldPos.y - ((Component)compiler).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 = hMap.GetHeight(i, j);
					float num6 = num4 - height;
					float num7 = smoothDelta[num5];
					float num8 = num7 + num6;
					float num9 = RoundToTwoDecimals(height, num7, num8);
					float num10 = Mathf.Clamp(num9, -1f, 1f);
					smoothDelta[num5] = num10;
					modifiedHeight[num5] = true;
					Log.LogInfo($"tilePos: ({i}, {j}), tileH: {height}, deltaH: {num6}, oldDeltaH: {num7}, newDeltaH: {num8}, roundedNewDeltaH: {num9}, limDeltaH: {num10}", LogLevel.Medium);
				}
			}
			Log.LogInfo("[SUCCESS] Smooth Terrain Modification", LogLevel.Medium);
		}

		public static void RaiseTerrain(TerrainComp compiler, Vector3 worldPos, Heightmap hMap, int worldWidth, float power, ref float[] levelDelta, ref float[] smoothDelta, ref bool[] modifiedHeight)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			Log.LogInfo("[INIT] Raise Terrain Modification", LogLevel.Medium);
			int num = worldWidth + 1;
			int num2 = default(int);
			int num3 = default(int);
			hMap.WorldToVertex(worldPos, ref num2, ref num3);
			float num4 = worldPos.y - ((Component)compiler).transform.position.y + power;
			Log.LogInfo($"worldPos: {worldPos}, xPos: {num2}, yPos: {num3}, power: {power}, 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 = hMap.GetHeight(i, j);
					float num6 = num4 - height;
					if (num6 >= 0f)
					{
						float num7 = levelDelta[num5];
						float num8 = smoothDelta[num5];
						float num9 = num7 + num8 + num6;
						float num10 = 0f;
						float num11 = RoundToTwoDecimals(height, num7 + num8, num9 + num10);
						float num12 = Mathf.Clamp(num11, -16f, 16f);
						levelDelta[num5] = num12;
						smoothDelta[num5] = num10;
						modifiedHeight[num5] = true;
						Log.LogInfo($"tilePos: ({i}, {j}), tileH: {height}, deltaH: {num6}, oldLevelDelta: {num7}, oldSmoothDelta: {num8}, newLevelDelta: {num9}, newSmoothDelta: {num10}, roundedNewLevelDelta: {num11}, limitedNewLevelDelta: {num12}", LogLevel.Medium);
					}
					else
					{
						Log.LogInfo("Declined to process tile: deltaH < 0!", LogLevel.Medium);
						Log.LogInfo($"tilePos: ({i}, {j}), tileH: {height}, deltaH: {num6}", LogLevel.Medium);
					}
				}
			}
			Log.LogInfo("[SUCCESS] Raise Terrain Modification", LogLevel.Medium);
		}

		public static void RemoveTerrainModifications(Vector3 worldPos, Heightmap hMap, int worldWidth, ref float[] levelDelta, ref float[] smoothDelta, ref bool[] modifiedHeight)
		{
			//IL_0010: 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)
			Log.LogInfo("[INIT] Remove Terrain Modifications", LogLevel.Medium);
			int num = worldWidth + 1;
			int num2 = default(int);
			int num3 = default(int);
			hMap.WorldToVertex(worldPos, ref num2, ref num3);
			Log.LogInfo($"worldPos: {worldPos}, vertexPos: ({num2}, {num3})", 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 num4 = j * num + i;
					levelDelta[num4] = 0f;
					smoothDelta[num4] = 0f;
					modifiedHeight[num4] = false;
					Log.LogInfo($"tilePos: ({i}, {j}), tileIndex: {num4}", LogLevel.Medium);
				}
			}
			Log.LogInfo("[SUCCESS] Remove Terrain Modifications", LogLevel.Medium);
		}

		public static void RecolorTerrain(Vector3 worldPos, PaintType paintType, Heightmap hMap, int worldWidth, ref Color[] paintMask, ref bool[] modifiedPaint)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			Log.LogInfo("[INIT] Color Terrain Modification", LogLevel.Medium);
			int num = default(int);
			int num2 = default(int);
			hMap.WorldToVertex(worldPos, ref num, ref num2);
			Log.LogInfo($"worldPos: {worldPos}, vertexPos: ({num}, {num2})", LogLevel.Medium);
			Color val = ResolveColor(paintType);
			bool flag = val == Color.black;
			FindExtrema(num, worldWidth, out var xMin, out var xMax);
			FindExtrema(num2, worldWidth, out var xMin2, out var xMax2);
			for (int i = xMin; i <= xMax; i++)
			{
				for (int j = xMin2; j <= xMax2; j++)
				{
					int num3 = j * worldWidth + i;
					paintMask[num3] = val;
					modifiedPaint[num3] = !flag;
					Log.LogInfo($"tilePos: ({i}, {j}), tileIndex: {num3}, tileColor: {val}", LogLevel.Medium);
				}
			}
			Log.LogInfo("[SUCCESS] Color Terrain Modification", LogLevel.Medium);
		}

		public static Color ResolveColor(PaintType paintType)
		{
			//IL_0000: 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_000b: Invalid comparison between Unknown and I4
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if ((int)paintType == 0)
			{
				return Color.red;
			}
			if ((int)paintType == 2)
			{
				return Color.blue;
			}
			if ((int)paintType == 1)
			{
				return Color.green;
			}
			return Color.black;
		}

		public static void FindExtrema(int x, int worldSize, out int xMin, out int xMax)
		{
			xMin = Mathf.Max(0, x - 1);
			xMax = Mathf.Min(x + 1, worldSize - 1);
		}

		public static float RoundToTwoDecimals(float oldH, float oldDeltaH, float newDeltaH)
		{
			float num = oldH - oldDeltaH + newDeltaH;
			float num2 = Mathf.Round(num * 100f) / 100f;
			float num3 = num2 - oldH + oldDeltaH;
			Log.LogInfo($"oldH: {oldH}, oldDeltaH: {oldDeltaH}, newDeltaH: {newDeltaH}, newH: {num}, roundedNewH: {num2}, roundedNewDeltaH: {num3}", LogLevel.Medium);
			return num3;
		}
	}
	[HarmonyPatch]
	internal class RadiusModifier
	{
		[HarmonyPatch(typeof(Player))]
		internal class PlayerPatch
		{
			[HarmonyPrefix]
			[HarmonyPatch("Update")]
			private static void UpdatePrefix(Player __instance)
			{
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || !((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible())
				{
					if (lastOriginalRadius != 0f)
					{
						lastOriginalRadius = 0f;
						lastModdedRadius = 0f;
						lastTotalDelta = 0f;
						SetRadius(__instance, 0f);
					}
				}
				else if (ShouldModifyRadius())
				{
					SetRadius(__instance, Input.mouseScrollDelta.y * TerrainTools.RadiusScrollScale);
				}
			}
		}

		[HarmonyPatch(typeof(TerrainOp))]
		internal class TerrainOpPatch
		{
			[HarmonyPrefix]
			[HarmonyPriority(700)]
			[HarmonyPatch("Awake")]
			private static void AwakePrefix(TerrainOp __instance)
			{
				if (__instance != null && ((Component)__instance).gameObject != null && !((Component)__instance).gameObject.HasComponent<OverlayVisualizer>())
				{
					if (__instance.m_settings.m_level)
					{
						__instance.m_settings.m_levelRadius = ModifyRadius(__instance.m_settings.m_levelRadius, lastTotalDelta);
						Log.LogInfo($"Applying level radius {__instance.m_settings.m_levelRadius}", LogLevel.Medium);
					}
					if (__instance.m_settings.m_raise)
					{
						__instance.m_settings.m_raiseRadius = ModifyRadius(__instance.m_settings.m_raiseRadius, lastTotalDelta);
						Log.LogInfo($"Applying raise radius {__instance.m_settings.m_raiseRadius}", LogLevel.Medium);
					}
					if (__instance.m_settings.m_smooth)
					{
						__instance.m_settings.m_smoothRadius = ModifyRadius(__instance.m_settings.m_smoothRadius, lastTotalDelta);
						Log.LogInfo($"Applying smooth radius {__instance.m_settings.m_smoothRadius}", LogLevel.Medium);
					}
					if (__instance.m_settings.m_paintCleared)
					{
						__instance.m_settings.m_paintRadius = ModifyRadius(__instance.m_settings.m_paintRadius, lastTotalDelta);
						Log.LogInfo($"Applying paint radius {__instance.m_settings.m_paintRadius}", LogLevel.Medium);
					}
				}
			}
		}

		internal static float lastOriginalRadius;

		internal static float lastModdedRadius;

		internal static float lastTotalDelta;

		private const float MinRadius = 0.5f;

		internal static bool ShouldModifyRadius()
		{
			//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.IsEnableRadiusModifier && Input.GetKey(TerrainTools.RadiusKey))
			{
				return Input.mouseScrollDelta.y != 0f;
			}
			return false;
		}

		private static float ModifyRadius(float radius, float delta)
		{
			return Mathf.Clamp(radius + delta, 0.5f, TerrainTools.MaxRadius);
		}

		private static void SetRadius(Player player, float delta)
		{
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			Piece selectedPiece = player.GetSelectedPiece();
			if (selectedPiece == null || ((Component)selectedPiece).gameObject == null || ((Component)selectedPiece).gameObject.HasComponent<OverlayVisualizer>())
			{
				return;
			}
			TerrainOp component = ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Log.LogInfo($"Adjusting radius by {delta}", LogLevel.Medium);
			float num = 0f;
			float num2 = ModifyRadius(lastModdedRadius, delta);
			lastTotalDelta += delta;
			if (lastOriginalRadius == 0f)
			{
				if (component.m_settings.m_level && num < component.m_settings.m_levelRadius)
				{
					num = component.m_settings.m_levelRadius;
					num2 = ModifyRadius(component.m_settings.m_levelRadius, delta);
				}
				if (component.m_settings.m_raise && num < component.m_settings.m_raiseRadius)
				{
					num = component.m_settings.m_raiseRadius;
					num2 = ModifyRadius(component.m_settings.m_raiseRadius, delta);
				}
				if (component.m_settings.m_smooth && num < component.m_settings.m_smoothRadius)
				{
					num = component.m_settings.m_smoothRadius;
					num2 = ModifyRadius(component.m_settings.m_smoothRadius, delta);
				}
				if (component.m_settings.m_paintCleared && num < component.m_settings.m_paintRadius)
				{
					num = component.m_settings.m_paintRadius;
					num2 = ModifyRadius(component.m_settings.m_paintRadius, delta);
				}
				lastOriginalRadius = num;
			}
			lastModdedRadius = num2;
			if (lastOriginalRadius > 0f && lastModdedRadius > 0f)
			{
				Log.LogInfo($"total delta {lastTotalDelta}", LogLevel.Medium);
				GameObject placementGhost = player.m_placementGhost;
				Transform val = ((placementGhost != null) ? placementGhost.transform.Find("_GhostOnly") : null);
				if ((Object)(object)val != (Object)null)
				{
					Log.LogInfo($"Adjusting ghost scale to {lastModdedRadius / lastOriginalRadius}x", LogLevel.Medium);
					val.localScale = new Vector3(lastModdedRadius / lastOriginalRadius, lastModdedRadius / lastOriginalRadius, lastModdedRadius / lastOriginalRadius);
				}
			}
		}
	}
}
namespace TerrainTools.Extensions
{
	internal static class EventExtensions
	{
		public static void SafeInvoke(this Action events)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action action = (Action)invocationList[i];
				try
				{
					action();
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TArg1>(this Action<TArg1> events, TArg1 arg1)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<TArg1> action = (Action<TArg1>)invocationList[i];
				try
				{
					action(arg1);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TArg1, TArg2>(this Action<TArg1, TArg2> events, TArg1 arg1, TArg2 arg2)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<TArg1, TArg2> action = (Action<TArg1, TArg2>)invocationList[i];
				try
				{
					action(arg1, arg2);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TEventArg>(this EventHandler<TEventArg> events, object sender, TEventArg arg1)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				EventHandler<TEventArg> eventHandler = (EventHandler<TEventArg>)invocationList[i];
				try
				{
					eventHandler(sender, arg1);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {eventHandler.Method.DeclaringType.Name}.{eventHandler.Method.Name}:\n{ex}");
				}
			}
		}
	}
	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 HasComponent<T>(this GameObject gameObject) where T : Component
		{
			return (Object)(object)gameObject.GetComponent<T>() != (Object)null;
		}

		public static bool HasComponent(this GameObject gameObject, string componentName)
		{
			return (Object)(object)gameObject.GetComponent(componentName) != (Object)null;
		}

		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]);
			}
		}

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

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

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

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

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

		public static bool HasComponentInChildren<T>(this GameObject gameObject, bool includeInactive = false) where T : Component
		{
			return (Object)(object)gameObject.GetComponentInChildren<T>(includeInactive) != (Object)null;
		}

		internal static T GetComponentInChildrenByName<T>(this GameObject gameObject, string name, bool includeInactive = false) where T : Component
		{
			T[] componentsInChildren = gameObject.GetComponentsInChildren<T>(includeInactive);
			foreach (T val in componentsInChildren)
			{
				if (((Object)(object)val).name == name)
				{
					return val;
				}
			}
			Log.LogWarning("No T with name " + name + " found for GameObject: " + ((Object)gameObject).name);
			return default(T);
		}

		internal static Mesh GetMesh(this GameObject gameObject, string meshName)
		{
			MeshFilter[] componentsInChildren = gameObject.GetComponentsInChildren<MeshFilter>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Mesh mesh = componentsInChildren[i].mesh;
				if (!((Object)(object)mesh == (Object)null) && ((Object)mesh).name.RemoveSuffix("Instance").Trim() == meshName)
				{
					return mesh;
				}
			}
			Log.LogWarning("Could not find Mesh: " + meshName + " for GameObject: " + ((Object)gameObject).name);
			return null;
		}
	}
	internal static class TypeExtensions
	{
		internal static List<T> GetAllPublicConstantValues<T>(this Type type)
		{
			return (from fi in type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy)
				where fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(T)
				select fi into x
				select (T)x.GetRawConstantValue()).ToList();
		}

		internal static List<T> GetAllPublicStaticValues<T>(this Type type)
		{
			return (from fi in type.GetFields(BindingFlags.Static | BindingFlags.Public)
				where fi.FieldType == typeof(T)
				select fi into x
				select (T)x.GetValue(null)).ToList();
		}
	}
	internal static class GenericExtensions
	{
		private const BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;

		public static void CopyFields(this object target, object source)
		{
			if (target == null || source == null)
			{
				throw new Exception("Target or/and Source Objects are null");
			}
			Type type = source.GetType();
			FieldInfo[] fields = target.GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
			foreach (FieldInfo fieldInfo in fields)
			{
				FieldInfo field = type.GetField(fieldInfo.Name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
				if (!(field == null) && field.IsInitOnly && field.FieldType.IsAssignableFrom(fieldInfo.FieldType))
				{
					field.SetValue(source, fieldInfo.GetValue(target));
				}
			}
		}

		internal static T Ref<T>(this T o) where T : Object
		{
			if (!Object.op_Implicit((Object)(object)o))
			{
				return default(T);
			}
			return o;
		}
	}
	internal static class IEnumerableExtensions
	{
		internal static void Dispose(this IEnumerable<IDisposable> collection)
		{
			foreach (IDisposable item in collection)
			{
				if (item != null)
				{
					try
					{
						item.Dispose();
					}
					catch (Exception)
					{
						Log.LogWarning("Could not dispose of item");
					}
				}
			}
		}
	}
	internal static class ReflectionUtils
	{
		public const BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;

		internal static MethodInfo GetMethod(Type type, string name, Type[] types)
		{
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == name && HasMatchingParameterTypes(0, types, methodInfo.GetParameters()))
				{
					return methodInfo;
				}
			}
			return null;
		}

		internal static MethodInfo GetGenericMethod(Type type, string name, int genericParameterCount, Type[] types)
		{
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.IsGenericMethod && methodInfo.ContainsGenericParameters && methodInfo.Name == name && HasMatchingParameterTypes(genericParameterCount, types, methodInfo.GetParameters()))
				{
					return methodInfo;
				}
			}
			return null;
		}

		private static bool HasMatchingParameterTypes(int genericParameterCount, Type[] types, ParameterInfo[] parameters)
		{
			if (parameters.Length < genericParameterCount || parameters.Length != types.Length)
			{
				return false;
			}
			int num = 0;
			for (int i = 0; i < parameters.Length; i++)
			{
				if (parameters[i].ParameterType.IsGenericParameter)
				{
					num++;
				}
				else if (types[i] != parameters[i].ParameterType)
				{
					return false;
				}
			}
			if (num != genericParameterCount)
			{
				return false;
			}
			return true;
		}
	}
	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);
		}

		internal static string EmptyIfNull(this object value)
		{
			if (value == null)
			{
				return string.Empty;
			}
			return value.ToString();
		}
	}
	internal static class TransformExtensions
	{
		public static Transform FindDeepChild(this Transform transform, string childName, bool breadthFirst = true)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			if (breadthFirst)
			{
				Queue<Transform> queue = new Queue<Transform>();
				queue.Enqueue(transform);
				while (queue.Count > 0)
				{
					Transform val = queue.Dequeue();
					if (((Object)val).name == childName)
					{
						return val;
					}
					foreach (Transform item2 in val)
					{
						Transform item = item2;
						queue.Enqueue(item);
					}
				}
				return null;
			}
			foreach (Transform item3 in transform)
			{
				Transform val2 = item3;
				if (((Object)val2).name == childName)
				{
					return val2;
				}
				Transform val3 = val2.FindDeepChild(childName);
				if ((Object)(object)val3 != (Object)null)
				{
					return val3;
				}
			}
			return null;
		}
	}
}
namespace TerrainTools.Configs
{
	internal class ConfigManager
	{
		private static string ConfigFileName;

		private static string ConfigFileFullPath;

		private static ConfigFile configFile;

		private static BaseUnityPlugin ConfigurationManager;

		private const string ConfigManagerGUID = "com.bepis.bepinex.configurationmanager";

		private static readonly ConfigurationManagerAttributes AdminConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		};

		private static readonly ConfigurationManagerAttributes ClientConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = false
		};

		private const char ZWS = '\u200b';

		internal static event Action OnConfigWindowClosed;

		internal static event Action OnConfigFileReloaded;

		private static void InvokeOnConfigWindowClosed()
		{
			ConfigManager.OnConfigWindowClosed?.SafeInvoke();
		}

		private static void InvokeOnConfigFileReloaded()
		{
			ConfigManager.OnConfigFileReloaded?.SafeInvoke();
		}

		internal static ConfigEntry<T> BindConfig<T>(string section, string name, T value, string description, AcceptableValueBase acceptVals = null, bool synced = true)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			string extendedDescription = GetExtendedDescription(description, synced);
			return configFile.Bind<T>(section, name, value, new ConfigDescription(extendedDescription, acceptVals, new object[1] { synced ? AdminConfig : ClientConfig }));
		}

		internal static string SetStringPriority(string sectionName, int priority)
		{
			if (priority == 0)
			{
				return sectionName;
			}
			return new string('\u200b', priority) + sectionName;
		}

		internal static string GetExtendedDescription(string description, bool synchronizedSetting)
		{
			return description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]");
		}

		internal static void Init(string GUID, ConfigFile config)
		{
			configFile = config;
			configFile.SaveOnConfigSet = false;
			ConfigFileName = GUID + ".cfg";
			ConfigFileFullPath = Path.Combine(Paths.ConfigPath, ConfigFileName);
		}

		private static bool DisableSaveOnConfigSet()
		{
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			return saveOnConfigSet;
		}

		internal static void SaveOnConfigSet(bool value)
		{
			configFile.SaveOnConfigSet = value;
		}

		internal static void Save()
		{
			configFile.Save();
		}

		internal static void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReloadConfigFile;
			fileSystemWatcher.Created += ReloadConfigFile;
			fileSystemWatcher.Renamed += ReloadConfigFile;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private static void ReloadConfigFile(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				Log.LogInfo("Reloading config file");
				bool value = DisableSaveOnConfigSet();
				configFile.Reload();
				SaveOnConfigSet(value);
				InvokeOnConfigFileReloaded();
			}
			catch
			{
				Log.LogError("There was an issue loading your " + ConfigFileName);
				Log.LogError("Please check your config entries for spelling and format!");
			}
		}

		internal static void CheckForConfigManager()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)SystemInfo.graphicsDeviceType != 4 && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				ConfigurationManager = value.Instance;
				Log.LogDebug("Configuration manager found, hooking DisplayingWindowChanged");
				EventInfo @event = ((object)ConfigurationManager).GetType().GetEvent("DisplayingWindowChanged");
				if (@event != null)
				{
					Action<object, object> action = OnConfigManagerDisplayingWindowChanged;
					Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method);
					@event.AddEventHandler(ConfigurationManager, handler);
				}
			}
		}

		private static void OnConfigManagerDisplayingWindowChanged(object sender, object e)
		{
			if (!(bool)((object)ConfigurationManager).GetType().GetProperty("DisplayingWindow").GetValue(ConfigurationManager, null))
			{
				InvokeOnConfigWindowClosed();
			}
		}
	}
	internal class ToolConfigs
	{
		internal static Dictionary<string, ToolDB> ToolConfigsMap;

		static ToolConfigs()
		{
			Dictionary<string, ToolDB> obj = new Dictionary<string, ToolDB>
			{
				{
					"mud_road_v2_sq",
					new ToolDB("mud_road_v2_sq", "mud_road_v2", "Level ground(square)", "Levels ground according to the world grid based on player position. (Use shift+click to level ground based on where you are pointing instead)", IconCache.MudRoadSquare, PieceTables.Hoe, 1, typeof(LevelGroundOverlayVisualizer))
				},
				{
					"raise_v2_precise",
					new ToolDB("raise_v2_precise", "raise_v2", "Raise ground (precision)", "Raise ground with precision accuracy by using scroll wheel to set ground height.", IconCache.RaiseSquare, PieceTables.Hoe, 2, typeof(RaiseGroundOverlayVisualizer))
				},
				{
					"path_v2_square",
					new ToolDB("path_v2_square", "path_v2", "Pathen (square)", "Creates a dirt path according to the world grid without affecting ground height.", IconCache.MudRoadPathSquare, PieceTables.Hoe, 3, typeof(SquarePathOverlayVisualizer))
				},
				{
					"paved_road_v2_square",
					new ToolDB("Paved road (Square)", "paved_road_v2", "Paved road (square)", "Creates a paved path according to the world grid and levels ground based on player position. (Use shift+click to level ground based on where you are pointing)", IconCache.PavedRoadSquare, PieceTables.Hoe, -1, typeof(SquarePathOverlayVisualizer))
				}
			};
			Texture2D pavedRoadPath = IconCache.PavedRoadPath;
			string hoe = PieceTables.Hoe;
			bool? smooth = false;
			obj.Add("paved_road_v2_path", new ToolDB("paved_road_v2_path", "paved_road_v2", "Paved road (path)", "Creates a paved path without affecting ground height", pavedRoadPath, hoe, -1, null, null, null, smooth));
			Texture2D pavedRoadPathSquare = IconCache.PavedRoadPathSquare;
			string hoe2 = PieceTables.Hoe;
			Type typeFromHandle = typeof(SquarePathOverlayVisualizer);
			smooth = false;
			obj.Add("paved_road_v2_path_square", new ToolDB("paved_road_v2_path_square", "paved_road_v2", "Paved road (path, square)", "Created a paved path according to the world grid without affecting ground height", pavedRoadPathSquare, hoe2, -1, typeFromHandle, null, null, smooth));
			obj.Add("remove_terrain_mods", new ToolDB("remove_terrain_mods", "mud_road_v2", "Remove Terrain Modifications", "Resets ground height and paint", IconCache.Remove, PieceTables.Hoe, -1, typeof(RemoveModificationsOverlayVisualizer), smooth: false, level: false, raise: false, clearPaint: false));
			obj.Add("cultivate_v2_square", new ToolDB("cultivate_v2_square", "cultivate_v2", "Cultivate (square)", "Cultivates ground according to the world grid and levels terrain based on player position. (Use shift+click to level ground based on where you are pointing)", IconCache.CultivateSquare, PieceTables.Cultivator, 1, typeof(CultivateOverlayVisualizer)));
			Texture2D cultivatePath = IconCache.CultivatePath;
			string cultivator = PieceTables.Cultivator;
			smooth = false;
			obj.Add("cultivate_v2_path", new ToolDB("cultivate_v2_path", "cultivate_v2", "Cultivate (path)", "Cultivates ground without affecting ground height.", cultivatePath, cultivator, 1, null, null, null, smooth));
			Texture2D cultivatePathSquare = IconCache.CultivatePathSquare;
			string cultivator2 = PieceTables.Cultivator;
			Type typeFromHandle3 = typeof(CultivateOverlayVisualizer);
			smooth = false;
			obj.Add("cultivate_v2_path_square", new ToolDB("cultivate_v2_path_square", "cultivate_v2", "Cultivate (path, square)", "Cultivates ground according to the world grid without affecting ground height.", cultivatePathSquare, cultivator2, 1, typeFromHandle3, null, null, smooth));
			obj.Add("replant_v2_square", new ToolDB("replant_v2_square", "replant_v2", "Replant (square)", "Replants terrain according to world grid without affecting ground height.", IconCache.ReplantSquare, PieceTables.Cultivator, 2, typeof(SeedGrassOverlayVisualizer)));
			ToolConfigsMap = obj;
		}
	}
	internal class ToolDB
	{
		public string name;

		public string basePrefab;

		public string pieceName;

		public string pieceDesc;

		public Texture2D icon;

		public string pieceTable;

		public int insertIndex;

		public Type overlayType;

		public bool? level;

		public bool? raise;

		public bool? smooth;

		public bool? clearPaint;

		public ToolDB(string name, string basePrefab, string pieceName, string pieceDesc, Texture2D icon, string pieceTable, int insertIndex = -1, Type overlayType = null, bool? level = null, bool? raise = null, bool? smooth = null, bool? clearPaint = null)
		{
			this.name = name;
			this.basePrefab = basePrefab;
			this.pieceName = pieceName;
			this.pieceDesc = pieceDesc;
			this.icon = icon;
			this.pieceTable = pieceTable;
			this.insertIndex = insertIndex;
			if (overlayType != null)
			{
				this.overlayType = overlayType;
			}
			this.level = level;
			this.raise = raise;
			this.smooth = smooth;
			this.clearPaint = clearPaint;
		}
	}
}