Decompiled source of InfinityHammerAddon v1.0.0

InfinityHammerAddon.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using InfinityHammer;
using InfinityTools;
using Microsoft.CodeAnalysis;
using ServerDevcommands;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using WorldEditCommands;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace InfinityHammerAddon
{
	[BepInPlugin("sighsorry.InfinityHammerAddon", "InfinityHammerAddon", "1.0.0")]
	[BepInDependency("infinity_hammer", "1.79.7")]
	[BepInDependency("server_devcommands", "1.108.5")]
	[BepInDependency("world_edit_commands", "1.73.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__9_0;

			internal void <RegisterCommand>b__9_0(ConsoleEventArgs args)
			{
				if (!Enabled.Value || Faulted || !Configuration.Enabled || !Configuration.ToolsEnabled)
				{
					throw new InvalidOperationException("Infinity Hammer addon tools are not enabled for this player.");
				}
				TerrainEdits.Execute(args);
			}
		}

		internal const string Guid = "sighsorry.InfinityHammerAddon";

		internal const string Version = "1.0.0";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> DefaultSoftness;

		internal static bool Faulted;

		private static ConsoleCommand? _command;

		private readonly Harmony _harmony = new Harmony("sighsorry.InfinityHammerAddon");

		private void Awake()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enhance the existing default Infinity Hammer tools. Adds no menu entries.");
			DefaultSoftness = ((BaseUnityPlugin)this).Config.Bind<float>("Level", "EdgeSoftness", 0.5f, new ConfigDescription("Initial circular Level edge softness. Alt + wheel adjusts it for the current selection.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_harmony.PatchAll();
		}

		private void Update()
		{
			if (Faulted)
			{
				return;
			}
			try
			{
				ToolEnhancements.UpdateInput();
			}
			catch (Exception ex)
			{
				Faulted = true;
				ToolEnhancements.Clear();
				((BaseUnityPlugin)this).Logger.LogError((object)("Addon input disabled after an unexpected error; native IH tools remain available. " + ex));
			}
		}

		internal static void RegisterCommand()
		{
			//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)
			//IL_004d: Expected O, but got Unknown
			if (_command != null)
			{
				return;
			}
			if (Terminal.commands.ContainsKey("iha_terrain"))
			{
				throw new InvalidOperationException("Another plugin already registered iha_terrain.");
			}
			object obj = <>c.<>9__9_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					if (!Enabled.Value || Faulted || !Configuration.Enabled || !Configuration.ToolsEnabled)
					{
						throw new InvalidOperationException("Infinity Hammer addon tools are not enabled for this player.");
					}
					TerrainEdits.Execute(args);
				};
				<>c.<>9__9_0 = val;
				obj = (object)val;
			}
			Helper.Command("iha_terrain", "Addon terrain edit: level softness=0..1 / paintonly / clearvegetation", (ConsoleEvent)obj);
			_command = Terminal.commands["iha_terrain"];
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
			ToolEnhancements.Clear();
			TerrainPreview.Dispose();
			if (_command != null && Terminal.commands.TryGetValue("iha_terrain", out var value) && value == _command)
			{
				Terminal.commands.Remove("iha_terrain");
			}
			_command = null;
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class RegisterAddonCommand
	{
		private static void Postfix()
		{
			Plugin.RegisterCommand();
		}
	}
	internal static class TerrainEdits
	{
		private const float MaxExtent = 128f;

		private const float MaxCoordinate = 20000f;

		private const float MaxDelta = 8f;

		internal static void Execute(ConsoleEventArgs args)
		{
			//IL_05b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: 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_0053: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e0: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZoneSystem.instance) || !Object.op_Implicit((Object)(object)ZNet.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				throw new InvalidOperationException("Terrain editing requires a loaded player world.");
			}
			ValidateArguments(args.Args, out var paintOnly, out var clearVegetation, out var softness);
			TerrainParameters val = new TerrainParameters(args);
			ValidateParameters(val, paintOnly, clearVegetation, softness);
			bool flag = paintOnly || clearVegetation;
			float num = ((val.Radius != null) ? val.Radius.Max : (Mathf.Max(val.Width.Max, val.Depth.Max) * (Mathf.Abs(Mathf.Sin(val.Angle)) + Mathf.Abs(Mathf.Cos(val.Angle)))));
			RequireLoadedArea(val.Position, num + 1f);
			TerrainComp[] array = ((val.Radius != null) ? Terrain.GetCompilers(val.Position, val.Radius) : Terrain.GetCompilers(val.Position, val.Width, val.Depth, val.Angle)).Distinct().ToArray();
			if (array.Length == 0)
			{
				throw new InvalidOperationException("No terrain is loaded in the selected area.");
			}
			TerrainComp[] array2 = array;
			foreach (TerrainComp obj in array2)
			{
				RequireCompiler(obj);
				obj.m_nview.ClaimOwnership();
			}
			array2 = array;
			foreach (TerrainComp obj2 in array2)
			{
				RequireOwnership(obj2);
				obj2.CheckLoad();
				obj2.m_hmap.Poke(false);
				RequireCompiler(obj2);
			}
			List<HeightNode> list = new List<HeightNode>();
			List<PaintNode> list2 = new List<PaintNode>();
			array2 = array;
			foreach (TerrainComp val2 in array2)
			{
				if (val.Radius != null)
				{
					if (flag)
					{
						Terrain.GetPaintNodesWithCircle(list2, val2, val.Position, val.Radius);
					}
					else
					{
						Terrain.GetHeightNodesWithCircle(list, val2, val.Position, val.Radius);
					}
				}
				else if (flag)
				{
					Terrain.GetPaintNodesWithRect(list2, val2, val.Position, val.Width, val.Depth, val.Angle);
				}
				else
				{
					Terrain.GetHeightNodesWithRect(list, val2, val.Position, val.Width, val.Depth, val.Angle);
				}
			}
			if (list.Count == 0 && list2.Count == 0)
			{
				throw new InvalidOperationException("The selected area contains no terrain nodes.");
			}
			foreach (HeightNode item in list)
			{
				TerrainComp compiler = ((TerrainNode)item).Compiler;
				if (!Finite(compiler.m_levelDelta[((TerrainNode)item).Index]) || !Finite(compiler.m_smoothDelta[((TerrainNode)item).Index]) || !Finite(compiler.m_hmap.m_heights[((TerrainNode)item).Index]))
				{
					throw new InvalidOperationException("The selected terrain contains non-finite height data.");
				}
			}
			if (clearVegetation)
			{
				foreach (PaintNode item2 in list2)
				{
					TerrainComp compiler2 = ((TerrainNode)item2).Compiler;
					int num2 = compiler2.m_width + 1;
					Color paintMask = compiler2.m_hmap.GetPaintMask(((TerrainNode)item2).Index % num2, ((TerrainNode)item2).Index / num2);
					if (!Finite(paintMask.r) || !Finite(paintMask.g) || !Finite(paintMask.b) || !Finite(paintMask.a))
					{
						throw new InvalidOperationException("The selected terrain contains non-finite paint data.");
					}
				}
			}
			array = list.Select((HeightNode n) => ((TerrainNode)n).Compiler).Concat(list2.Select((PaintNode n) => ((TerrainNode)n).Compiler)).Distinct()
				.ToArray();
			array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RequireOwnership(array2[i]);
			}
			Dictionary<Vector3, TerrainUndoData> data = Terrain.GetData(list, list2);
			Dictionary<Vector3, TerrainUndoData> dictionary = null;
			try
			{
				if (paintOnly)
				{
					Terrain.ClearPaint(list2, val.Position, num);
				}
				else if (clearVegetation)
				{
					ApplyClearVegetation(list2);
				}
				else if (softness.HasValue)
				{
					ApplySoftLevel(list, val.Level.Value, softness.Value);
				}
				else
				{
					Terrain.LevelTerrain(list, val.Position, num, val.Smooth, val.Level.Value);
					foreach (HeightNode item3 in list)
					{
						TerrainComp compiler3 = ((TerrainNode)item3).Compiler;
						compiler3.m_levelDelta[((TerrainNode)item3).Index] = Mathf.Clamp(compiler3.m_levelDelta[((TerrainNode)item3).Index], -8f, 8f);
						compiler3.m_modifiedHeight[((TerrainNode)item3).Index] = compiler3.m_levelDelta[((TerrainNode)item3).Index] != 0f;
					}
				}
				dictionary = Terrain.GetData(list, list2);
				array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					RequireOwnership(array2[i]);
				}
				array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					Terrain.Save(array2[i]);
				}
				ClutterSystem instance = ClutterSystem.instance;
				if (instance != null)
				{
					instance.ResetGrass(val.Position, num);
				}
			}
			catch (Exception ex)
			{
				try
				{
					array2 = array;
					for (int i = 0; i < array2.Length; i++)
					{
						RequireOwnership(array2[i]);
					}
					Terrain.ApplyData(data, val.Position, num);
				}
				catch (Exception ex2)
				{
					if (dictionary != null)
					{
						AddUndo(data, dictionary, val.Position, num);
					}
					throw new AggregateException("Terrain save and restoration failed; check the terrain and use undo after it is loaded again.", ex, ex2);
				}
				throw;
			}
			AddUndo(data, dictionary, val.Position, num);
		}

		private static void AddUndo(Dictionary<Vector3, TerrainUndoData> before, Dictionary<Vector3, TerrainUndoData> after, Vector3 position, float radius)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			UndoManager.Add((IUndoAction)new UndoAction((IEnumerable<UndoData>)Array.Empty<UndoData>(), (IEnumerable<UndoTerrain>)(object)new UndoTerrain[1]
			{
				new UndoTerrain(before, after, position, radius)
			}));
		}

		private static void ApplySoftLevel(List<HeightNode> nodes, float altitude, float softness)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			foreach (HeightNode node in nodes)
			{
				float levelFalloff = GetLevelFalloff(((TerrainNode)node).Distance, softness);
				if (!(levelFalloff <= 0f))
				{
					TerrainComp compiler = ((TerrainNode)node).Compiler;
					int index = ((TerrainNode)node).Index;
					float num = ((Component)compiler.m_hmap).transform.position.y + compiler.m_hmap.m_heights[index];
					compiler.m_levelDelta[index] = Mathf.Clamp(compiler.m_levelDelta[index] + compiler.m_smoothDelta[index] + (altitude - num) * levelFalloff, -8f, 8f);
					compiler.m_smoothDelta[index] = 0f;
					compiler.m_modifiedHeight[index] = compiler.m_levelDelta[index] != 0f;
				}
			}
		}

		private static float GetLevelFalloff(float normalizedDistance, float softness)
		{
			if (softness <= 0f)
			{
				return 1f;
			}
			float num = Mathf.Pow(1f - softness, 1.5f);
			if (normalizedDistance <= num)
			{
				return 1f;
			}
			return Mathf.Pow(Mathf.Clamp01((1f - normalizedDistance) / Mathf.Max(1f - num, 1E-06f)), 1f / Mathf.Lerp(1f, 4f, softness));
		}

		private static void ApplyClearVegetation(List<PaintNode> nodes)
		{
			//IL_003a: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			foreach (PaintNode node in nodes)
			{
				TerrainComp compiler = ((TerrainNode)node).Compiler;
				int num = compiler.m_width + 1;
				Color paintMask = compiler.m_hmap.GetPaintMask(((TerrainNode)node).Index % num, ((TerrainNode)node).Index / num);
				float num2 = Mathf.Pow(1f - Mathf.Clamp01(((TerrainNode)node).Distance), 0.1f);
				if (!(num2 <= 0f))
				{
					compiler.m_paintMask[((TerrainNode)node).Index] = Color.Lerp(paintMask, Color.clear, num2);
					compiler.m_modifiedPaint[((TerrainNode)node).Index] = true;
				}
			}
		}

		private static void RequireLoadedArea(Vector3 position, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Vector2i zone = ZoneSystem.GetZone(position - new Vector3(radius, 0f, radius));
			Vector2i zone2 = ZoneSystem.GetZone(position + new Vector3(radius, 0f, radius));
			Vector3 referencePosition = ZNet.instance.GetReferencePosition();
			Vector2i val = default(Vector2i);
			for (int i = zone.x; i <= zone2.x; i++)
			{
				for (int j = zone.y; j <= zone2.y; j++)
				{
					((Vector2i)(ref val))..ctor(i, j);
					Heightmap val2 = Heightmap.FindHeightmap(ZoneSystem.GetZonePos(val));
					if (!ZoneSystem.instance.IsZoneLoaded(val) || !ZNetScene.InActiveArea(val, referencePosition) || !Object.op_Implicit((Object)(object)val2) || val2.IsDistantLod || ZoneSystem.GetZone(((Component)val2).transform.position) != val)
					{
						throw new InvalidOperationException("The complete terrain area must be loaded and active. Move closer or reduce the range, then retry.");
					}
				}
			}
		}

		private static void RequireCompiler(TerrainComp compiler)
		{
			if (!Object.op_Implicit((Object)(object)compiler) || !compiler.m_initialized || !Object.op_Implicit((Object)(object)compiler.m_nview) || !compiler.m_nview.IsValid() || !Object.op_Implicit((Object)(object)compiler.m_hmap) || compiler.m_width <= 0 || compiler.m_width > 128)
			{
				throw new InvalidOperationException("A selected terrain compiler is not ready; retry once the area has loaded.");
			}
			int num = (compiler.m_width + 1) * (compiler.m_width + 1);
			if (compiler.m_levelDelta.Length != num || compiler.m_smoothDelta.Length != num || compiler.m_modifiedHeight.Length != num || compiler.m_modifiedPaint.Length != num || compiler.m_paintMask.Length != num || compiler.m_hmap.m_heights.Count != num)
			{
				throw new InvalidOperationException("A selected terrain compiler has an unsupported node layout.");
			}
		}

		private static void RequireOwnership(TerrainComp compiler)
		{
			RequireCompiler(compiler);
			if (!compiler.m_nview.IsOwner())
			{
				throw new InvalidOperationException("Terrain ownership is not ready. No edit was started; retry shortly.");
			}
		}

		private static void ValidateParameters(TerrainParameters pars, bool paintOnly, bool clearVegetation, float? softness)
		{
			if (!Finite(pars.Position.x) || !Finite(pars.Position.y) || !Finite(pars.Position.z) || Mathf.Abs(pars.Position.x) > 20000f || Mathf.Abs(pars.Position.z) > 20000f || Mathf.Abs(pars.Position.y) > 20000f || !Finite(pars.Angle) || !Finite(pars.Smooth) || pars.Smooth < 0f || pars.Smooth > 1f)
			{
				throw new InvalidOperationException("Position, angle and smoothing must be finite and within the supported limits.");
			}
			if (pars.Radius != null)
			{
				ValidateRange(pars.Radius);
			}
			else
			{
				ValidateRange(pars.Width);
				ValidateRange(pars.Depth);
			}
			if ((paintOnly ? 1 : 0) + (clearVegetation ? 1 : 0) + (pars.Level.HasValue ? 1 : 0) != 1)
			{
				throw new InvalidOperationException("Use exactly one operation: level, paintonly or clearvegetation.");
			}
			if (pars.Level.HasValue && (!Finite(pars.Level.Value) || Mathf.Abs(pars.Level.Value) > 20000f))
			{
				throw new InvalidOperationException("The target height must be finite and within the supported limits.");
			}
			if (softness.HasValue && (paintOnly || clearVegetation || pars.Radius == null))
			{
				throw new InvalidOperationException("Nonlinear softness is supported only for circular level edits.");
			}
			if (softness.HasValue && pars.Smooth != 0f)
			{
				throw new InvalidOperationException("Use softness or smooth, not both.");
			}
			if ((paintOnly || clearVegetation) && pars.Smooth != 0f)
			{
				throw new InvalidOperationException("Paint-only reset and Clear Vegetation do not support the smooth parameter.");
			}
		}

		private static void ValidateRange(Range<float> range)
		{
			if (!Finite(range.Min) || !Finite(range.Max) || range.Min < 0f || range.Min > range.Max || range.Max <= 0f || range.Max > 128f)
			{
				throw new InvalidOperationException("Terrain radius and rectangle half-extents must be greater than zero and no larger than 128 metres.");
			}
		}

		private static void ValidateArguments(string[] args, out bool paintOnly, out bool clearVegetation, out float? softness)
		{
			paintOnly = false;
			clearVegetation = false;
			softness = null;
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			for (int i = 1; i < args.Length; i++)
			{
				if (string.IsNullOrWhiteSpace(args[i]))
				{
					continue;
				}
				string[] array = args[i].Split(new char[1] { '=' });
				string text = array[0].ToLowerInvariant();
				string text2 = ((array.Length == 2) ? array[1] : null);
				if (array.Length > 2 || !hashSet.Add(text))
				{
					throw new InvalidOperationException("Invalid or duplicate terrain argument: " + args[i]);
				}
				if (((text == "id" || text == "ignore") && text2 != null) || (text == "blockcheck" && string.Equals(text2, "off", StringComparison.OrdinalIgnoreCase)) || (text == "chance" && text2 != null && ReadNumber(text2) == 1f))
				{
					continue;
				}
				switch (text)
				{
				case "paintonly":
					if (text2 != null)
					{
						throw new InvalidOperationException("Use paintonly without a value.");
					}
					paintOnly = true;
					break;
				case "clearvegetation":
					if (text2 != null)
					{
						throw new InvalidOperationException("Use clearvegetation without a value.");
					}
					clearVegetation = true;
					break;
				case "level":
					if (text2 != null)
					{
						ReadNumber(text2);
					}
					break;
				case "softness":
					softness = ReadNumber(text2);
					if (softness < 0f || softness > 1f)
					{
						throw new InvalidOperationException("Softness must be between 0 and 1.");
					}
					break;
				case "smooth":
					ReadNumber(text2);
					break;
				case "circle":
					if (text2 != null)
					{
						ValidateRangeText(text2);
					}
					break;
				case "rect":
					if (text2 != null)
					{
						string[] array2 = text2.Split(new char[1] { ',' });
						if (array2.Length > 2)
						{
							throw new InvalidOperationException("Use rect=width,depth.");
						}
						string[] array3 = array2;
						for (int j = 0; j < array3.Length; j++)
						{
							ValidateRangeText(array3[j]);
						}
					}
					break;
				case "offset":
				case "from":
				case "step":
				case "to":
				{
					if (text2 == null)
					{
						throw new InvalidOperationException("Missing value for " + text);
					}
					string[] array4 = text2.Split(new char[1] { ',' });
					if (array4.Length < 1 || array4.Length > 3)
					{
						throw new InvalidOperationException("Invalid coordinate value for " + text);
					}
					string[] array3 = array4;
					for (int j = 0; j < array3.Length; j++)
					{
						ReadNumber(array3[j]);
					}
					break;
				}
				case "angle":
					if (text2 == null || !new string[8] { "n", "ne", "e", "se", "s", "sw", "w", "nw" }.Contains(text2.ToLowerInvariant()))
					{
						ReadNumber(text2);
					}
					break;
				default:
					throw new InvalidOperationException("Unsupported addon terrain argument: " + text + ". Use the original terrain command for filters and other operations.");
				}
			}
		}

		private static void ValidateRangeText(string value)
		{
			Match match = Regex.Match(value, "\\A([+]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+]?\\d+)?)(?:[-;]([+]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+]?\\d+)?))?\\z");
			if (!match.Success)
			{
				throw new InvalidOperationException("Invalid non-negative terrain range: " + value);
			}
			ReadNumber(match.Groups[1].Value);
			if (match.Groups[2].Success)
			{
				ReadNumber(match.Groups[2].Value);
			}
		}

		private static float ReadNumber(string? value)
		{
			if (value == null || !float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !Finite(result))
			{
				throw new InvalidOperationException("Invalid finite number: " + value);
			}
			return result;
		}

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	internal static class TerrainPreview
	{
		private const int MaxMarkers = 2048;

		private const float SurfaceOffset = 0.06f;

		private const float MovingRefresh = 1f / 30f;

		private const float StationaryRefresh = 0.25f;

		private static readonly Color PreviewColor = new Color(1f, 0.15f, 0.8f, 0.9f);

		private static readonly List<Heightmap> Heightmaps = new List<Heightmap>();

		private static readonly HashSet<Vector2> SeenNodes = new HashSet<Vector2>();

		private static readonly List<Vector3> Vertices = new List<Vector3>(8192);

		private static readonly List<int> Indices = new List<int>(12288);

		private static readonly List<Color> Colors = new List<Color>(8192);

		private static GameObject? _root;

		private static LineRenderer? _outline;

		private static LineRenderer? _startMarker;

		private static MeshRenderer? _nodesRenderer;

		private static Mesh? _nodesMesh;

		private static Material? _material;

		private static ZNetScene? _world;

		private static Vector3 _lastStart;

		private static Vector3 _lastEnd;

		private static float _lastSize;

		private static float _lastRefresh;

		private static int _lastKind;

		private static int _sceneHandle;

		internal static void ShowCircle(Vector3 center, float radius, bool showNodes)
		{
			//IL_0000: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFinite(center) || !ValidSize(radius) || !EnsureResources())
			{
				Hide();
			}
			else
			{
				if (!ShouldRefresh((!showNodes) ? 1 : 2, center, center, radius))
				{
					return;
				}
				CollectHeightmaps(center, radius);
				int num = Mathf.Clamp(Mathf.CeilToInt(radius * (float)Math.PI * 2f), 64, 768);
				_outline.positionCount = num;
				_outline.loop = true;
				for (int i = 0; i < num; i++)
				{
					float num2 = (float)i * (float)Math.PI * 2f / (float)num;
					Vector3 val = center + new Vector3(Mathf.Cos(num2) * radius, 0f, Mathf.Sin(num2) * radius);
					if (TryGetSurfaceHeight(val, out var height))
					{
						val.y = height;
					}
					val.y += 0.06f;
					_outline.SetPosition(i, val);
				}
				((Renderer)_startMarker).enabled = false;
				((Renderer)_nodesRenderer).enabled = showNodes && DrawPaintNodes(center, radius);
				_root.SetActive(true);
			}
		}

		internal static void ShowSlope(Vector3 start, Vector3 end, float halfWidth)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0039: 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_004b: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFinite(start) || !IsFinite(end) || !ValidSize(halfWidth) || !EnsureResources())
			{
				Hide();
			}
			else
			{
				if (!ShouldRefresh(3, start, end, halfWidth))
				{
					return;
				}
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(end.x - start.x, 0f, end.z - start.z);
				if (!IsFinite(val) || ((Vector3)(ref val)).sqrMagnitude > 16777216f)
				{
					Hide();
					return;
				}
				Vector3 val2;
				if (!(((Vector3)(ref val)).sqrMagnitude > 0.0001f))
				{
					val2 = Vector3.right * halfWidth;
				}
				else
				{
					Vector3 val3 = new Vector3(val.z, 0f, 0f - val.x);
					val2 = ((Vector3)(ref val3)).normalized * halfWidth;
				}
				Vector3 val4 = val2;
				Vector3 val5 = Vector3.up * 0.06f;
				_outline.positionCount = 4;
				_outline.loop = true;
				_outline.SetPosition(0, start - val4 + val5);
				_outline.SetPosition(1, end - val4 + val5);
				_outline.SetPosition(2, end + val4 + val5);
				_outline.SetPosition(3, start + val4 + val5);
				_startMarker.positionCount = 16;
				_startMarker.loop = true;
				for (int i = 0; i < 16; i++)
				{
					float num = (float)i * (float)Math.PI / 8f;
					_startMarker.SetPosition(i, start + val5 + new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * 0.25f);
				}
				((Renderer)_startMarker).enabled = true;
				((Renderer)_nodesRenderer).enabled = false;
				_root.SetActive(true);
			}
		}

		internal static void Hide()
		{
			if (_world != null && (!Object.op_Implicit((Object)(object)ZNetScene.instance) || _world != ZNetScene.instance))
			{
				Dispose();
				return;
			}
			if (Object.op_Implicit((Object)(object)_root))
			{
				_root.SetActive(false);
			}
			_lastKind = 0;
		}

		internal static void Dispose()
		{
			SceneManager.sceneUnloaded -= OnSceneUnloaded;
			if (Object.op_Implicit((Object)(object)_root))
			{
				Object.Destroy((Object)(object)_root);
			}
			if (Object.op_Implicit((Object)(object)_nodesMesh))
			{
				Object.Destroy((Object)(object)_nodesMesh);
			}
			if (Object.op_Implicit((Object)(object)_material))
			{
				Object.Destroy((Object)(object)_material);
			}
			_root = null;
			_outline = null;
			_startMarker = null;
			_nodesRenderer = null;
			_nodesMesh = null;
			_material = null;
			_world = null;
			_lastKind = 0;
			Heightmaps.Clear();
			SeenNodes.Clear();
			Vertices.Clear();
			Indices.Clear();
			Colors.Clear();
		}

		private static bool EnsureResources()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			ZNetScene instance = ZNetScene.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				Dispose();
				return false;
			}
			if (_world != instance || !Object.op_Implicit((Object)(object)_root))
			{
				Dispose();
			}
			if (Object.op_Implicit((Object)(object)_root))
			{
				return true;
			}
			Shader val = Shader.Find("Sprites/Default");
			if (!Object.op_Implicit((Object)(object)val))
			{
				return false;
			}
			_world = instance;
			_material = new Material(val)
			{
				name = "InfinityHammerAddon.Preview",
				hideFlags = (HideFlags)52,
				color = Color.white
			};
			_root = new GameObject("InfinityHammerAddon.Preview")
			{
				hideFlags = (HideFlags)52
			};
			_root.SetActive(false);
			Scene scene = _root.scene;
			_sceneHandle = ((Scene)(ref scene)).handle;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			_outline = CreateLine("Range", PreviewColor);
			_startMarker = CreateLine("SlopeStart", Color.white);
			GameObject val2 = new GameObject("PaintNodes")
			{
				hideFlags = (HideFlags)52
			};
			val2.transform.SetParent(_root.transform, false);
			_nodesRenderer = val2.AddComponent<MeshRenderer>();
			((Renderer)_nodesRenderer).sharedMaterial = _material;
			((Renderer)_nodesRenderer).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_nodesRenderer).receiveShadows = false;
			((Renderer)_nodesRenderer).enabled = false;
			_nodesMesh = new Mesh
			{
				name = "InfinityHammerAddon.PaintNodes",
				hideFlags = (HideFlags)52
			};
			_nodesMesh.MarkDynamic();
			val2.AddComponent<MeshFilter>().sharedMesh = _nodesMesh;
			return true;
		}

		private static LineRenderer CreateLine(string name, Color color)
		{
			//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_000e: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name)
			{
				hideFlags = (HideFlags)52
			};
			val.transform.SetParent(_root.transform, false);
			LineRenderer obj = val.AddComponent<LineRenderer>();
			((Renderer)obj).sharedMaterial = _material;
			obj.useWorldSpace = true;
			obj.widthMultiplier = 0.05f;
			obj.numCornerVertices = 2;
			obj.startColor = color;
			obj.endColor = color;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			return obj;
		}

		private static void OnSceneUnloaded(Scene scene)
		{
			if (((Scene)(ref scene)).handle == _sceneHandle || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				Dispose();
			}
		}

		private static bool ShouldRefresh(int kind, Vector3 start, Vector3 end, float size)
		{
			//IL_0011: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.unscaledTime - _lastRefresh;
			bool flag = ((Vector3)(ref _lastStart)).Equals(start) && ((Vector3)(ref _lastEnd)).Equals(end) && _lastSize == size;
			if (_lastKind == kind && _root.activeSelf && num >= 0f && num < (flag ? 0.25f : (1f / 30f)))
			{
				return false;
			}
			_lastKind = kind;
			_lastStart = start;
			_lastEnd = end;
			_lastSize = size;
			_lastRefresh = Time.unscaledTime;
			return true;
		}

		private static void CollectHeightmaps(Vector3 center, float radius)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Heightmaps.Clear();
			Heightmap.FindHeightmap(center, radius + 1f, Heightmaps);
			Heightmaps.RemoveAll((Heightmap hmap) => !IsReady(hmap));
		}

		private static bool IsReady(Heightmap hmap)
		{
			if (Object.op_Implicit((Object)(object)hmap) && ((Behaviour)hmap).isActiveAndEnabled && !hmap.IsDistantLod && hmap.m_width > 0 && hmap.m_width <= 1024 && ValidSize(hmap.m_scale) && hmap.m_heights != null)
			{
				return hmap.m_heights.Count == (hmap.m_width + 1) * (hmap.m_width + 1);
			}
			return false;
		}

		private static bool DrawPaintNodes(Vector3 center, float radius)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			Vertices.Clear();
			Indices.Clear();
			Colors.Clear();
			SeenNodes.Clear();
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return false;
			}
			Vector3 referencePosition = ZNet.instance.GetReferencePosition();
			Vector3 val = default(Vector3);
			foreach (Heightmap heightmap in Heightmaps)
			{
				if (!ZNetScene.InActiveArea(ZoneSystem.GetZone(((Component)heightmap).transform.position), referencePosition))
				{
					continue;
				}
				Vector3 position = ((Component)heightmap).transform.position;
				float num = position.x - (float)(heightmap.m_width / 2) * heightmap.m_scale;
				float num2 = position.z - (float)(heightmap.m_width / 2) * heightmap.m_scale;
				int num3 = Mathf.Clamp(Mathf.FloorToInt((center.x - radius - num) / heightmap.m_scale), 0, heightmap.m_width);
				int num4 = Mathf.Clamp(Mathf.CeilToInt((center.x + radius - num) / heightmap.m_scale), 0, heightmap.m_width);
				int num5 = Mathf.Clamp(Mathf.FloorToInt((center.z - radius - num2) / heightmap.m_scale), 0, heightmap.m_width);
				int num6 = Mathf.Clamp(Mathf.CeilToInt((center.z + radius - num2) / heightmap.m_scale), 0, heightmap.m_width);
				for (int i = num3; i <= num4; i++)
				{
					for (int j = num5; j <= num6; j++)
					{
						((Vector3)(ref val))..ctor(position.x + (float)(i - heightmap.m_width / 2) * heightmap.m_scale, position.y + heightmap.GetHeight(i, j), position.z + (float)(j - heightmap.m_width / 2) * heightmap.m_scale);
						if (!(Utils.DistanceXZ(center, val) > radius) && IsFinite(val) && SeenNodes.Add(new Vector2(val.x, val.z)))
						{
							if (SeenNodes.Count > 2048)
							{
								return false;
							}
							val.y += 0.06f;
							AddMarker(val);
						}
					}
				}
			}
			if (Vertices.Count == 0)
			{
				return false;
			}
			_nodesMesh.Clear();
			_nodesMesh.SetVertices(Vertices);
			_nodesMesh.SetColors(Colors);
			_nodesMesh.SetTriangles(Indices, 0);
			_nodesMesh.RecalculateBounds();
			return true;
		}

		private static void AddMarker(Vector3 center)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			int count = Vertices.Count;
			Vertices.Add(center + new Vector3(-0.08f, 0f, -0.08f));
			Vertices.Add(center + new Vector3(-0.08f, 0f, 0.08f));
			Vertices.Add(center + new Vector3(0.08f, 0f, 0.08f));
			Vertices.Add(center + new Vector3(0.08f, 0f, -0.08f));
			for (int i = 0; i < 4; i++)
			{
				Colors.Add(PreviewColor);
			}
			Indices.Add(count);
			Indices.Add(count + 1);
			Indices.Add(count + 2);
			Indices.Add(count);
			Indices.Add(count + 2);
			Indices.Add(count + 3);
		}

		private static bool TryGetSurfaceHeight(Vector3 point, out float height)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//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_0043: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			foreach (Heightmap heightmap in Heightmaps)
			{
				Vector3 position = ((Component)heightmap).transform.position;
				float num = (point.x - position.x) / heightmap.m_scale + (float)(heightmap.m_width / 2);
				float num2 = (point.z - position.z) / heightmap.m_scale + (float)(heightmap.m_width / 2);
				if (!(num < 0f) && !(num2 < 0f) && !(num > (float)heightmap.m_width) && !(num2 > (float)heightmap.m_width))
				{
					int num3 = Mathf.Min(Mathf.FloorToInt(num), heightmap.m_width - 1);
					int num4 = Mathf.Min(Mathf.FloorToInt(num2), heightmap.m_width - 1);
					float num5 = num - (float)num3;
					float num6 = num2 - (float)num4;
					float height2 = heightmap.GetHeight(num3, num4);
					float height3 = heightmap.GetHeight(num3 + 1, num4);
					float height4 = heightmap.GetHeight(num3, num4 + 1);
					float height5 = heightmap.GetHeight(num3 + 1, num4 + 1);
					height = position.y + ((num5 + num6 <= 1f) ? (height2 + (height3 - height2) * num5 + (height4 - height2) * num6) : (height5 + (height4 - height5) * (1f - num5) + (height3 - height5) * (1f - num6)));
					return IsFinite(height);
				}
			}
			height = 0f;
			return false;
		}

		private static bool ValidSize(float size)
		{
			if (IsFinite(size) && size > 0f)
			{
				return size <= 4096f;
			}
			return false;
		}

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

		private static bool IsFinite(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (IsFinite(value.x) && IsFinite(value.y))
			{
				return IsFinite(value.z);
			}
			return false;
		}
	}
	internal static class ToolEnhancements
	{
		private enum Kind
		{
			Level,
			Paint,
			Reset,
			Slope
		}

		private sealed class ToolInfo
		{
			internal readonly Kind Kind;

			internal readonly int Paint;

			internal ToolInfo(Kind kind, int paint = 0)
			{
				Kind = kind;
				Paint = paint;
			}
		}

		private static readonly string[] PaintNames = new string[10] { "Grass", "Dirt", "Cultivate", "Pave", "DarkGrass", "PatchyGrass", "MossyPaving", "DirtPaving", "DarkPaving", "ClearVegetation" };

		private static readonly string[] PaintValues = new string[10] { "grass", "dirt", "cultivated", "paved", "grass_dark", "patches", "paved_moss", "paved_dirt", "paved_dark", "" };

		private static readonly ConditionalWeakTable<Tool, ToolInfo> Recognized = new ConditionalWeakTable<Tool, ToolInfo>();

		private static ToolSelection? _selection;

		private static ToolInfo? _info;

		private static ZNetScene? _world;

		private static Vector3? _slopeStart;

		private static bool _paintOnly;

		private static int _paint;

		private static float _softness;

		private static int _wheelFrame = -1;

		private static int _altFrame = -1;

		internal static void Recognize(Tool tool, ToolData data)
		{
			if (data.commands != null)
			{
				return;
			}
			string text = Regex.Replace(data.command.Trim(), "\\s+", " ");
			ToolInfo toolInfo = null;
			if (data.name == "Level" && text == "terrain level smooth=<mod1>?.5:0 <area>")
			{
				toolInfo = new ToolInfo(Kind.Level);
			}
			if (data.name == "Reset" && text == "terrain reset <area>")
			{
				toolInfo = new ToolInfo(Kind.Reset);
			}
			if (data.name == "Slope" && text == "terrain slope <to>" && data.targetEdge == "true")
			{
				toolInfo = new ToolInfo(Kind.Slope);
			}
			for (int i = 0; i < PaintValues.Length - 1; i++)
			{
				if (data.name == PaintNames[i] && text == "terrain paint=" + PaintValues[i] + " <area>")
				{
					toolInfo = new ToolInfo(Kind.Paint, i);
				}
			}
			if (toolInfo != null)
			{
				Recognized.Add(tool, toolInfo);
			}
		}

		private static bool RefreshSelection()
		{
			Player localPlayer = Player.m_localPlayer;
			if (Plugin.Enabled.Value && !Plugin.Faulted && Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)ZNetScene.instance) && ((Character)localPlayer).InPlaceMode() && Configuration.Enabled && Configuration.ToolsEnabled)
			{
				BaseSelection obj = Selection.Get();
				ToolSelection val = (ToolSelection)(object)((obj is ToolSelection) ? obj : null);
				if (val != null && Recognized.TryGetValue(val.Tool, out ToolInfo value))
				{
					if (_selection != val || _world != ZNetScene.instance)
					{
						Clear();
						_selection = val;
						_info = value;
						_world = ZNetScene.instance;
						_paint = value.Paint;
						_softness = Plugin.DefaultSoftness.Value;
					}
					return true;
				}
			}
			Clear();
			return false;
		}

		internal static void Clear()
		{
			if (_selection != null && Object.op_Implicit((Object)(object)Ruler.Projector))
			{
				Ruler.Projector.SetActive(true);
			}
			_selection = null;
			_info = null;
			_world = null;
			_slopeStart = null;
			_paintOnly = false;
			_wheelFrame = -1;
			_altFrame = -1;
			TerrainPreview.Hide();
		}

		private static bool CanInput()
		{
			if (!Console.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible())
			{
				if (Object.op_Implicit((Object)(object)Hud.instance))
				{
					return !Hud.instance.m_pieceSelectionWindow.activeSelf;
				}
				return true;
			}
			return false;
		}

		private static bool BareAlt()
		{
			if ((Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)) && !Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)305) && !Input.GetKey((KeyCode)304))
			{
				return !Input.GetKey((KeyCode)303);
			}
			return false;
		}

		internal static void UpdateInput()
		{
			if (!RefreshSelection() || !CanInput())
			{
				return;
			}
			if (_altFrame != Time.frameCount && BareAlt() && (Input.GetKeyDown((KeyCode)308) || Input.GetKeyDown((KeyCode)307)))
			{
				_altFrame = Time.frameCount;
				if (_info.Kind == Kind.Slope)
				{
					_slopeStart = null;
				}
				if (_info.Kind == Kind.Reset)
				{
					_paintOnly = !_paintOnly;
					Message(_paintOnly ? "Reset: paint only" : "Reset: terrain + paint");
				}
			}
			ConsumeWheel();
		}

		internal static bool ConsumeWheel()
		{
			//IL_0015: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!RefreshSelection() || !CanInput() || !BareAlt() || Input.mouseScrollDelta.y == 0f || (_info.Kind != Kind.Paint && (_info.Kind != Kind.Level || (int)Ruler.Shape != 0)))
			{
				return false;
			}
			if (_wheelFrame == Time.frameCount)
			{
				return true;
			}
			if (HasNativeWheelConflict())
			{
				return false;
			}
			_wheelFrame = Time.frameCount;
			int num = ((Input.mouseScrollDelta.y > 0f) ? 1 : (-1));
			if (_info.Kind == Kind.Level)
			{
				_softness = Mathf.Clamp01(_softness + (float)num * 0.05f);
				Message("Level edge softness: " + _softness.ToString("0.00", CultureInfo.InvariantCulture));
			}
			else
			{
				_paint = (_paint + num + PaintValues.Length) % PaintValues.Length;
				Message("Paint: " + PaintNames[_paint]);
			}
			return true;
		}

		private static bool HasNativeWheelConflict()
		{
			foreach (CommandBind bestWheelCommand in BindManager.GetBestWheelCommands())
			{
				string text = Aliasing.Plain(bestWheelCommand.Command).Trim();
				if (text.IndexOf(';') >= 0 || MultiCommands.Split(text).Length != 1)
				{
					return true;
				}
				int i;
				for (i = 0; i < text.Length && !char.IsWhiteSpace(text[i]); i++)
				{
				}
				string text2 = text.Substring(0, i);
				if (!text2.Equals("_bind_command_radius_mouse_wheel", StringComparison.OrdinalIgnoreCase) && !text2.Equals("hammer_zoom_x", StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool BeforePlace(ToolSelection selection, GameObject obj)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			UpdateInput();
			if (!RefreshSelection() || selection != _selection || _info.Kind != Kind.Slope)
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)obj.GetComponent<ZNetView>()))
			{
				return true;
			}
			Vector3 position = HammerHelper.GetPlacementGhost().transform.position;
			if (!_slopeStart.HasValue)
			{
				_slopeStart = position;
				Message("Slope start set. Click the end point; Alt cancels.");
				Object.Destroy((Object)(object)obj);
				return false;
			}
			Vector3 value = _slopeStart.Value;
			float num = Utils.DistanceXZ(value, position);
			float x = Scaling.Get().X;
			if (!Finite(value) || !Finite(position) || float.IsNaN(x) || float.IsInfinity(x) || x <= 0f || x > 128f || num < 0.25f || num > 256f)
			{
				Message("Slope requires distinct points within 256 m and a half-width of at most 128 m.");
				Object.Destroy((Object)(object)obj);
				return false;
			}
			obj.AddComponent<PlacedCommand>().Command = "terrain slope from=" + Coordinates(value) + " to=" + Coordinates(position) + " rect=" + Number(x) + "," + Number(num / 2f);
			_slopeStart = null;
			return false;
		}

		internal static void AfterPlace(ToolSelection selection, GameObject obj)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (_selection != selection || _info == null || !Object.op_Implicit((Object)(object)obj))
			{
				return;
			}
			PlacedCommand component = obj.GetComponent<PlacedCommand>();
			if (!Object.op_Implicit((Object)(object)component) || component.Command.Contains(";"))
			{
				return;
			}
			string command = component.Command;
			if (_info.Kind == Kind.Level && (int)Ruler.Shape == 0 && command.StartsWith("terrain level ", StringComparison.Ordinal))
			{
				string text = Regex.Replace(command.Substring("terrain level ".Length), "(?:^|\\s)smooth=\\S+", "");
				component.Command = "iha_terrain level softness=" + Number(_softness) + " " + text;
			}
			else if (_info.Kind == Kind.Reset && _paintOnly && command.StartsWith("terrain reset ", StringComparison.Ordinal))
			{
				component.Command = "iha_terrain paintonly " + command.Substring("terrain reset ".Length);
			}
			else if (_info.Kind == Kind.Paint && command.StartsWith("terrain paint=", StringComparison.Ordinal))
			{
				int num = command.IndexOf(' ', "terrain paint=".Length);
				if (num >= 0)
				{
					string text2 = command.Substring(num + 1);
					component.Command = ((_paint == PaintValues.Length - 1) ? ("iha_terrain clearvegetation " + text2) : ("terrain paint=" + PaintValues[_paint] + " " + text2));
				}
			}
		}

		internal static bool BeforeRuler()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			UpdateInput();
			if (!RefreshSelection() || _info.Kind != Kind.Slope)
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)Ruler.Projector))
			{
				Ruler.Projector.SetActive(false);
			}
			if (!CanInput() || !Object.op_Implicit((Object)(object)Player.m_localPlayer.m_placementGhost))
			{
				TerrainPreview.Hide();
				return false;
			}
			Vector3 position = Player.m_localPlayer.m_placementGhost.transform.position;
			TerrainPreview.ShowSlope(_slopeStart ?? position, position, Scaling.Get().X);
			return false;
		}

		internal static void AfterRuler()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (_info == null || _info.Kind == Kind.Slope)
			{
				return;
			}
			if (!CanInput() || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)Player.m_localPlayer.m_placementGhost) || (int)Ruler.Shape != 0 || (_info.Kind != Kind.Paint && _info.Kind != Kind.Reset))
			{
				TerrainPreview.Hide();
				return;
			}
			if (Object.op_Implicit((Object)(object)Ruler.Projector))
			{
				Ruler.Projector.SetActive(false);
			}
			TerrainPreview.ShowCircle(Player.m_localPlayer.m_placementGhost.transform.position, Scaling.Get().X, _info.Kind == Kind.Paint || _paintOnly);
		}

		internal static void Describe(Hud hud, Piece piece)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)piece) || !RefreshSelection() || !CanInput() || (Object)(object)piece != (Object)(object)((BaseSelection)_selection).GetSelectedPiece())
			{
				return;
			}
			string text;
			switch (_info.Kind)
			{
			case Kind.Level:
				if ((int)Ruler.Shape != 0)
				{
					return;
				}
				text = "Level terrain — edge softness: " + _softness.ToString("0.00", CultureInfo.InvariantCulture) + "\nAlt + wheel: softness · Wheel: range\nCtrl: free mode · AltPlace: player height";
				break;
			case Kind.Paint:
				text = "Paint: " + PaintNames[_paint] + "\nAlt + wheel: paint type · Wheel: range\nHold Alt: single use · Ctrl: free mode";
				break;
			case Kind.Reset:
				text = "Reset: " + (_paintOnly ? "PAINT ONLY (height unchanged)" : "TERRAIN + PAINT") + "\nTap Alt: switch reset mode · Wheel: range\nHold Alt: single use · Ctrl: free mode";
				break;
			default:
				text = "Slope: click the " + (_slopeStart.HasValue ? "END" : "START") + " point\nWheel: width · Alt: cancel";
				break;
			}
			string text2 = ((_info.Kind == Kind.Slope) ? ("Width: " + Number(Scaling.Get().X * 2f) + " m") : Ruler.DescriptionScale(_selection));
			string text3 = ((_info.Kind == Kind.Slope) ? "" : ("\n" + Ruler.DescriptionPosition()));
			hud.m_pieceDescription.text = text + "\n" + text2 + text3;
		}

		private static void Message(string message)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null);
			}
		}

		private static string Number(float value)
		{
			return value.ToString("R", CultureInfo.InvariantCulture);
		}

		private static string Coordinates(Vector3 value)
		{
			//IL_0008: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			return Number(value.x) + "," + Number(value.z) + "," + Number(value.y);
		}

		private static bool Finite(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!float.IsNaN(value.x) && !float.IsNaN(value.y) && !float.IsNaN(value.z) && !float.IsInfinity(value.x) && !float.IsInfinity(value.y))
			{
				return !float.IsInfinity(value.z);
			}
			return false;
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class RecognizeDefaultTool
	{
		private static void Postfix(Tool __instance, ToolData data)
		{
			ToolEnhancements.Recognize(__instance, data);
		}
	}
	[HarmonyPatch(typeof(ToolSelection), "AfterPlace")]
	internal static class EnhanceToolPlacement
	{
		private static bool Prefix(ToolSelection __instance, GameObject obj, out bool __state)
		{
			__state = ToolEnhancements.BeforePlace(__instance, obj);
			return __state;
		}

		private static void Postfix(ToolSelection __instance, GameObject obj, bool __state)
		{
			if (__state)
			{
				ToolEnhancements.AfterPlace(__instance, obj);
			}
		}
	}
	[HarmonyPatch(typeof(Ruler), "Update")]
	internal static class EnhanceToolRuler
	{
		private static bool Prefix()
		{
			return ToolEnhancements.BeforeRuler();
		}

		private static void Postfix()
		{
			ToolEnhancements.AfterRuler();
		}
	}
	[HarmonyPatch(typeof(ScalingData), "ZoomX")]
	internal static class ReserveAltWheel
	{
		private static bool Prefix(ScalingData __instance)
		{
			if (__instance == Scaling.Get(true))
			{
				return !ToolEnhancements.ConsumeWheel();
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Hud), "SetupPieceInfo")]
	internal static class DescribeEnhancedTool
	{
		[HarmonyAfter(new string[] { "infinity_hammer" })]
		[HarmonyPriority(0)]
		private static void Postfix(Hud __instance, Piece piece)
		{
			ToolEnhancements.Describe(__instance, piece);
		}
	}
}