Decompiled source of AdvancedTerrainModifiers v1.2.6

TerrainTools.dll

Decompiled 4 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
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.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.2.6")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.6.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 = 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 = 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.2.6")]
	[BepInDependency("com.jotunn.jotunn", "2.16.2")]
	[NetworkCompatibility(/*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.2.6";

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

		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 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.", 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, "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.", null, synced: false);
			hardnessScrollScale = ConfigManager.BindConfig(HardnessSection, "HardnessScrollScale", 0.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 = !UpdatePlugin || UpdatePlugin;
		}
	}
	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_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_00a7: Expected O, but got Unknown
			//IL_00a9: 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);
			string name2 = (from name in Assembly.GetExecutingAssembly().GetManifestResourceNames()
				where name.Contains(fileName)
				select name).FirstOrDefault();
			Stream? manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name2);
			byte[] array = new byte[manifestResourceStream.Length];
			manifestResourceStream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(0, 0);
			ImageConversion.LoadImage(val, array);
			return val;
		}
	}
	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.op_Implicit((Object)(object)((Component)__instance).GetComponentInChildren<OverlayVisualizer>());
		}
	}
	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 lower_v2 => (Bitmap)ResourceManager.GetObject("lower_v2", 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 ShovelIcon => (Bitmap)ResourceManager.GetObject("ShovelIcon", 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 static 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 && (Object.op_Implicit((Object)(object)((Component)val).gameObject.GetComponentInChildren<RaiseGroundOverlayVisualizer>()) || RadiusModifier.ShouldModifyRadius() || HardnessModifier.ShouldModifyHardness()))
			{
				return true;
			}
			return localPlayer.CanRotatePiece();
		}
	}
	[HarmonyPatch]
	internal class PlayerPatch
	{
		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static void UpdatePlacementGhostPostfix(Player __instance)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0083: 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.op_Implicit((Object)(object)__instance.m_placementGhost) && Object.op_Implicit((Object)(object)__instance.m_placementGhost.GetComponent<OverlayVisualizer>()))
			{
				Vector3 position = __instance.m_placementGhost.transform.position;
				position.x = RoundToNearest(position.x, 1f);
				position.z = RoundToNearest(position.z, 1f);
				__instance.m_placementGhost.transform.position = position;
			}
		}

		private static float RoundToNearest(float x, float precision)
		{
			if (precision <= 0f)
			{
				return x;
			}
			float num = Mathf.Sign(x);
			int num2 = (int)Mathf.Abs(x * 1000f);
			int num3 = num2 / 1000;
			int num4 = num2 % 1000;
			int num5 = (int)(precision * 1000f / 2f);
			if (num4 < num5)
			{
				return num * (float)num3;
			}
			return num * ((float)num3 + precision);
		}
	}
}
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 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 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;

		[HarmonyPrefix]
		[HarmonyPriority(300)]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void UpdatePrefix(Player __instance)
		{
			//IL_009a: 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;
					SetPower(__instance, 0f);
				}
				if (RaiseToolIsInUse)
				{
					RaiseToolIsInUse = false;
					lastModdedRaisePwr = 0f;
					lastTotalRaiseDelta = 0f;
					lastDisplayedRaiseHardness = -1f;
					SetPower(__instance, 0f);
				}
			}
			else 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;
		}

		[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) && !Object.op_Implicit((Object)(object)((Component)__instance).gameObject.GetComponent<OverlayVisualizer>()))
			{
				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) || Object.op_Implicit((Object)(object)((Component)selectedPiece).gameObject.GetComponent<OverlayVisualizer>()))
			{
				return;
			}
			TerrainOp component = ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			SetSmoothPower(component, delta);
			SetRaisePower(component, 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($"Terrain tool smoothing hardness: {smoothPowerDisplayValue:0}%");
				}
			}
			if (RaiseToolIsInUse)
			{
				float raisePowerDisplayValue = GetRaisePowerDisplayValue(lastModdedRaisePwr);
				if (Mathf.Abs(raisePowerDisplayValue - lastDisplayedRaiseHardness) > 0.9f)
				{
					lastDisplayedRaiseHardness = Mathf.Round(raisePowerDisplayValue);
					list.Add($"Terrain tool raise hardness: {raisePowerDisplayValue:0}%");
				}
			}
			if (SmoothToolIsInUse || RaiseToolIsInUse)
			{
				Sprite icon = player.m_placementGhost.GetComponent<Piece>().m_icon;
				if ((Object)(object)icon != (Object)null && list.Count > 0)
				{
					((Character)player).Message((MessageType)2, string.Join("\n", list.ToArray()), 0, icon);
				}
			}
		}

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

		private static void SetRaisePower(TerrainOp terrainOp, float delta)
		{
			if (terrainOp.m_settings.m_raise)
			{
				delta = ConvertSmoothDeltaToRaiseDelta(delta);
				Log.LogInfo($"Adjusting Raise Power by {delta}", LogLevel.High);
				if (!RaiseToolIsInUse)
				{
					RaiseToolIsInUse = true;
					lastModdedRaisePwr = ModifyRaisePower(terrainOp.m_settings.m_raisePower, delta);
				}
				else
				{
					lastModdedRaisePwr = ModifyRaisePower(lastModdedRaisePwr, delta);
				}
				lastTotalRaiseDelta += delta;
				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;

		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 void InitToolPieces()
		{
			if (HasInitialized)
			{
				return;
			}
			FixVanillaToolDescriptions();
			foreach (string key in ToolConfigs.ToolConfigsMap.Keys)
			{
				try
				{
					ToolDB toolDB = ToolConfigs.ToolConfigsMap[key];
					toolDB.prefab = MakeToolPiece(toolDB);
				}
				catch
				{
					Log.LogWarning("Failed to create: " + key);
				}
			}
			HasInitialized = true;
			UpdateTools();
		}

		internal static void FixVanillaToolDescriptions()
		{
			SetDescription("mud_road_v2", "Levels ground based on player position. Use shift + click to level ground based on where you are pointing (this will smooth the terrain).");
			SetDescription("raise_v2", "Raise grounds up to a maximum of 8 m above it's original height.");
			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 (this will smooth the terrain).");
			SetDescription("cultivate_v2", "Cultivates ground and levels ground based on player position. Use shift + click to level ground based on where you are pointing (this will smooth the terrain).");
			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()
		{
			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];
					RegisterPieceInPieceTable(toolDB.prefab, toolDB.pieceTable, null, 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, null, toolDB.insertIndex);
				}
				catch
				{
					Log.LogWarning("Failed to create: " + key);
				}
			}
		}

		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();
				}
				if (rightItem.m_shared.m_name == "$item_hoe")
				{
					Log.LogWarning("AdvancedTerrainModifiers updated through config change, unequipping hoe");
					((Humanoid)Player.m_localPlayer).HideHandItems();
				}
			}
		}

		internal static GameObject MakeToolPiece(ToolDB toolDB)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: 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 ((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;
			}
			Settings settings = val.GetComponent<TerrainOp>().m_settings;
			settings.m_level = UpdateValueIfNeeded(settings.m_level, toolDB.level);
			settings.m_levelRadius = UpdateValueIfNeeded(settings.m_levelRadius, toolDB.levelRadius);
			settings.m_raise = UpdateValueIfNeeded(settings.m_raise, toolDB.raise);
			settings.m_raiseRadius = UpdateValueIfNeeded(settings.m_raiseRadius, toolDB.raiseRadius);
			settings.m_raisePower = UpdateValueIfNeeded(settings.m_raisePower, toolDB.raisePower);
			settings.m_raiseDelta = UpdateValueIfNeeded(settings.m_raiseDelta, toolDB.raiseDelta);
			settings.m_smooth = UpdateValueIfNeeded(settings.m_smooth, toolDB.smooth);
			settings.m_smoothRadius = UpdateValueIfNeeded(settings.m_smoothRadius, toolDB.smoothRadius);
			settings.m_smoothPower = UpdateValueIfNeeded(settings.m_smoothPower, toolDB.smoothPower);
			settings.m_paintCleared = UpdateValueIfNeeded(settings.m_paintCleared, toolDB.clearPaint);
			settings.m_paintRadius = UpdateValueIfNeeded(settings.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, 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 (!InsertionIndexes.ContainsKey(pieceTable))
			{
				InsertionIndexes[pieceTable] = new List<int>();
			}
			int num = position + InsertionIndexes[pieceTable].Where((int x) => x <= position).Count();
			if (num >= pieceTable2.m_pieces.Count)
			{
				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));
		}

		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 < pieceTable.m_pieces.Count; i++)
			{
				if (list[i] > num)
				{
					list[i]--;
				}
			}
		}
	}
	[HarmonyPatch(typeof(TerrainComp))]
	public static class PreciseTerrainModifier
	{
		public const int FixedRadius = 1;

		[HarmonyPrefix]
		[HarmonyPatch("ApplyOperation")]
		private static void ApplyOperationPrefix(TerrainOp modifier)
		{
			if (Object.op_Implicit((Object)(object)modifier) && Object.op_Implicit((Object)(object)((Component)modifier).gameObject) && Object.op_Implicit((Object)(object)((Component)modifier).gameObject.GetComponentInChildren<OverlayVisualizer>()))
			{
				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;
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("RPC_ApplyOperation")]
		private static void RPC_ApplyOperationPrefix(TerrainComp __instance)
		{
			if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)__instance.m_nview) && !__instance.m_nview.IsOwner())
			{
				__instance.m_nview.ClaimOwnership();
			}
		}

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

		[HarmonyPrefix]
		[HarmonyPatch("InternalDoOperation")]
		private static bool InternalDoOperationPrefix(TerrainComp __instance, Vector3 pos, Settings modifier)
		{
			//IL_0021: 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 (!modifier.m_level && !modifier.m_raise && !modifier.m_smooth && !modifier.m_paintCleared)
			{
				RemoveTerrainModifications(__instance, pos);
				PreciseRecolorTerrain(__instance, pos, (PaintType)3);
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("SmoothTerrain")]
		private static bool PreciseSmoothTerrian(TerrainComp __instance, Vector3 worldPos, float radius)
		{
			//IL_0029: 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_0058: 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_hmap.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}, oldSmoothDelta: {num7}, newSmoothDelta {__instance.m_smoothDelta[num5]}", LogLevel.Medium);
				}
			}
			Log.LogInfo("[SUCCESS] Smooth Terrain Modification", LogLevel.Medium);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("RaiseTerrain")]
		private static bool RaiseTerrainPrefix(TerrainComp __instance, Vector3 worldPos, float radius, float delta)
		{
			//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, 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++)
				{
					float height = __instance.m_hmap.GetHeight(i, j);
					float num5 = num4 + delta;
					if (delta < 0f && num5 > height)
					{
						continue;
					}
					if (delta >= 0f)
					{
						if (num5 < height)
						{
							continue;
						}
						if (num5 > height + delta)
						{
							num5 = height + delta;
						}
					}
					int num6 = j * num + i;
					__instance.m_levelDelta[num6] += num5 - height + __instance.m_smoothDelta[num6];
					__instance.m_smoothDelta[num6] = 0f;
					__instance.m_levelDelta[num6] = Mathf.Clamp(__instance.m_levelDelta[num6], -8f, 8f);
					__instance.m_modifiedHeight[num6] = true;
				}
			}
			Log.LogInfo("[SUCCESS] Raise Terrain Modification", LogLevel.Medium);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("PaintCleared")]
		private static bool PaintClearedPrefix(TerrainComp __instance, Vector3 worldPos, float radius, PaintType paintType)
		{
			//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)
			if (!IsPrecisionModifier(radius))
			{
				return true;
			}
			PreciseRecolorTerrain(__instance, worldPos, paintType);
			return false;
		}

		public static void RemoveTerrainModifications(TerrainComp comp, Vector3 worldPos)
		{
			//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)
			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, 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;
					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)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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)
			Log.LogInfo("[INIT] PreciseRecolorTerrain", LogLevel.Medium);
			int x = default(int);
			int x2 = default(int);
			comp.m_hmap.WorldToVertex(worldPos, ref x, ref x2);
			Color val = ResolveColor(paintType);
			bool flag = (int)paintType == 3;
			FindExtrema(x, comp.m_width + 1, out var xMin, out var xMax);
			FindExtrema(x2, comp.m_width + 1, out var xMin2, out var xMax2);
			for (int i = xMin; i < xMax; i++)
			{
				for (int j = xMin2; j < xMax2; j++)
				{
					int num = j * comp.m_width + i;
					comp.m_paintMask[num] = val;
					comp.m_modifiedPaint[num] = !flag;
					Log.LogInfo($"tilePos: ({i}, {j}), tileIndex: {num}, 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_0016: Expected I4, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			return (Color)((int)paintType switch
			{
				0 => Heightmap.m_paintMaskDirt, 
				1 => Heightmap.m_paintMaskCultivated, 
				2 => Heightmap.m_paintMaskPaved, 
				3 => Heightmap.m_paintMaskNothing, 
				_ => Heightmap.m_paintMaskNothing, 
			});
		}

		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);
		}
	}
	[HarmonyPatch]
	internal static class RadiusModifier
	{
		private static bool RadiusToolIsInUse = false;

		private static float lastOriginalRadius;

		private static float lastModdedRadius;

		private static float lastTotalDelta;

		private static Vector3 lastGhostScale = Vector3.zero;

		private const float MinRadius = 0.5f;

		private const float Tolerance = 0.01f;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void UpdatePrefix(Player __instance)
		{
			//IL_0050: 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_006e: 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;
			}
			TerrainOp terrainOp;
			if (!((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible())
			{
				if (RadiusToolIsInUse)
				{
					RadiusToolIsInUse = false;
					lastOriginalRadius = 0f;
					lastModdedRadius = 0f;
					lastTotalDelta = 0f;
					lastGhostScale = Vector3.zero;
				}
			}
			else if (IsValidSelectedPiece(__instance, out terrainOp))
			{
				if (ShouldModifyRadius())
				{
					SetRadius(terrainOp, Input.mouseScrollDelta.y * TerrainTools.RadiusScrollScale);
				}
				RefreshGhostScale(__instance);
			}
		}

		internal static bool IsValidSelectedPiece(Player player, out TerrainOp terrainOp)
		{
			Piece selectedPiece = player.GetSelectedPiece();
			if (!Object.op_Implicit((Object)(object)selectedPiece) || !Object.op_Implicit((Object)(object)((Component)selectedPiece).gameObject) || Object.op_Implicit((Object)(object)((Component)selectedPiece).gameObject.GetComponent<OverlayVisualizer>()))
			{
				terrainOp = null;
				return false;
			}
			terrainOp = ((Component)selectedPiece).gameObject.GetComponent<TerrainOp>();
			if (!Object.op_Implicit((Object)(object)terrainOp))
			{
				return false;
			}
			return true;
		}

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

		[HarmonyPrefix]
		[HarmonyPriority(700)]
		[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) && !Object.op_Implicit((Object)(object)((Component)__instance).gameObject.GetComponent<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);
				}
			}
		}

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

		private static void SetRadius(TerrainOp terrainOp, float delta)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			Log.LogInfo($"Adjusting radius by {delta}", LogLevel.High);
			if (!RadiusToolIsInUse && Object.op_Implicit((Object)(object)terrainOp))
			{
				if (TryGetMaximumRadius(terrainOp, out var maxRadius))
				{
					RadiusToolIsInUse = true;
					lastOriginalRadius = maxRadius;
					lastModdedRadius = ModifyRadius(maxRadius, delta);
					lastTotalDelta += delta;
				}
			}
			else
			{
				lastModdedRadius = ModifyRadius(lastModdedRadius, delta);
				lastTotalDelta += delta;
			}
			Log.LogInfo($"total delta {lastTotalDelta}", LogLevel.High);
			lastGhostScale = new Vector3(lastModdedRadius / lastOriginalRadius, lastModdedRadius / lastOriginalRadius, lastModdedRadius / lastOriginalRadius);
		}

		private static void RefreshGhostScale(Player player)
		{
			//IL_0043: 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_0060: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			if (!RadiusToolIsInUse || !Object.op_Implicit((Object)(object)player.m_placementGhost))
			{
				return;
			}
			Transform val = player.m_placementGhost.transform.Find("_GhostOnly");
			if (Object.op_Implicit((Object)(object)val))
			{
				ParticleSystem componentInChildren = ((Component)val).GetComponentInChildren<ParticleSystem>();
				if (Object.op_Implicit((Object)(object)componentInChildren) && !(lastGhostScale == Vector3.zero) && Vector3.Distance(((Component)componentInChildren).transform.localScale, lastGhostScale) > 0.01f)
				{
					Log.LogInfo($"Adjusting ghost scale to {lastGhostScale}x", LogLevel.High);
					((Component)componentInChildren).transform.localScale = lastGhostScale;
				}
			}
		}

		private static bool TryGetMaximumRadius(TerrainOp terrainOp, out float maxRadius)
		{
			maxRadius = 0f;
			if (terrainOp.m_settings.m_level && maxRadius < terrainOp.m_settings.m_levelRadius)
			{
				maxRadius = terrainOp.m_settings.m_levelRadius;
			}
			if (terrainOp.m_settings.m_raise && maxRadius < terrainOp.m_settings.m_raiseRadius)
			{
				maxRadius = terrainOp.m_settings.m_raiseRadius;
			}
			if (terrainOp.m_settings.m_smooth && maxRadius < terrainOp.m_settings.m_smoothRadius)
			{
				maxRadius = terrainOp.m_settings.m_smoothRadius;
			}
			if (terrainOp.m_settings.m_paintCleared && maxRadius < terrainOp.m_settings.m_paintRadius)
			{
				maxRadius = terrainOp.m_settings.m_paintRadius;
			}
			return maxRadius != 0f;
		}
	}
	internal static class Shovel
	{
		private static bool HasBeenCreated;

		internal const string ShovelPrefabName = "ATM_Shovel";

		internal const string ShovelPieceTable = "_ShovelPieceTable";

		internal static CustomItem shovel;

		internal static bool TryGetShovel(out CustomItem shovel)
		{
			shovel = ItemManager.Instance.GetItem("ATM_Shovel");
			return shovel != null;
		}

		internal static void CreateShovel()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			if (!HasBeenCreated)
			{
				GameObject obj = CreateShovelPrefab();
				CreatePieceTable();
				List<RequirementConfig> list = new List<RequirementConfig>
				{
					new RequirementConfig("Wood", 5, 1, false),
					new RequirementConfig("Iron", 2, 1, false)
				};
				ItemConfig val = new ItemConfig
				{
					Name = "Shovel",
					Description = "",
					CraftingStation = CraftingStations.Forge,
					PieceTable = "_ShovelPieceTable",
					RepairStation = CraftingStations.Forge,
					Requirements = list.ToArray()
				};
				shovel = new CustomItem(obj, true, val);
				shovel.Recipe.Recipe.m_enabled = TerrainTools.IsShovelEnabled;
				ItemManager.Instance.AddItem(shovel);
				HasBeenCreated = true;
			}
		}

		private static void CreatePieceTable()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			PieceTableConfig val = new PieceTableConfig
			{
				CanRemovePieces = false,
				UseCategories = true,
				UseCustomCategories = false
			};
			CustomPieceTable val2 = new CustomPieceTable("_ShovelPieceTable", val);
			PieceManager.Instance.AddPieceTable(val2);
		}

		private static GameObject CreateShovelPrefab()
		{
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("ATM_Shovel", "Hoe");
			object obj;
			if (val == null)
			{
				obj = null;
			}
			else
			{
				Transform transform = val.transform;
				if (transform == null)
				{
					obj = null;
				}
				else
				{
					Transform obj2 = transform.Find("collider");
					obj = ((obj2 != null) ? ((Component)obj2).gameObject : null);
				}
			}
			GameObject val2 = (GameObject)obj;
			object obj3;
			if (val == null)
			{
				obj3 = null;
			}
			else
			{
				Transform transform2 = val.transform;
				if (transform2 == null)
				{
					obj3 = null;
				}
				else
				{
					Transform obj4 = transform2.Find("collider (1)");
					obj3 = ((obj4 != null) ? ((Component)obj4).gameObject : null);
				}
			}
			GameObject val3 = (GameObject)obj3;
			object obj5;
			if (val == null)
			{
				obj5 = null;
			}
			else
			{
				Transform transform3 = val.transform;
				if (transform3 == null)
				{
					obj5 = null;
				}
				else
				{
					Transform obj6 = transform3.Find("attach");
					obj5 = ((obj6 != null) ? ((Component)obj6).gameObject : null);
				}
			}
			GameObject val4 = (GameObject)obj5;
			object obj7;
			if (val4 == null)
			{
				obj7 = null;
			}
			else
			{
				Transform transform4 = val4.transform;
				if (transform4 == null)
				{
					obj7 = null;
				}
				else
				{
					Transform obj8 = transform4.Find("visual");
					obj7 = ((obj8 != null) ? ((Component)obj8).gameObject : null);
				}
			}
			GameObject val5 = (GameObject)obj7;
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null)
			{
				Log.LogWarning("Failed to create shovel");
				return null;
			}
			Vector3 val6 = val4.transform.localPosition + val5.transform.localPosition;
			Quaternion val7 = val4.transform.localRotation * val5.transform.localRotation;
			try
			{
				object obj9;
				if (val5 == null)
				{
					obj9 = null;
				}
				else
				{
					Transform transform5 = val5.transform;
					if (transform5 == null)
					{
						obj9 = null;
					}
					else
					{
						Transform obj10 = transform5.Find("blade");
						obj9 = ((obj10 != null) ? ((Component)obj10).gameObject : null);
					}
				}
				GameObject val8 = (GameObject)obj9;
				val8.transform.localPosition = new Vector3(0f, -0.01f, 0.815f);
				val8.transform.localRotation = Quaternion.identity;
				val8.transform.localScale = new Vector3(0.225f, 0.08f, 0.6f);
				((Renderer)val8.GetComponent<MeshRenderer>()).sharedMaterial = Cache.GetPrefab<Material>("iron");
				val3.transform.localPosition = val6 + val8.transform.localPosition;
				val3.transform.localRotation = val7 * val8.transform.localRotation;
				val3.transform.localScale = val8.transform.localScale;
				BoxCollider component = val3.GetComponent<BoxCollider>();
				component.center = Vector3.zero;
				component.size = Vector3.one * 1.1f;
			}
			catch
			{
				Log.LogWarning("Failed to modify shovel blade");
			}
			try
			{
				object obj12;
				if (val5 == null)
				{
					obj12 = null;
				}
				else
				{
					Transform transform6 = val5.transform;
					if (transform6 == null)
					{
						obj12 = null;
					}
					else
					{
						Transform obj13 = transform6.Find("handle");
						obj12 = ((obj13 != null) ? ((Component)obj13).gameObject : null);
					}
				}
				GameObject val9 = (GameObject)obj12;
				Vector3 localScale = val9.transform.localScale;
				localScale.z = 1.6f;
				val9.transform.localScale = localScale;
				val2.transform.localPosition = val6 + val9.transform.localPosition;
				val2.transform.localRotation = val7 * val9.transform.localRotation;
				val2.transform.localScale = val9.transform.localScale;
				BoxCollider component2 = val2.GetComponent<BoxCollider>();
				component2.center = Vector3.zero;
				component2.size = new Vector3(1.5f, 1.5f, 1.025f);
			}
			catch
			{
				Log.LogWarning("Failed to modify shovel handle");
			}
			try
			{
				ItemDrop val10 = default(ItemDrop);
				if (val.TryGetComponent<ItemDrop>(ref val10))
				{
					SharedData val11 = val10?.m_itemData?.m_shared;
					if (val11 != null)
					{
						Texture2D val12 = IconCache.Shovel;
						Sprite val13 = Sprite.Create(val12, new Rect(0f, 0f, (float)((Texture)val12).width, (float)((Texture)val12).height), Vector2.zero);
						val11.m_icons = (Sprite[])(object)new Sprite[1] { val13 };
					}
				}
			}
			catch
			{
				Log.LogWarning("Failed to create shovel icon");
			}
			return val;
		}
	}
}
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 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;
		}
	}
}
namespace TerrainTools.Configs
{
	internal static 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