Decompiled source of Dismantleheim v0.1.0

Dismantleheim.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dismantleheim.Core;
using Dismantleheim.Input;
using Dismantleheim.Install;
using Dismantleheim.Integration;
using Dismantleheim.Removal;
using Dismantleheim.Selection;
using Dismantleheim.UI;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Dismantleheim")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+8ecd339e038533b99f6b98fdebb101cdbc119c52")]
[assembly: AssemblyProduct("Dismantleheim")]
[assembly: AssemblyTitle("Dismantleheim")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Dismantleheim
{
	[BepInPlugin("com.sonicdm.valheim.dismantleheim", "Dismantleheim", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class DismantleheimPlugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__56_0;

			internal void <RegisterCommands>b__56_0(ConsoleEventArgs args)
			{
				DismantleSession session = Session;
				if (session == null)
				{
					PrintCmd("Dismantleheim session unavailable.");
					return;
				}
				if (!PatchesReady && !GUIManager.IsHeadless())
				{
					PrintCmd("Dismantleheim patches failed; activation closed.");
					return;
				}
				if (!IsModEnabled())
				{
					PrintCmd("Dismantleheim disabled in config.");
					return;
				}
				switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "status")
				{
				case "mode":
				{
					string text = ((args.Length > 2) ? args[2] : string.Empty);
					if (!OperationModeUtil.TryParse(text, out var mode))
					{
						PrintCmd("Usage: dismantleheim mode dismantle|delete");
						break;
					}
					session.SetMode(mode, "command");
					PrintCmd("Dismantleheim mode=" + OperationModeUtil.ShortName(session.ActiveMode) + " active=" + session.IsActive);
					break;
				}
				case "activate":
				{
					if (session.TryActivate(GetDefaultMode(), "command", out var reject))
					{
						PrintCmd("Dismantleheim activated mode=" + OperationModeUtil.ShortName(session.ActiveMode));
					}
					else
					{
						PrintCmd("Dismantleheim activate rejected: " + (reject ?? "unknown") + " (equip Hammer / enter place mode).");
					}
					break;
				}
				case "deactivate":
				case "off":
					session.Deactivate("command");
					PrintCmd("Dismantleheim deactivated.");
					break;
				case "clear":
					session.Queue.Clear();
					session.SyncStateAfterSelectionChange();
					PrintCmd("Dismantleheim selection cleared.");
					break;
				case "why":
					PrintCmd(session.LastRejectReason ?? "(no recent reject)");
					break;
				default:
					PrintCmd("state=" + session.StateMachine.State.ToString() + " mode=" + OperationModeUtil.ShortName(session.ActiveMode) + " queue=" + session.Queue.Count + " filter=" + (session.Sampler.ActiveFilter ?? "(none)") + " dryRun=" + (DryRunOnly != null && DryRunOnly.Value) + " patches=" + PatchesReady);
					break;
				}
			}
		}

		public const string PluginGuid = "com.sonicdm.valheim.dismantleheim";

		public const string PluginName = "Dismantleheim";

		public const string PluginVersion = "0.1.0";

		internal const string ActivateButtonName = "Dismantleheim_Activate";

		internal static ManualLogSource ModLogger;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<KeyCode> ActivateKey;

		internal static ConfigEntry<float> ConfirmHoldSeconds;

		internal static ConfigEntry<bool> ShowRing;

		internal static ConfigEntry<bool> ShowSelectedCount;

		internal static ConfigEntry<bool> AllowEnvironmentWithFilter;

		internal static ConfigEntry<bool> ClearQueueOnToolSwitch;

		internal static ConfigEntry<string> ExtraDenyPrefabs;

		internal static ConfigEntry<string> ExtraAllowPrefabs;

		internal static ConfigEntry<bool> InstallInfinityHammerTool;

		internal static ConfigEntry<bool> PreferInfinityHammerOnly;

		internal static ConfigEntry<bool> DryRunOnly;

		internal static ConfigEntry<string> DefaultMode;

		internal static ConfigEntry<bool> ShowActiveMode;

		internal static ConfigEntry<bool> PreserveSelectionOnModeSwitch;

		internal static ConfigEntry<int> MaximumTargets;

		internal static ConfigEntry<float> DragSelectRadius;

		internal static ConfigEntry<bool> WarnWhenDeletingOccupiedContainers;

		internal static ConfigEntry<bool> RefuseUnknownDeleteTargets;

		private Harmony _harmony;

		private ButtonConfig _activateButton;

		private bool _clientSystemsStarted;

		private bool _ihToolsInstallDone;

		private static bool _commandsRegistered;

		internal static bool DebugEnabled
		{
			get
			{
				if (DebugLogging != null)
				{
					return DebugLogging.Value;
				}
				return false;
			}
		}

		internal static DismantleSession Session { get; private set; }

		internal static bool PatchesReady { get; private set; }

		private void Awake()
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			ModLogger = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			Session = new DismantleSession();
			RegisterCommands();
			if (GUIManager.IsHeadless())
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Dismantleheim 0.1.0 skipped client systems on headless server.");
				return;
			}
			RegisterActivateButton();
			if (ActivateKey != null)
			{
				ActivateKey.SettingChanged += OnActivateKeyChanged;
			}
			if (Enabled != null)
			{
				Enabled.SettingChanged += OnEnabledChanged;
			}
			TryInstallInfinityHammerTools(forceRetry: false);
			_harmony = new Harmony("com.sonicdm.valheim.dismantleheim");
			try
			{
				_harmony.PatchAll(typeof(DismantleheimPlugin).Assembly);
				PatchesReady = true;
				_clientSystemsStarted = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Dismantleheim 0.1.0 loaded.");
			}
			catch (Exception ex)
			{
				PatchesReady = false;
				((BaseUnityPlugin)this).Logger.LogError((object)("Dismantleheim failed to patch (fail-closed): " + ex));
				try
				{
					_harmony.UnpatchSelf();
				}
				catch
				{
				}
			}
		}

		private void Start()
		{
			if (!GUIManager.IsHeadless() && !_ihToolsInstallDone)
			{
				TryInstallInfinityHammerTools(forceRetry: true);
			}
		}

		private void TryInstallInfinityHammerTools(bool forceRetry)
		{
			if (InstallInfinityHammerTool == null || !InstallInfinityHammerTool.Value)
			{
				_ihToolsInstallDone = true;
			}
			else
			{
				if (_ihToolsInstallDone && !forceRetry)
				{
					return;
				}
				if (InfinityHammerDetector.IsInstalled(out var guid, out var version))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Infinity Hammer detected (" + guid + " " + version + ")."));
				}
				else
				{
					if (!forceRetry)
					{
						return;
					}
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Infinity Hammer not detected; writing owned tools YAML for next IH load. ActivateKey/console remain available.");
				}
				if (YamlToolInstallerBridge.TryInstall(((BaseUnityPlugin)this).Logger, out var destPath, out var wroteBytes))
				{
					_ihToolsInstallDone = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)(wroteBytes ? ("Dismantleheim: wrote owned IH tools file " + destPath) : ("Dismantleheim: owned IH tools file already current " + destPath)));
				}
			}
		}

		private void OnDestroy()
		{
			if (ActivateKey != null)
			{
				ActivateKey.SettingChanged -= OnActivateKeyChanged;
			}
			if (Enabled != null)
			{
				Enabled.SettingChanged -= OnEnabledChanged;
			}
			if (Session != null && Session.IsActive)
			{
				Session.ResetHard("unload");
			}
			HoverHighlighter.ClearAll();
			ContextualInputRouter.ResetLatches();
			DragBoxSelector.Cancel();
			if (_harmony != null)
			{
				try
				{
					_harmony.UnpatchSelf();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Unpatch failed: " + ex.Message));
				}
				_harmony = null;
			}
			PatchesReady = false;
			_activateButton = null;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Dismantleheim unloaded (ScriptEngine-safe).");
		}

		private void RegisterActivateButton()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0015: 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)
			KeyCode key = (KeyCode)((ActivateKey == null) ? 127 : ((int)ActivateKey.Value));
			string key2 = "Dismantleheim_Activate!com.sonicdm.valheim.dismantleheim";
			try
			{
				if (AccessTools.Field(typeof(InputManager), "Buttons")?.GetValue(null) is Dictionary<string, ButtonConfig> dictionary && dictionary.TryGetValue(key2, out var value) && value != null)
				{
					value.Key = key;
					_activateButton = value;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Reused Jotunn activate button after reload.");
					return;
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Activate button reuse failed: " + ex.Message));
			}
			_activateButton = new ButtonConfig
			{
				Name = "Dismantleheim_Activate",
				Key = key,
				ActiveInGUI = false,
				ActiveInCustomGUI = false
			};
			InputManager.Instance.AddButton("com.sonicdm.valheim.dismantleheim", _activateButton);
		}

		internal static bool WasActivatePressed()
		{
			//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)
			ButtonConfig value = null;
			try
			{
				if (AccessTools.Field(typeof(InputManager), "Buttons")?.GetValue(null) is Dictionary<string, ButtonConfig> dictionary)
				{
					dictionary.TryGetValue("Dismantleheim_Activate!com.sonicdm.valheim.dismantleheim", out value);
				}
			}
			catch
			{
			}
			if (value != null && ZInput.GetButtonDown(value.Name))
			{
				return true;
			}
			if (ZInput.GetButtonDown("Dismantleheim_Activate"))
			{
				return true;
			}
			KeyCode val = (KeyCode)((ActivateKey == null) ? 127 : ((int)ActivateKey.Value));
			return Input.GetKeyDown(val);
		}

		private void OnActivateKeyChanged(object sender, EventArgs e)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (_activateButton != null && ActivateKey != null)
			{
				_activateButton.Key = ActivateKey.Value;
			}
		}

		private void OnEnabledChanged(object sender, EventArgs e)
		{
			if (!IsModEnabled() && Session != null && Session.IsActive)
			{
				Session.ResetHard("disabled");
			}
		}

		private void BindConfig()
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Expected O, but got Unknown
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Dismantleheim.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", true, "Write diagnostic lines to BepInEx LogOutput.log. Default on while debugging selection.");
			DefaultMode = ((BaseUnityPlugin)this).Config.Bind<string>("Modes", "DefaultMode", "MassDismantle", "Mode entered by ActivateKey / activate command: MassDismantle or MassDelete.");
			ShowActiveMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Modes", "ShowActiveMode", true, "Show MASS DISMANTLE / MASS DELETE banner near the cursor.");
			PreserveSelectionOnModeSwitch = ((BaseUnityPlugin)this).Config.Bind<bool>("Modes", "PreserveSelectionOnModeSwitch", true, "Keep the queue when switching between Mass Dismantle and Mass Delete (revalidated; never executes).");
			ActivateKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ActivateKey", (KeyCode)127, "Toggle DefaultMode session on/off. Default: Delete. Does not switch modes.");
			ConfirmHoldSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Confirm", "HoldSeconds", 1f, new ConfigDescription("Seconds to hold Mouse3 to confirm.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 5f), Array.Empty<object>()));
			ShowRing = ((BaseUnityPlugin)this).Config.Bind<bool>("Confirm", "ShowRing", true, "Draw the confirmation progress ring around the cursor.");
			ShowSelectedCount = ((BaseUnityPlugin)this).Config.Bind<bool>("Confirm", "ShowSelectedCount", true, "Show selected object count near the reticle.");
			AllowEnvironmentWithFilter = ((BaseUnityPlugin)this).Config.Bind<bool>("Selection", "AllowEnvironmentWithFilter", true, "Mass Delete only: when a prefab filter is sampled, allow matching rocks/trees into the queue.");
			DragSelectRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Selection", "DragSelectRadius", 40f, new ConfigDescription("Unused legacy key (box-select removed). Mass-select is Satisfactory-style Ctrl + aim paint.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 120f), Array.Empty<object>()));
			ClearQueueOnToolSwitch = ((BaseUnityPlugin)this).Config.Bind<bool>("Selection", "ClearQueueOnToolSwitch", true, "Clear the pending selection when leaving Dismantleheim mode.");
			MaximumTargets = ((BaseUnityPlugin)this).Config.Bind<int>("Selection", "MaximumTargets", 50, new ConfigDescription("Maximum queued targets.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 500), Array.Empty<object>()));
			ExtraDenyPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Selection", "ExtraDenyPrefabs", "", "Comma-separated prefab names never selectable.");
			ExtraAllowPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Selection", "ExtraAllowPrefabs", "", "Comma-separated prefab names that ignore ExtraDeny only. Does not bypass type/removability/environment rules.");
			WarnWhenDeletingOccupiedContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "WarnWhenDeletingOccupiedContainers", true, "Mass Delete: show contents-loss warning when queued containers hold items.");
			RefuseUnknownDeleteTargets = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "RefuseUnknownDeleteTargets", true, "Mass Delete: skip unsupported/unknown targets instead of forcing network destroy.");
			InstallInfinityHammerTool = ((BaseUnityPlugin)this).Config.Bind<bool>("Integration", "InstallInfinityHammerTool", true, "Write owned infinity_tools_dismantleheim.yaml (two Tools entries) when Infinity Hammer is installed.");
			PreferInfinityHammerOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Integration", "PreferInfinityHammerOnly", true, "Architecture: never spawn an extra inventory Hammer; Tools YAML + ActivateKey/console only.");
			DryRunOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Removal", "DryRunOnly", false, "When true, confirmation only logs the plan — no world deletes. Default false (live remove). Enable for safe testing.");
		}

		internal static OperationMode GetDefaultMode()
		{
			if (DefaultMode != null && OperationModeUtil.TryParse(DefaultMode.Value, out var mode))
			{
				return mode;
			}
			return OperationMode.MassDismantle;
		}

		private void Update()
		{
			if (_clientSystemsStarted && PatchesReady && IsModEnabled() && Session != null && !GUIManager.IsHeadless())
			{
				ContextualInputRouter.Tick(Session);
				HoverHighlighter.Tick(Session);
				ConfirmationRing.Tick(Session);
			}
		}

		private void OnGUI()
		{
			if (_clientSystemsStarted && PatchesReady && IsModEnabled() && Session != null && Session.IsActive)
			{
				DragBoxSelector.DrawGui();
				ConfirmationRing.DrawGui(Session);
			}
		}

		internal static float GetDragSelectRadius()
		{
			if (DragSelectRadius == null)
			{
				return 40f;
			}
			return Mathf.Clamp(DragSelectRadius.Value, 5f, 120f);
		}

		internal static bool IsModEnabled()
		{
			if (Enabled != null)
			{
				return Enabled.Value;
			}
			return true;
		}

		internal static void DebugLog(string message)
		{
			if (DebugEnabled && ModLogger != null)
			{
				ModLogger.LogInfo((object)("Dismantleheim debug: " + message));
			}
		}

		internal static float GetHoldSeconds()
		{
			if (ConfirmHoldSeconds == null)
			{
				return 1f;
			}
			float value = ConfirmHoldSeconds.Value;
			if (value < 0.2f)
			{
				return 0.2f;
			}
			if (value > 5f)
			{
				return 5f;
			}
			return value;
		}

		private void RegisterCommands()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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
			if (_commandsRegistered)
			{
				return;
			}
			_commandsRegistered = true;
			object obj = <>c.<>9__56_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					DismantleSession session = Session;
					if (session == null)
					{
						PrintCmd("Dismantleheim session unavailable.");
					}
					else if (!PatchesReady && !GUIManager.IsHeadless())
					{
						PrintCmd("Dismantleheim patches failed; activation closed.");
					}
					else if (!IsModEnabled())
					{
						PrintCmd("Dismantleheim disabled in config.");
					}
					else
					{
						switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "status")
						{
						case "mode":
						{
							string text = ((args.Length > 2) ? args[2] : string.Empty);
							if (!OperationModeUtil.TryParse(text, out var mode))
							{
								PrintCmd("Usage: dismantleheim mode dismantle|delete");
							}
							else
							{
								session.SetMode(mode, "command");
								PrintCmd("Dismantleheim mode=" + OperationModeUtil.ShortName(session.ActiveMode) + " active=" + session.IsActive);
							}
							break;
						}
						case "activate":
						{
							if (session.TryActivate(GetDefaultMode(), "command", out var reject))
							{
								PrintCmd("Dismantleheim activated mode=" + OperationModeUtil.ShortName(session.ActiveMode));
							}
							else
							{
								PrintCmd("Dismantleheim activate rejected: " + (reject ?? "unknown") + " (equip Hammer / enter place mode).");
							}
							break;
						}
						case "deactivate":
						case "off":
							session.Deactivate("command");
							PrintCmd("Dismantleheim deactivated.");
							break;
						case "clear":
							session.Queue.Clear();
							session.SyncStateAfterSelectionChange();
							PrintCmd("Dismantleheim selection cleared.");
							break;
						case "why":
							PrintCmd(session.LastRejectReason ?? "(no recent reject)");
							break;
						default:
							PrintCmd("state=" + session.StateMachine.State.ToString() + " mode=" + OperationModeUtil.ShortName(session.ActiveMode) + " queue=" + session.Queue.Count + " filter=" + (session.Sampler.ActiveFilter ?? "(none)") + " dryRun=" + (DryRunOnly != null && DryRunOnly.Value) + " patches=" + PatchesReady);
							break;
						}
					}
				};
				<>c.<>9__56_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("dismantleheim", "Dismantleheim: mode dismantle|delete | activate|deactivate|status|clear|why", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void PrintCmd(string msg)
		{
			if ((Object)(object)Console.instance != (Object)null)
			{
				Console.instance.Print(msg);
			}
			ManualLogSource modLogger = ModLogger;
			if (modLogger != null)
			{
				modLogger.LogInfo((object)msg);
			}
		}
	}
}
namespace Dismantleheim.Core
{
	public sealed class ConfirmationHold
	{
		private float _startTime = -1f;

		private bool _armed = true;

		private bool _holding;

		public bool IsHolding => _holding;

		public float Progress { get; private set; }

		public bool CompletedThisFrame { get; private set; }

		public void Begin(float nowSeconds)
		{
			CompletedThisFrame = false;
			if (_armed)
			{
				_holding = true;
				_startTime = nowSeconds;
				Progress = 0f;
			}
		}

		public void Update(float nowSeconds, float holdSeconds)
		{
			CompletedThisFrame = false;
			if (_holding && _armed)
			{
				float num = ((holdSeconds <= 0.01f) ? 0.01f : holdSeconds);
				float num2 = nowSeconds - _startTime;
				if (num2 < 0f)
				{
					num2 = 0f;
				}
				Progress = num2 / num;
				if (Progress >= 1f)
				{
					Progress = 1f;
					CompletedThisFrame = true;
					_holding = false;
					_armed = false;
				}
			}
		}

		public void Cancel()
		{
			_holding = false;
			_startTime = -1f;
			Progress = 0f;
			CompletedThisFrame = false;
		}

		public void Rearm()
		{
			_armed = true;
			if (!_holding)
			{
				Progress = 0f;
			}
		}
	}
	public enum DismantleState
	{
		Inactive,
		ActiveIdle,
		Selected,
		HoldingConfirm,
		Validating,
		Executing
	}
	public enum DismantleTransition
	{
		Activate,
		Deactivate,
		SelectionChanged,
		BeginHold,
		CancelHold,
		HoldComplete,
		ValidationDone,
		ExecutionDone,
		ToolSwitch
	}
	public sealed class DismantleStateMachine
	{
		public DismantleState State { get; private set; }

		public bool LastTransitionRequestedExecute { get; private set; }

		public bool TryTransition(DismantleTransition transition, int queueCount, out DismantleState newState)
		{
			LastTransitionRequestedExecute = false;
			DismantleState dismantleState = (newState = State);
			if (transition == DismantleTransition.ToolSwitch || transition == DismantleTransition.Deactivate)
			{
				State = DismantleState.Inactive;
				newState = State;
				return true;
			}
			switch (dismantleState)
			{
			case DismantleState.Inactive:
				if (transition == DismantleTransition.Activate)
				{
					State = DismantleState.ActiveIdle;
					newState = State;
					return true;
				}
				break;
			case DismantleState.ActiveIdle:
				switch (transition)
				{
				case DismantleTransition.SelectionChanged:
					State = ((queueCount <= 0) ? DismantleState.ActiveIdle : DismantleState.Selected);
					newState = State;
					return true;
				case DismantleTransition.BeginHold:
					if (queueCount <= 0)
					{
						return false;
					}
					State = DismantleState.HoldingConfirm;
					newState = State;
					return true;
				}
				break;
			case DismantleState.Selected:
				switch (transition)
				{
				case DismantleTransition.SelectionChanged:
					State = ((queueCount <= 0) ? DismantleState.ActiveIdle : DismantleState.Selected);
					newState = State;
					return true;
				case DismantleTransition.BeginHold:
					if (queueCount <= 0)
					{
						return false;
					}
					State = DismantleState.HoldingConfirm;
					newState = State;
					return true;
				}
				break;
			case DismantleState.HoldingConfirm:
				switch (transition)
				{
				case DismantleTransition.CancelHold:
					State = ((queueCount <= 0) ? DismantleState.ActiveIdle : DismantleState.Selected);
					newState = State;
					return true;
				case DismantleTransition.HoldComplete:
					if (queueCount <= 0)
					{
						State = DismantleState.ActiveIdle;
						newState = State;
						return true;
					}
					State = DismantleState.Validating;
					newState = State;
					return true;
				}
				break;
			case DismantleState.Validating:
				if (transition == DismantleTransition.ValidationDone)
				{
					State = DismantleState.Executing;
					LastTransitionRequestedExecute = true;
					newState = State;
					return true;
				}
				break;
			case DismantleState.Executing:
				if (transition == DismantleTransition.ExecutionDone)
				{
					State = ((queueCount <= 0) ? DismantleState.ActiveIdle : DismantleState.Selected);
					newState = State;
					return true;
				}
				break;
			}
			return false;
		}

		public void ForceInactive()
		{
			State = DismantleState.Inactive;
			LastTransitionRequestedExecute = false;
		}
	}
	public enum TargetKind
	{
		Unsupported,
		BuildPiece,
		Environment
	}
	public enum EligibilityRejectReason
	{
		None,
		NullTarget,
		Stale,
		UnsupportedType,
		NoPiece,
		NotRemovable,
		EnvironmentWithoutFilter,
		PrefabFilterMismatch,
		ExtraDeny,
		SessionMismatch,
		NoScopePreview
	}
	public static class Eligibility
	{
		public static bool IsEligible(TargetIdentity target, string prefabFilter, bool allowEnvironmentWithFilter, ISet<string> extraDeny, ISet<string> extraAllow, out EligibilityRejectReason reason)
		{
			return IsEligible(target, OperationMode.MassDelete, prefabFilter, allowEnvironmentWithFilter, extraDeny, extraAllow, out reason);
		}

		public static bool IsEligible(TargetIdentity target, OperationMode mode, string prefabFilter, bool allowEnvironmentWithFilter, ISet<string> extraDeny, ISet<string> extraAllow, out EligibilityRejectReason reason)
		{
			if (!PassesDenyAllow(target, extraDeny, extraAllow, out reason))
			{
				return false;
			}
			bool flag = !string.IsNullOrEmpty(prefabFilter);
			bool flag2 = flag && string.Equals(target.PrefabName ?? string.Empty, prefabFilter, StringComparison.OrdinalIgnoreCase);
			if (mode == OperationMode.MassDelete && flag2 && allowEnvironmentWithFilter)
			{
				if (target.Kind == TargetKind.BuildPiece)
				{
					return PassesBuildPieceRemovability(target, out reason);
				}
				reason = EligibilityRejectReason.None;
				return true;
			}
			if (!PassesHardSafety(target, out reason))
			{
				return false;
			}
			if (mode == OperationMode.MassDismantle)
			{
				if (target.Kind == TargetKind.Environment)
				{
					reason = EligibilityRejectReason.EnvironmentWithoutFilter;
					return false;
				}
				if (target.Kind != TargetKind.BuildPiece)
				{
					reason = EligibilityRejectReason.UnsupportedType;
					return false;
				}
				if (flag && !flag2)
				{
					reason = EligibilityRejectReason.PrefabFilterMismatch;
					return false;
				}
				return PassesBuildPieceRemovability(target, out reason);
			}
			if (flag && !flag2)
			{
				reason = EligibilityRejectReason.PrefabFilterMismatch;
				return false;
			}
			if (target.Kind == TargetKind.Environment)
			{
				reason = EligibilityRejectReason.EnvironmentWithoutFilter;
				return false;
			}
			if (target.Kind != TargetKind.BuildPiece)
			{
				reason = EligibilityRejectReason.UnsupportedType;
				return false;
			}
			return PassesBuildPieceRemovability(target, out reason);
		}

		public static bool IsEligibleForCommit(TargetIdentity target, bool allowEnvironmentWithFilter, ISet<string> extraDeny, ISet<string> extraAllow, out EligibilityRejectReason reason)
		{
			return IsEligibleForCommit(target, OperationMode.MassDelete, allowEnvironmentWithFilter, extraDeny, extraAllow, out reason);
		}

		public static bool IsEligibleForCommit(TargetIdentity target, OperationMode mode, bool allowEnvironmentWithFilter, ISet<string> extraDeny, ISet<string> extraAllow, out EligibilityRejectReason reason)
		{
			if (!PassesDenyAllow(target, extraDeny, extraAllow, out reason))
			{
				return false;
			}
			if (mode == OperationMode.MassDismantle)
			{
				if (!PassesHardSafety(target, out reason))
				{
					return false;
				}
				if (target.Kind != TargetKind.BuildPiece)
				{
					reason = ((target.Kind == TargetKind.Environment) ? EligibilityRejectReason.EnvironmentWithoutFilter : EligibilityRejectReason.UnsupportedType);
					return false;
				}
				return PassesBuildPieceRemovability(target, out reason);
			}
			if (target.Kind == TargetKind.Environment || target.Kind == TargetKind.Unsupported)
			{
				if (!allowEnvironmentWithFilter)
				{
					reason = EligibilityRejectReason.EnvironmentWithoutFilter;
					return false;
				}
				reason = EligibilityRejectReason.None;
				return true;
			}
			if (target.Kind == TargetKind.BuildPiece)
			{
				if (!PassesHardSafety(target, out reason))
				{
					return false;
				}
				return PassesBuildPieceRemovability(target, out reason);
			}
			reason = EligibilityRejectReason.UnsupportedType;
			return false;
		}

		private static bool PassesDenyAllow(TargetIdentity target, ISet<string> extraDeny, ISet<string> extraAllow, out EligibilityRejectReason reason)
		{
			reason = EligibilityRejectReason.None;
			if (target == null)
			{
				reason = EligibilityRejectReason.NullTarget;
				return false;
			}
			if (target.IsStale)
			{
				reason = EligibilityRejectReason.Stale;
				return false;
			}
			string item = target.PrefabName ?? string.Empty;
			bool flag = extraDeny?.Contains(item) ?? false;
			bool flag2 = extraAllow?.Contains(item) ?? false;
			if (flag && !flag2)
			{
				reason = EligibilityRejectReason.ExtraDeny;
				return false;
			}
			return true;
		}

		private static bool PassesHardSafety(TargetIdentity target, out EligibilityRejectReason reason)
		{
			reason = EligibilityRejectReason.None;
			if (target.Kind == TargetKind.Unsupported)
			{
				reason = EligibilityRejectReason.UnsupportedType;
				return false;
			}
			if (!target.HasScopePreview && target.Kind != TargetKind.Environment)
			{
				reason = EligibilityRejectReason.NoScopePreview;
				return false;
			}
			return true;
		}

		private static bool PassesBuildPieceRemovability(TargetIdentity target, out EligibilityRejectReason reason)
		{
			reason = EligibilityRejectReason.None;
			if (!target.HasPiece)
			{
				reason = EligibilityRejectReason.NoPiece;
				return false;
			}
			if (!target.CanBeRemoved)
			{
				reason = EligibilityRejectReason.NotRemovable;
				return false;
			}
			return true;
		}

		public static TargetKind Classify(bool hasPiece, bool canBeRemoved, bool isEnvironment, bool hasScopePreview)
		{
			if (isEnvironment)
			{
				return TargetKind.Environment;
			}
			if (hasPiece)
			{
				return TargetKind.BuildPiece;
			}
			return TargetKind.Unsupported;
		}

		public static HashSet<string> ParsePrefabList(string csv)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(csv))
			{
				return hashSet;
			}
			string[] array = csv.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				string text2 = text.Trim();
				if (text2.Length > 0)
				{
					hashSet.Add(text2);
				}
			}
			return hashSet;
		}
	}
	public static class IhToolNames
	{
		public static bool TryMatch(string label, out OperationMode mode)
		{
			mode = OperationMode.MassDismantle;
			if (string.IsNullOrEmpty(label))
			{
				return false;
			}
			if (label.IndexOf("Mass Delete", StringComparison.OrdinalIgnoreCase) >= 0 || label.IndexOf("mode delete", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				mode = OperationMode.MassDelete;
				return true;
			}
			if (label.IndexOf("Mass Dismantle", StringComparison.OrdinalIgnoreCase) >= 0 || label.IndexOf("mode dismantle", StringComparison.OrdinalIgnoreCase) >= 0 || (label.IndexOf("Dismantleheim", StringComparison.OrdinalIgnoreCase) >= 0 && label.IndexOf("Delete", StringComparison.OrdinalIgnoreCase) < 0))
			{
				mode = OperationMode.MassDismantle;
				return true;
			}
			return false;
		}
	}
	public interface IRemovalPolicy
	{
		OperationMode Mode { get; }

		DropPolicy PredictedDropPolicy { get; }

		bool AllowsEnvironment { get; }

		RemovalPlanEntry PlanEntry(TargetIdentity target, bool allowEnvironmentWithFilter, ISet<string> extraDeny, ISet<string> extraAllow, bool contentsLossWarning);
	}
	public sealed class MassDismantlePolicy : IRemovalPolicy
	{
		public OperationMode Mode => OperationMode.MassDismantle;

		public DropPolicy PredictedDropPolicy => DropPolicy.RefundsViaNative;

		public bool AllowsEnvironment => false;

		public RemovalPlanEntry PlanEntry(TargetIdentity target, bool allowEnvironmentWithFilter, ISet<string> extraDeny, ISet<string> extraAllow, bool contentsLossWarning)
		{
			if (!Eligibility.IsEligibleForCommit(target, Mode, allowEnvironmentWithFilter, extraDeny, extraAllow, out var reason))
			{
				return new RemovalPlanEntry(target, Mode, DropPolicy.None, RemovalSkipReason.ModeIneligible, reason.ToString(), contentsLossWarning: false);
			}
			return new RemovalPlanEntry(target, Mode, DropPolicy.RefundsViaNative, RemovalSkipReason.None, "native refund path", contentsLossWarning: false);
		}
	}
	public sealed class MassDeletePolicy : IRemovalPolicy
	{
		public OperationMode Mode => OperationMode.MassDelete;

		public DropPolicy PredictedDropPolicy => DropPolicy.NoDrops;

		public bool AllowsEnvironment => true;

		public RemovalPlanEntry PlanEntry(TargetIdentity target, bool allowEnvironmentWithFilter, ISet<string> extraDeny, ISet<string> extraAllow, bool contentsLossWarning)
		{
			if (!Eligibility.IsEligibleForCommit(target, Mode, allowEnvironmentWithFilter, extraDeny, extraAllow, out var reason))
			{
				return new RemovalPlanEntry(target, Mode, DropPolicy.None, RemovalSkipReason.ModeIneligible, reason.ToString(), contentsLossWarning: false);
			}
			return new RemovalPlanEntry(target, Mode, DropPolicy.NoDrops, RemovalSkipReason.None, contentsLossWarning ? "no drops; contents-loss warning" : "no drops", contentsLossWarning);
		}
	}
	public static class RemovalPolicyFactory
	{
		public static IRemovalPolicy For(OperationMode mode)
		{
			if (mode != OperationMode.MassDelete)
			{
				return new MassDismantlePolicy();
			}
			return new MassDeletePolicy();
		}
	}
	public enum OperationMode
	{
		MassDismantle,
		MassDelete
	}
	public enum DropPolicy
	{
		None,
		RefundsViaNative,
		NoDrops
	}
	public static class OperationModeUtil
	{
		public static string Banner(OperationMode mode)
		{
			if (mode != OperationMode.MassDelete)
			{
				return "MASS DISMANTLE — Returns Materials";
			}
			return "MASS DELETE — No Drops";
		}

		public static string ShortName(OperationMode mode)
		{
			if (mode != OperationMode.MassDelete)
			{
				return "dismantle";
			}
			return "delete";
		}

		public static bool TryParse(string text, out OperationMode mode)
		{
			mode = OperationMode.MassDismantle;
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			switch (text.Trim().ToLowerInvariant())
			{
			case "dismantle":
			case "massdismantle":
			case "mass-dismantle":
				mode = OperationMode.MassDismantle;
				return true;
			case "delete":
			case "massdelete":
			case "mass-delete":
				mode = OperationMode.MassDelete;
				return true;
			default:
				return false;
			}
		}
	}
	public sealed class PrefabSampler
	{
		public string ActiveFilter { get; private set; }

		public bool HasFilter => !string.IsNullOrEmpty(ActiveFilter);

		public bool TrySample(string prefabName, out string resultingFilter)
		{
			resultingFilter = ActiveFilter;
			if (string.IsNullOrWhiteSpace(prefabName))
			{
				return false;
			}
			string text = prefabName.Trim();
			if (string.Equals(ActiveFilter, text, StringComparison.OrdinalIgnoreCase))
			{
				ActiveFilter = null;
				resultingFilter = null;
				return true;
			}
			ActiveFilter = text;
			resultingFilter = ActiveFilter;
			return true;
		}

		public void Clear()
		{
			ActiveFilter = null;
		}
	}
	public sealed class RemovalPlan
	{
		private readonly List<TargetIdentity> _targets;

		public IReadOnlyList<TargetIdentity> Targets => _targets;

		public int Count => _targets.Count;

		private RemovalPlan(IEnumerable<TargetIdentity> targets)
		{
			_targets = targets.ToList();
		}

		public static RemovalPlan FromQueue(IEnumerable<TargetIdentity> queued, Func<TargetIdentity, bool> isStillValid, out List<TargetIdentity> skipped)
		{
			skipped = new List<TargetIdentity>();
			List<TargetIdentity> list = new List<TargetIdentity>();
			if (queued == null)
			{
				return new RemovalPlan(list);
			}
			foreach (TargetIdentity item in queued)
			{
				if (item != null)
				{
					if (LooksLikeWildcard(item.PrefabName))
					{
						skipped.Add(item);
					}
					else if (isStillValid != null && !isStillValid(item))
					{
						skipped.Add(item);
					}
					else
					{
						list.Add(item);
					}
				}
			}
			return new RemovalPlan(list);
		}

		public static bool LooksLikeWildcard(string prefabOrDescriptor)
		{
			if (string.IsNullOrEmpty(prefabOrDescriptor))
			{
				return false;
			}
			if (prefabOrDescriptor.IndexOf("id=*", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			if (prefabOrDescriptor.IndexOf("*", StringComparison.Ordinal) >= 0 && prefabOrDescriptor.IndexOf("remove", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			return false;
		}
	}
	public enum RemovalSkipReason
	{
		None,
		Stale,
		PermissionDenied,
		ContainerWithContents,
		Portal,
		Ward,
		UnsupportedEnvironment,
		WildcardRejected,
		DryRun,
		UnsafeDelete,
		ModeIneligible,
		PendingNetwork
	}
	public sealed class RemovalPlanEntry
	{
		public TargetIdentity Target { get; }

		public OperationMode Mode { get; }

		public DropPolicy DropPolicy { get; }

		public RemovalSkipReason SkipReason { get; }

		public string Message { get; }

		public bool ContentsLossWarning { get; }

		public bool IsExecutable
		{
			get
			{
				if (SkipReason != RemovalSkipReason.None)
				{
					return SkipReason == RemovalSkipReason.DryRun;
				}
				return true;
			}
		}

		public RemovalPlanEntry(TargetIdentity target, OperationMode mode, DropPolicy dropPolicy, RemovalSkipReason skipReason, string message, bool contentsLossWarning)
		{
			Target = target;
			Mode = mode;
			DropPolicy = dropPolicy;
			SkipReason = skipReason;
			Message = message ?? string.Empty;
			ContentsLossWarning = contentsLossWarning;
		}
	}
	public sealed class RemovalResult
	{
		public TargetIdentity Target { get; }

		public bool Removed { get; }

		public RemovalSkipReason SkipReason { get; }

		public string Message { get; }

		public DropPolicy DropPolicy { get; }

		public OperationMode Mode { get; }

		public RemovalResult(TargetIdentity target, bool removed, RemovalSkipReason skipReason, string message, DropPolicy dropPolicy = DropPolicy.None, OperationMode mode = OperationMode.MassDismantle)
		{
			Target = target;
			Removed = removed;
			SkipReason = skipReason;
			Message = message ?? string.Empty;
			DropPolicy = dropPolicy;
			Mode = mode;
		}
	}
	public sealed class SelectionQueue
	{
		private readonly List<TargetIdentity> _entries = new List<TargetIdentity>();

		public int Count => _entries.Count;

		public IReadOnlyList<TargetIdentity> Entries => _entries;

		public bool Contains(TargetIdentity identity)
		{
			if (identity == null)
			{
				return false;
			}
			for (int i = 0; i < _entries.Count; i++)
			{
				if (_entries[i].Equals(identity))
				{
					return true;
				}
			}
			return false;
		}

		public bool Toggle(TargetIdentity identity, int maxCount = 0)
		{
			if (identity == null)
			{
				return false;
			}
			for (int i = 0; i < _entries.Count; i++)
			{
				if (_entries[i].Equals(identity))
				{
					_entries.RemoveAt(i);
					return false;
				}
			}
			return TryAdd(identity, maxCount);
		}

		public bool TryAdd(TargetIdentity identity, int maxCount = 0)
		{
			if (identity == null || Contains(identity))
			{
				return false;
			}
			if (maxCount > 0 && _entries.Count >= maxCount)
			{
				return false;
			}
			_entries.Add(identity);
			return true;
		}

		public bool TryRemove(TargetIdentity identity)
		{
			if (identity == null)
			{
				return false;
			}
			for (int i = 0; i < _entries.Count; i++)
			{
				if (_entries[i].Equals(identity))
				{
					_entries.RemoveAt(i);
					return true;
				}
			}
			return false;
		}

		public void Clear()
		{
			_entries.Clear();
		}

		public IReadOnlyList<TargetIdentity> Snapshot()
		{
			return _entries.ToList();
		}
	}
	public sealed class TargetIdentity : IEquatable<TargetIdentity>
	{
		public long UserId { get; }

		public uint ObjectId { get; }

		public long NetworkId => ObjectId;

		public string WorldSessionKey { get; }

		public string PrefabName { get; }

		public bool HasPiece { get; }

		public bool CanBeRemoved { get; }

		public bool IsEnvironment { get; }

		public TargetKind Kind { get; }

		public bool HasScopePreview { get; }

		public bool IsStale { get; }

		public TargetIdentity(long userId, uint objectId, string worldSessionKey, string prefabName, bool hasPiece, bool canBeRemoved, bool isEnvironment, TargetKind kind, bool hasScopePreview, bool isStale = false)
		{
			UserId = userId;
			ObjectId = objectId;
			WorldSessionKey = worldSessionKey ?? string.Empty;
			PrefabName = prefabName ?? string.Empty;
			HasPiece = hasPiece;
			CanBeRemoved = canBeRemoved;
			IsEnvironment = isEnvironment;
			Kind = kind;
			HasScopePreview = hasScopePreview;
			IsStale = isStale;
		}

		public bool Equals(TargetIdentity other)
		{
			if (other == null)
			{
				return false;
			}
			if (UserId == other.UserId && ObjectId == other.ObjectId)
			{
				return string.Equals(WorldSessionKey, other.WorldSessionKey, StringComparison.Ordinal);
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			return Equals(obj as TargetIdentity);
		}

		public override int GetHashCode()
		{
			int hashCode = UserId.GetHashCode();
			hashCode = (hashCode * 397) ^ ObjectId.GetHashCode();
			return (hashCode * 397) ^ ((WorldSessionKey != null) ? WorldSessionKey.GetHashCode() : 0);
		}
	}
	public static class YamlToolInstaller
	{
		public const string ToolNameDismantle = "Dismantleheim - Mass Dismantle";

		public const string ToolNameDelete = "Dismantleheim - Mass Delete";

		public const string LegacyToolName = "Dismantleheim";

		public const string Marker = "dismantleheim-tool-v10";

		public const string ActivateCommandDismantle = "dismantleheim mode dismantle";

		public const string ActivateCommandDelete = "dismantleheim mode delete";

		public const string LegacyActivateCommand = "dismantleheim activate";

		public const string EquipmentKey = "hammer";

		public const string OwnedFileName = "infinity_tools_dismantleheim.yaml";

		public const string ConflictBackupSuffix = ".dismantleheim-conflict.bak";

		public const string ToolName = "Dismantleheim - Mass Dismantle";

		public const string ActivateCommand = "dismantleheim mode dismantle";

		public static string BuildOwnedDocument()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# dismantleheim-tool-v10 — owned by Dismantleheim; safe to delete on uninstall");
			stringBuilder.AppendLine("hammer:");
			AppendTool(stringBuilder, "Dismantleheim - Mass Dismantle", "Select built pieces, then hold Mouse3 to reclaim materials (vanilla refunds).", "dismantleheim mode dismantle");
			AppendTool(stringBuilder, "Dismantleheim - Mass Delete", "Select objects, then hold Mouse3 to erase without drops. Containers may destroy contents.", "dismantleheim mode delete");
			return stringBuilder.ToString();
		}

		private static void AppendTool(StringBuilder sb, string name, string description, string command)
		{
			sb.AppendLine("- name: " + name);
			sb.AppendLine("  description: |-");
			sb.AppendLine("    " + description);
			sb.AppendLine("    Hold Ctrl + wave aim to mass-select. Ctrl+click unselects one. Shift+Mouse3 samples.");
			sb.AppendLine("    Hold Mouse3 to confirm.");
			sb.AppendLine("  icon: Hammer");
			sb.AppendLine("  instant: true");
			sb.AppendLine("  command: " + command);
			sb.AppendLine("  tabIndex: 0");
		}

		public static bool WriteOwnedDocument(string existingOwnedYaml, out string nextYaml)
		{
			string text = existingOwnedYaml ?? string.Empty;
			if (ShouldPreserveOwnedDocument(text))
			{
				nextYaml = NormalizeNewlines(text).TrimEnd() + Environment.NewLine;
				return false;
			}
			string text2 = NormalizeNewlines(BuildOwnedDocument()).TrimEnd() + "\n";
			string a = NormalizeNewlines(text).TrimEnd() + "\n";
			nextYaml = text2.Replace("\n", Environment.NewLine);
			return !string.Equals(a, text2, StringComparison.Ordinal);
		}

		public static bool ShouldPreserveOwnedDocument(string yaml)
		{
			if (string.IsNullOrWhiteSpace(yaml))
			{
				return false;
			}
			string a = NormalizeNewlines(BuildOwnedDocument()).TrimEnd();
			string text = NormalizeNewlines(yaml).TrimEnd();
			if (string.Equals(a, text, StringComparison.Ordinal))
			{
				return false;
			}
			if (IsUpgradeableStockDocument(text))
			{
				return false;
			}
			return true;
		}

		public static bool IsUpgradeableStockDocument(string yaml)
		{
			if (string.IsNullOrWhiteSpace(yaml))
			{
				return false;
			}
			if (yaml.IndexOf("dismantleheim-tool", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return false;
			}
			if (Regex.IsMatch(NormalizeNewlines(yaml), "(?m)^\\s*icon:\\s*(?!Hammer\\s*$).+$"))
			{
				return false;
			}
			int num = CountNamedToolsInDocument(yaml, "Dismantleheim - Mass Dismantle");
			int num2 = CountNamedToolsInDocument(yaml, "Dismantleheim - Mass Delete");
			bool flag = CountNamedToolsInDocument(yaml, "Dismantleheim") > 0;
			bool flag2 = num == 1 && num2 == 1;
			if (num == 0 && num2 == 0 && !flag)
			{
				return false;
			}
			if (yaml.IndexOf("dismantleheim-tool-", StringComparison.OrdinalIgnoreCase) >= 0 && yaml.IndexOf("dismantleheim-tool-v10", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return true;
			}
			return !flag2 || flag;
		}

		public static bool WriteOwnedFile(string configRoot, bool preferToolsSubfolder)
		{
			if (string.IsNullOrEmpty(configRoot))
			{
				throw new ArgumentException("configRoot required", "configRoot");
			}
			string text = Path.Combine(configRoot, "tools");
			bool flag = preferToolsSubfolder && Directory.Exists(text);
			string text2 = Path.Combine(flag ? text : configRoot, "infinity_tools_dismantleheim.yaml");
			string text3 = Path.Combine(flag ? configRoot : text, "infinity_tools_dismantleheim.yaml");
			ResolveExistingOwnedContent(text2, text3, out var existing, out var _);
			bool result = false;
			WriteOwnedDocument(existing, out var nextYaml);
			string s = (File.Exists(text2) ? File.ReadAllText(text2, Encoding.UTF8) : string.Empty);
			if (!File.Exists(text2) || !string.Equals(NormalizeNewlines(s), NormalizeNewlines(nextYaml), StringComparison.Ordinal))
			{
				AtomicWrite(text2, nextYaml);
				result = true;
			}
			if (File.Exists(text3) && !string.Equals(Path.GetFullPath(text3), Path.GetFullPath(text2), StringComparison.OrdinalIgnoreCase))
			{
				string text4 = File.ReadAllText(text3, Encoding.UTF8);
				string s2 = File.ReadAllText(text2, Encoding.UTF8);
				if (!string.Equals(NormalizeNewlines(text4), NormalizeNewlines(s2), StringComparison.Ordinal))
				{
					AtomicWrite(text3 + ".dismantleheim-conflict.bak", text4);
				}
				File.Delete(text3);
				result = true;
			}
			TryRemoveStaleFromSharedDefault(configRoot);
			return result;
		}

		public static void ResolveExistingOwnedContent(string preferredPath, string alternatePath, out string existing, out string conflictBackupPath)
		{
			existing = string.Empty;
			conflictBackupPath = null;
			bool flag = File.Exists(preferredPath);
			bool flag2 = File.Exists(alternatePath) && !string.Equals(Path.GetFullPath(preferredPath), Path.GetFullPath(alternatePath), StringComparison.OrdinalIgnoreCase);
			if (!flag && !flag2)
			{
				return;
			}
			if (flag && !flag2)
			{
				existing = File.ReadAllText(preferredPath, Encoding.UTF8);
				return;
			}
			if (!flag && flag2)
			{
				existing = File.ReadAllText(alternatePath, Encoding.UTF8);
				return;
			}
			string text = File.ReadAllText(preferredPath, Encoding.UTF8);
			string text2 = File.ReadAllText(alternatePath, Encoding.UTF8);
			if (string.Equals(NormalizeNewlines(text), NormalizeNewlines(text2), StringComparison.Ordinal))
			{
				existing = text;
				return;
			}
			bool flag3 = ShouldPreserveOwnedDocument(text);
			if (ShouldPreserveOwnedDocument(text2) && !flag3)
			{
				existing = text2;
			}
			else
			{
				existing = text;
			}
			conflictBackupPath = alternatePath + ".dismantleheim-conflict.bak";
		}

		public static int CountNamedToolsInDocument(string yaml, string toolName)
		{
			if (string.IsNullOrEmpty(yaml))
			{
				return 0;
			}
			int num = 0;
			Regex regex = new Regex("^\\s*-\\s*name:\\s*(?:\"|')?" + Regex.Escape(toolName) + "(?:\"|')?\\s*$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
			foreach (Match item in regex.Matches(yaml))
			{
				num++;
			}
			return num;
		}

		public static bool OwnedEntryHasActivateCommand(string yaml)
		{
			if (!OwnedEntryHasCommand(yaml, "Dismantleheim - Mass Dismantle", "dismantleheim mode dismantle"))
			{
				return OwnedEntryHasCommand(yaml, "Dismantleheim - Mass Delete", "dismantleheim mode delete");
			}
			return true;
		}

		public static bool OwnedEntryHasCommand(string yaml, string toolName, string command)
		{
			if (string.IsNullOrEmpty(yaml))
			{
				return false;
			}
			string[] array = NormalizeNewlines(yaml).Split('\n');
			bool flag = false;
			Regex regex = new Regex("^\\s*-\\s*name:\\s*(?:\"|')?" + Regex.Escape(toolName) + "(?:\"|')?\\s*$", RegexOptions.IgnoreCase);
			Regex regex2 = new Regex("^\\s*-\\s*name:\\s*\\S");
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.TrimEnd('\r');
				if (regex.IsMatch(text2))
				{
					flag = true;
					continue;
				}
				if (flag && regex2.IsMatch(text2))
				{
					flag = false;
				}
				if (flag && text2.IndexOf("command:", StringComparison.OrdinalIgnoreCase) >= 0 && text2.IndexOf(command, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		public static bool LooksLikeEquipmentDictionary(string yaml)
		{
			if (string.IsNullOrEmpty(yaml))
			{
				return false;
			}
			return Regex.IsMatch(NormalizeNewlines(yaml), "(?m)^[A-Za-z][A-Za-z0-9_]*:\\s*$", RegexOptions.None);
		}

		public static string RemoveNamedToolFromShared(string yaml, string toolName)
		{
			if (string.IsNullOrEmpty(yaml))
			{
				return string.Empty;
			}
			string[] array = NormalizeNewlines(yaml).Split('\n');
			List<string> list = new List<string>();
			bool flag = false;
			Regex regex = new Regex("^\\s*-\\s*name:\\s*(?:\"|')?" + Regex.Escape(toolName) + "(?:\"|')?\\s*$", RegexOptions.IgnoreCase);
			Regex regex2 = new Regex("^\\s*-\\s*name:\\s*\\S");
			Regex regex3 = new Regex("^[A-Za-z][A-Za-z0-9_]*:\\s*$");
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].TrimEnd('\r');
				if (regex.IsMatch(text))
				{
					if (!BlockLooksOwned(array, i))
					{
						list.Add(text);
						continue;
					}
					flag = true;
					if (list.Count > 0 && list[list.Count - 1].IndexOf("dismantleheim-tool", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						list.RemoveAt(list.Count - 1);
					}
					continue;
				}
				if (flag)
				{
					if (!regex2.IsMatch(text) && !regex3.IsMatch(text))
					{
						continue;
					}
					flag = false;
				}
				list.Add(text);
			}
			return string.Join(Environment.NewLine, list).TrimEnd() + Environment.NewLine;
		}

		private static bool BlockLooksOwned(string[] lines, int nameLineIndex)
		{
			int num = nameLineIndex - 1;
			while (num >= 0 && num >= nameLineIndex - 3)
			{
				if (lines[num].IndexOf("dismantleheim-tool", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				num--;
			}
			Regex regex = new Regex("^\\s*-\\s*name:\\s*\\S");
			Regex regex2 = new Regex("^[A-Za-z][A-Za-z0-9_]*:\\s*$");
			for (int i = nameLineIndex + 1; i < lines.Length; i++)
			{
				string text = lines[i].TrimEnd('\r');
				if (regex.IsMatch(text) || regex2.IsMatch(text))
				{
					break;
				}
				if (text.IndexOf("command:", StringComparison.OrdinalIgnoreCase) >= 0 && (text.IndexOf("dismantleheim mode dismantle", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("dismantleheim mode delete", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("dismantleheim activate", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					return true;
				}
			}
			return false;
		}

		private static void TryRemoveStaleFromSharedDefault(string configRoot)
		{
			string[] array = new string[3] { "Dismantleheim - Mass Dismantle", "Dismantleheim - Mass Delete", "Dismantleheim" };
			string[] array2 = new string[2]
			{
				Path.Combine(configRoot, "infinity_tools.yaml"),
				Path.Combine(configRoot, "tools", "infinity_tools.yaml")
			};
			foreach (string path in array2)
			{
				if (!File.Exists(path))
				{
					continue;
				}
				string text = File.ReadAllText(path, Encoding.UTF8);
				string text2 = text;
				string[] array3 = array;
				foreach (string toolName in array3)
				{
					if (CountNamedToolsInDocument(text2, toolName) > 0)
					{
						text2 = RemoveNamedToolFromShared(text2, toolName);
					}
				}
				if (!string.Equals(NormalizeNewlines(text), NormalizeNewlines(text2), StringComparison.Ordinal))
				{
					AtomicWrite(path, text2);
				}
			}
		}

		private static void AtomicWrite(string path, string contents)
		{
			string directoryName = Path.GetDirectoryName(path);
			if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			string text = path + ".tmp";
			File.WriteAllText(text, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			if (File.Exists(path))
			{
				File.Replace(text, path, null);
			}
			else
			{
				File.Move(text, path);
			}
		}

		private static string NormalizeNewlines(string s)
		{
			return (s ?? string.Empty).Replace("\r\n", "\n").Replace('\r', '\n');
		}
	}
}
namespace Dismantleheim.UI
{
	internal static class ConfirmationRing
	{
		private static GUIStyle _bannerStyle;

		private static GUIStyle _subStyle;

		private static Texture2D _panelTex;

		public static void Tick(DismantleSession session)
		{
		}

		public static void DrawGui(DismantleSession session)
		{
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			if (session == null || !session.IsActive)
			{
				return;
			}
			EnsureStyles();
			bool flag = DismantleheimPlugin.ShowActiveMode == null || DismantleheimPlugin.ShowActiveMode.Value;
			bool flag2 = DismantleheimPlugin.ShowSelectedCount == null || DismantleheimPlugin.ShowSelectedCount.Value;
			if (flag || flag2)
			{
				string text = (flag ? OperationModeUtil.Banner(session.ActiveMode) : string.Empty);
				string text2 = string.Empty;
				if (flag2)
				{
					text2 = session.Queue.Count + " selected";
					if (session.Sampler.HasFilter)
					{
						text2 = text2 + "  [" + session.Sampler.ActiveFilter + "]";
					}
					if (DismantleheimPlugin.DryRunOnly != null && DismantleheimPlugin.DryRunOnly.Value)
					{
						text2 += "  (dry-run)";
					}
				}
				float num = 520f;
				float num2 = ((flag && flag2) ? 54f : 32f);
				if (session.HasContentsLossWarning)
				{
					num2 += 22f;
				}
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, 18f, num, num2);
				Color color = GUI.color;
				GUI.color = new Color(0f, 0f, 0f, 0.72f);
				GUI.DrawTexture(val, (Texture)(object)_panelTex);
				GUI.color = color;
				float num3 = ((Rect)(ref val)).y + 6f;
				if (flag)
				{
					_bannerStyle.normal.textColor = ((session.ActiveMode == OperationMode.MassDelete) ? new Color(1f, 0.45f, 0.35f, 1f) : new Color(0.85f, 0.95f, 0.55f, 1f));
					GUI.Label(new Rect(((Rect)(ref val)).x, num3, ((Rect)(ref val)).width, 26f), text, _bannerStyle);
					num3 += 24f;
				}
				if (flag2)
				{
					_subStyle.normal.textColor = new Color(1f, 0.95f, 0.4f, 1f);
					GUI.Label(new Rect(((Rect)(ref val)).x, num3, ((Rect)(ref val)).width, 22f), text2, _subStyle);
					num3 += 20f;
				}
				if (session.HasContentsLossWarning)
				{
					_subStyle.normal.textColor = new Color(1f, 0.35f, 0.2f, 1f);
					GUI.Label(new Rect(((Rect)(ref val)).x, num3, ((Rect)(ref val)).width, 22f), "WARNING: queued containers hold items", _subStyle);
				}
			}
			if ((DismantleheimPlugin.ShowRing == null || DismantleheimPlugin.ShowRing.Value) && (session.ConfirmHold.IsHolding || !(session.ConfirmHold.Progress <= 0f)))
			{
				float progress = session.ConfirmHold.Progress;
				Vector2 val2 = Vector2.op_Implicit(Input.mousePosition);
				val2.y = (float)Screen.height - val2.y;
				DrawArc(val2, 22f, progress, session.ActiveMode);
			}
		}

		private static void EnsureStyles()
		{
			//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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_004f: Expected O, but got Unknown
			//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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_0087: Expected O, but got Unknown
			if ((Object)(object)_panelTex == (Object)null)
			{
				_panelTex = Texture2D.whiteTexture;
			}
			if (_bannerStyle == null)
			{
				_bannerStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)1,
					fontSize = 18,
					fontStyle = (FontStyle)1,
					wordWrap = false
				};
			}
			if (_subStyle == null)
			{
				_subStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)1,
					fontSize = 14,
					fontStyle = (FontStyle)1,
					wordWrap = false
				};
			}
		}

		private static void DrawArc(Vector2 center, float radius, float progress, OperationMode mode)
		{
			//IL_005c: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			progress = Mathf.Clamp01(progress);
			Texture2D whiteTexture = Texture2D.whiteTexture;
			Color color = default(Color);
			((Color)(ref color))..ctor(0f, 0f, 0f, 0.55f);
			Color color2 = ((mode == OperationMode.MassDelete) ? new Color(1f, 0.4f, 0.25f, 0.95f) : new Color(1f, 0.75f, 0.2f, 0.95f));
			for (int i = 0; i < 48; i++)
			{
				float a = (float)i / 48f * MathF.PI * 2f - MathF.PI / 2f;
				float a2 = (float)(i + 1) / 48f * MathF.PI * 2f - MathF.PI / 2f;
				DrawSegment(center, radius, a, a2, color, whiteTexture);
			}
			int num = Mathf.CeilToInt(48f * progress);
			for (int j = 0; j < num; j++)
			{
				float a3 = (float)j / 48f * MathF.PI * 2f - MathF.PI / 2f;
				float a4 = (float)(j + 1) / 48f * MathF.PI * 2f - MathF.PI / 2f;
				DrawSegment(center, radius, a3, a4, color2, whiteTexture);
			}
		}

		private static void DrawSegment(Vector2 center, float radius, float a0, float a1, Color color, Texture2D tex)
		{
			//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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_003c: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			Vector2 a2 = center + new Vector2(Mathf.Cos(a0), Mathf.Sin(a0)) * radius;
			Vector2 b = center + new Vector2(Mathf.Cos(a1), Mathf.Sin(a1)) * radius;
			DrawLine(a2, b, color, tex, 3f);
		}

		private static void DrawLine(Vector2 a, Vector2 b, Color color, Texture2D tex, float width)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = b - a;
			float magnitude = ((Vector2)(ref val)).magnitude;
			if (!(magnitude < 0.01f))
			{
				float num = Mathf.Atan2(val.y, val.x) * 57.29578f;
				GUI.color = color;
				Matrix4x4 matrix = GUI.matrix;
				GUIUtility.RotateAroundPivot(num, a);
				GUI.DrawTexture(new Rect(a.x, a.y - width * 0.5f, magnitude, width), (Texture)(object)tex);
				GUI.matrix = matrix;
				GUI.color = Color.white;
			}
		}
	}
	internal static class HoverHighlighter
	{
		private static readonly Color SelectedColor = new Color(1f, 0.35f, 0.15f, 1f);

		private static readonly Color HoverColor = new Color(0.35f, 0.85f, 1f, 1f);

		private static readonly HashSet<int> _activeTintIds = new HashSet<int>();

		private static readonly HashSet<int> _frameTintIds = new HashSet<int>();

		private static readonly Dictionary<int, GameObject> _tintRoots = new Dictionary<int, GameObject>();

		public static void Tick(DismantleSession session)
		{
			//IL_0036: 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)
			if (session == null || !session.IsActive)
			{
				ClearAll();
				return;
			}
			_frameTintIds.Clear();
			foreach (TargetIdentity entry in session.Queue.Entries)
			{
				Apply(entry, SelectedColor);
			}
			TargetIdentity hoverTarget = session.HoverTarget;
			if (hoverTarget != null && Eligibility.IsEligible(hoverTarget, session.ActiveMode, session.Sampler.ActiveFilter, session.AllowEnvWithFilter, session.ExtraDeny(), session.ExtraAllow(), out var _) && !session.Queue.Contains(hoverTarget))
			{
				Apply(hoverTarget, HoverColor);
			}
			if (_activeTintIds.Count > 0)
			{
				List<int> list = null;
				foreach (int activeTintId in _activeTintIds)
				{
					if (!_frameTintIds.Contains(activeTintId))
					{
						if (list == null)
						{
							list = new List<int>();
						}
						list.Add(activeTintId);
					}
				}
				if (list != null)
				{
					foreach (int item in list)
					{
						ResetTracked(item);
					}
				}
			}
			_activeTintIds.Clear();
			foreach (int frameTintId in _frameTintIds)
			{
				_activeTintIds.Add(frameTintId);
			}
		}

		public static void ClearAll()
		{
			if (_activeTintIds.Count == 0 && _tintRoots.Count == 0)
			{
				return;
			}
			List<int> list = new List<int>(_activeTintIds);
			foreach (int item in list)
			{
				ResetTracked(item);
			}
			_activeTintIds.Clear();
			_frameTintIds.Clear();
			_tintRoots.Clear();
		}

		private static void Apply(TargetIdentity id, Color color)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (id == null)
			{
				return;
			}
			GameObject val = ExactObjectExecutor.ResolveInstance(id);
			if ((Object)val == (Object)null)
			{
				return;
			}
			WearNTear val2 = val.GetComponent<WearNTear>();
			if ((Object)val2 == (Object)null)
			{
				val2 = val.GetComponentInChildren<WearNTear>();
			}
			if ((Object)val2 != (Object)null)
			{
				val2.Highlight();
				ApplyMaterialTint(((Component)val2).gameObject, color);
				try
				{
					((MonoBehaviour)val2).CancelInvoke("ResetHighlight");
					((MonoBehaviour)val2).Invoke("ResetHighlight", 0.35f);
					return;
				}
				catch
				{
					return;
				}
			}
			ApplyMaterialTint(val, color);
		}

		private static void ApplyMaterialTint(GameObject go, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_002d: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)go == (Object)null)
			{
				return;
			}
			try
			{
				MaterialMan instance = MaterialMan.instance;
				if (!((Object)instance == (Object)null))
				{
					instance.SetValue<Color>(go, ShaderProps._EmissionColor, color * 0.55f, false);
					instance.SetValue<Color>(go, ShaderProps._Color, color, false);
					int instanceID = ((Object)go).GetInstanceID();
					_frameTintIds.Add(instanceID);
					_tintRoots[instanceID] = go;
				}
			}
			catch
			{
			}
		}

		private static void ResetTracked(int instanceId)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			if (!_tintRoots.TryGetValue(instanceId, out var value))
			{
				_activeTintIds.Remove(instanceId);
				return;
			}
			_tintRoots.Remove(instanceId);
			_activeTintIds.Remove(instanceId);
			if ((Object)value == (Object)null)
			{
				return;
			}
			try
			{
				MaterialMan instance = MaterialMan.instance;
				if (!((Object)instance == (Object)null))
				{
					instance.ResetValue(value, ShaderProps._Color);
					instance.ResetValue(value, ShaderProps._EmissionColor);
				}
			}
			catch
			{
			}
		}
	}
}
namespace Dismantleheim.Selection
{
	internal sealed class DismantleSession
	{
		private List<TargetIdentity> _confirmSnapshot;

		public SelectionQueue Queue { get; } = new SelectionQueue();

		public PrefabSampler Sampler { get; } = new PrefabSampler();

		public DismantleStateMachine StateMachine { get; } = new DismantleStateMachine();

		public ConfirmationHold ConfirmHold { get; } = new ConfirmationHold();

		public TargetIdentity HoverTarget { get; set; }

		public string LastRejectReason { get; set; }

		public int IgnorePieceChangeFrames { get; set; }

		public OperationMode ActiveMode { get; private set; }

		public bool HasContentsLossWarning { get; private set; }

		public bool IsActive => StateMachine.State != DismantleState.Inactive;

		public bool AllowEnvWithFilter
		{
			get
			{
				if (DismantleheimPlugin.AllowEnvironmentWithFilter != null)
				{
					return DismantleheimPlugin.AllowEnvironmentWithFilter.Value;
				}
				return true;
			}
		}

		public int MaximumTargets
		{
			get
			{
				if (DismantleheimPlugin.MaximumTargets == null)
				{
					return 50;
				}
				return DismantleheimPlugin.MaximumTargets.Value;
			}
		}

		public bool TryActivate(string source, out string reject)
		{
			return TryActivate(ActiveMode, source, out reject);
		}

		public bool TryActivate(OperationMode mode, string source, out string reject)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			reject = null;
			ActiveMode = mode;
			if (StateMachine.State != DismantleState.Inactive)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)localPlayer == (Object)null)
			{
				reject = "no-player";
				return false;
			}
			if (!((Character)localPlayer).InPlaceMode())
			{
				reject = "not-in-place-mode";
				ManualLogSource modLogger = DismantleheimPlugin.ModLogger;
				if (modLogger != null)
				{
					modLogger.LogInfo((object)("Dismantleheim activate rejected: " + reject));
				}
				return false;
			}
			StateMachine.TryTransition(DismantleTransition.Activate, Queue.Count, out var _);
			IgnorePieceChangeFrames = 180;
			ToolIdentityTracker.OnActivated();
			ContextualInputRouter.ResetLatches();
			DragBoxSelector.Cancel();
			RefreshContentsWarning();
			Player localPlayer2 = Player.m_localPlayer;
			bool flag = (Object)localPlayer2 != (Object)null && ((Character)localPlayer2).InPlaceMode();
			string text = (((Object)localPlayer2 != (Object)null && ((Humanoid)localPlayer2).RightItem != null) ? (((((Humanoid)localPlayer2).RightItem.m_shared != null) ? ((Humanoid)localPlayer2).RightItem.m_shared.m_name : "?") + "|" + (((Object)(object)((Humanoid)localPlayer2).RightItem.m_dropPrefab != (Object)null) ? ((Object)((Humanoid)localPlayer2).RightItem.m_dropPrefab).name : "?")) : "empty");
			ManualLogSource modLogger2 = DismantleheimPlugin.ModLogger;
			if (modLogger2 != null)
			{
				modLogger2.LogInfo((object)("Dismantleheim activate via " + source + " mode=" + OperationModeUtil.ShortName(ActiveMode) + " state=" + StateMachine.State.ToString() + " place=" + flag + " item=" + text + " grace=" + IgnorePieceChangeFrames));
			}
			if ((Object)localPlayer2 != (Object)null)
			{
				((Character)localPlayer2).Message((MessageType)1, OperationModeUtil.Banner(ActiveMode), 0, (Sprite)null, false);
			}
			return true;
		}

		public void Activate(string source)
		{
			TryActivate(source, out var _);
		}

		public void SetMode(OperationMode mode, string source)
		{
			if (ActiveMode == mode && IsActive)
			{
				return;
			}
			ConfirmHold.Cancel();
			ClearConfirmSnapshot();
			bool flag = DismantleheimPlugin.PreserveSelectionOnModeSwitch == null || DismantleheimPlugin.PreserveSelectionOnModeSwitch.Value;
			OperationMode activeMode = ActiveMode;
			ActiveMode = mode;
			if (!IsActive)
			{
				TryActivate(mode, source, out var _);
				return;
			}
			if (!flag)
			{
				Queue.Clear();
			}
			RefreshContentsWarning();
			SyncStateAfterSelectionChange();
			ManualLogSource modLogger = DismantleheimPlugin.ModLogger;
			if (modLogger != null)
			{
				modLogger.LogInfo((object)("Dismantleheim mode " + OperationModeUtil.ShortName(activeMode) + " → " + OperationModeUtil.ShortName(mode) + " via " + source + " queue=" + Queue.Count));
			}
		}

		public void Deactivate(string source)
		{
			int count = Queue.Count;
			DismantleState state = StateMachine.State;
			ConfirmHold.Cancel();
			ConfirmHold.Rearm();
			ClearConfirmSnapshot();
			if (DismantleheimPlugin.ClearQueueOnToolSwitch == null || DismantleheimPlugin.ClearQueueOnToolSwitch.Value)
			{
				Queue.Clear();
			}
			HoverTarget = null;
			HasContentsLossWarning = false;
			StateMachine.ForceInactive();
			ToolIdentityTracker.OnDeactivated();
			ContextualInputRouter.ResetLatches();
			HoverHighlighter.ClearAll();
			ManualLogSource modLogger = DismantleheimPlugin.ModLogger;
			if (modLogger != null)
			{
				modLogger.LogInfo((object)("Dismantleheim deactivate via " + source + " queue=" + count + " wasState=" + state.ToString() + " mode=" + OperationModeUtil.ShortName(ActiveMode)));
			}
		}

		public void ResetHard(string source)
		{
			Queue.Clear();
			Sampler.Clear();
			ConfirmHold.Cancel();
			ConfirmHold.Rearm();
			ClearConfirmSnapshot();
			HoverTarget = null;
			HasContentsLossWarning = false;
			StateMachine.ForceInactive();
			ToolIdentityTracker.OnDeactivated();
			ContextualInputRouter.ResetLatches();
			HoverHighlighter.ClearAll();
			ManualLogSource modLogger = DismantleheimPlugin.ModLogger;
			if (modLogger != null)
			{
				modLogger.LogInfo((object)("Dismantleheim hard-reset via " + source));
			}
		}

		public void ToggleActivate(string source)
		{
			if (IsActive)
			{
				Deactivate(source);
				return;
			}
			OperationMode defaultMode = DismantleheimPlugin.GetDefaultMode();
			TryActivate(defaultMode, source, out var _);
		}

		public void SyncStateAfterSelectionChange()
		{
			RefreshContentsWarning();
			if (IsActive)
			{
				StateMachine.TryTransition(DismantleTransition.SelectionChanged, Queue.Count, out var _);
			}
		}

		public void BeginConfirmSnapshot()
		{
			_confirmSnapshot = new List<TargetIdentity>(Queue.Snapshot());
		}

		public void ClearConfirmSnapshot()
		{
			_confirmSnapshot = null;
		}

		public ISet<string> ExtraDeny()
		{
			return Eligibility.ParsePrefabList((DismantleheimPlugin.ExtraDenyPrefabs != null) ? DismantleheimPlugin.ExtraDenyPrefabs.Value : string.Empty);
		}

		public ISet<string> ExtraAllow()
		{
			return Eligibility.ParsePrefabList((DismantleheimPlugin.ExtraAllowPrefabs != null) ? DismantleheimPlugin.ExtraAllowPrefabs.Value : string.Empty);
		}

		public void RefreshContentsWarning()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			HasContentsLossWarning = false;
			if (ActiveMode != OperationMode.MassDelete || (DismantleheimPlugin.WarnWhenDeletingOccupiedContainers != null && !DismantleheimPlugin.WarnWhenDeletingOccupiedContainers.Value))
			{
				return;
			}
			foreach (TargetIdentity entry in Queue.Entries)
			{
				GameObject val = ExactObjectExecutor.ResolveInstance(entry);
				if ((Object)val != (Object)null && ContainerContentsInspector.HasStoredItems(val, out var _))
				{
					HasContentsLossWarning = true;
					break;
				}
			}
		}

		public void CommitDryOrReal()
		{
			DismantleState newState;
			try
			{
				if (!StateMachine.TryTransition(DismantleTransition.HoldComplete, Queue.Count, out newState))
				{
					return;
				}
				IReadOnlyList<TargetIdentity> readOnlyList;
				if (_confirmSnapshot == null)
				{
					readOnlyList = Queue.Snapshot();
				}
				else
				{
					IReadOnlyList<TargetIdentity> confirmSnapshot = _confirmSnapshot;
					readOnlyList = confirmSnapshot;
				}
				IReadOnlyList<TargetIdentity> queued = readOnlyList;
				List<TargetIdentity> missing;
				List<RemovalPlanEntry> list = PreflightBatchValidator.BuildPlan(ActiveMode, queued, AllowEnvWithFilter, ExtraDeny(), ExtraAllow(), out missing);
				StateMachine.TryTransition(DismantleTransition.ValidationDone, list.Count, out newState);
				List<RemovalResult> list2 = ExactObjectExecutor.Execute(ActiveMode, list);
				ExecutionResultReporter.LogAll(list2);
				string text = ExecutionResultReporter.Summarize(list2, ActiveMode);
				ManualLogSource modLogger = DismantleheimPlugin.ModLogger;
				if (modLogger != null)
				{
					modLogger.LogInfo((object)text);
				}
				if ((Object)(object)Console.instance != (Object)null)
				{
					Console.instance.Print("Dismantleheim " + text);
				}
				if (DismantleheimPlugin.DryRunOnly == null || !DismantleheimPlugin.DryRunOnly.Value)
				{
					foreach (RemovalResult item in list2)
					{
						if (item.Removed && item.Target != null && Queue.Contains(item.Target))
						{
							Queue.Toggle(item.Target);
						}
					}
				}
				RefreshContentsWarning();
			}
			catch (Exception ex)
			{
				ManualLogSource modLogger2 = DismantleheimPlugin.ModLogger;
				if (modLogger2 != null)
				{
					modLogger2.LogError((object)("Commit failed: " + ex));
				}
			}
			finally
			{
				ClearConfirmSnapshot();
				ConfirmHold.Cancel();
				StateMachine.TryTransition(DismantleTransition.ExecutionDone, Queue.Count, out newState);
				if (StateMachine.State == DismantleState.Executing || StateMachine.State == DismantleState.Validating)
				{
					StateMachine.ForceInactive();
					TryActivate(ActiveMode, "post-commit", out var _);
					SyncStateAfterSelectionChange();
				}
				else if (IsActive)
				{
					IgnorePieceChangeFrames = Math.Max(IgnorePieceChangeFrames, 45);
					ToolIdentityTracker.RefreshBaseline("post-commit");
					SyncStateAfterSelectionChange();
				}
				ManualLogSource modLogger3 = DismantleheimPlugin.ModLogger;
				if (modLogger3 != null)
				{
					modLogger3.LogInfo((object)("Dismantleheim post-commit state=" + StateMachine.State.ToString() + " active=" + IsActive + " queue=" + Queue.Count + " grace=" + IgnorePieceChangeFrames));
				}
			}
		}
	}
	internal static class DragBoxSelector
	{
		private const float CtrlReleaseGraceSeconds = 0.18f;

		private static bool _ctrlActive;

		private static bool _paintedAny;

		private static TargetIdentity _lastPainted;

		private static TargetIdentity _ctrlClickCandidate;

		private static float _ctrlReleasedAt = -999f;

		public static bool IsDragging => _ctrlActive;

		public static bool BlocksConfirm => _ctrlActive;

		public static bool ConsumeClickSuppression()
		{
			return false;
		}

		public static void Cancel()
		{
			_ctrlActive = false;
			_paintedAny = false;
			_lastPainted = null;
			_ctrlClickCandidate = null;
			_ctrlReleasedAt = -999f;
		}

		public static void Tick(DismantleSession session)
		{
			if (session == null || !session.IsActive)
			{
				Cancel();
				return;
			}
			bool flag = IsCtrlHeld();
			if (flag)
			{
				_ctrlReleasedAt = -999f;
				_ctrlActive = true;
			}
			else if (_ctrlActive)
			{
				if (_ctrlReleasedAt < 0f)
				{
					_ctrlReleasedAt = Time.unscaledTime;
				}
				if (Time.unscaledTime - _ctrlReleasedAt < 0.18f)
				{
					flag = true;
				}
				else
				{
					_ctrlActive = false;
					_lastPainted = null;
					_ctrlClickCandidate = null;
					_ctrlReleasedAt = -999f;
				}
			}
			if (_ctrlActive && flag)
			{
				TickCtrlPaint(session);
			}
		}

		public static void DrawGui()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (_ctrlActive)
			{
				GUI.Label(new Rect(16f, 16f, 420f, 22f), "Ctrl: mass-select (wave / drag aim)");
			}
		}

		private static void TickCtrlPaint(DismantleSession session)
		{
			bool down = MouseButtons.GetDown(0);
			bool up = MouseButtons.GetUp(0);
			if (down)
			{
				_paintedAny = false;
				_ctrlClickCandidate = ResolveAimTarget(session);
				if (_ctrlClickCandidate != null && session.Queue.Contains(_ctrlClickCandidate))
				{
					_lastPainted = _ctrlClickCandidate;
				}
				else
				{
					_lastPainted = null;
				}
			}
			PaintCurrentAim(session, remove: false);
			if (!up)
			{
				return;
			}
			if (!_paintedAny && _ctrlClickCandidate != null)
			{
				if (session.Queue.TryRemove(_ctrlClickCandidate))
				{
					session.SyncStateAfterSelectionChange();
					Log("Unqueued " + _ctrlClickCandidate.PrefabName + "  (" + session.Queue.Count + " selected)");
				}
				_lastPainted = _ctrlClickCandidate;
			}
			_ctrlClickCandidate = null;
		}

		private static TargetIdentity ResolveAimTarget(DismantleSession session)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if ((Object)localPlayer != (Object)null && TargetResolver.TryResolveAim(localPlayer, out var identity, out var _))
			{
				session.HoverTarget = identity;
				return identity;
			}
			return session.HoverTarget;
		}

		private static void PaintCurrentAim(DismantleSession session, bool remove)
		{
			TargetIdentity targetIdentity = ResolveAimTarget(session);
			if (targetIdentity == null)
			{
				_lastPainted = null;
			}
			else if (_lastPainted == null || !_lastPainted.Equals(targetIdentity))
			{
				if (ApplyPaint(session, targetIdentity, remove))
				{
					_paintedAny = true;
					_lastPainted = targetIdentity;
				}
				else if (!remove && session.Queue.Contains(targetIdentity))
				{
					_lastPainted = targetIdentity;
				}
				else if (remove && !session.Queue.Contains(targetIdentity))
				{
					_lastPainted = targetIdentity;
				}
			}
		}

		private static bool ApplyPaint(DismantleSession session, TargetIdentity target, bool remove)
		{
			if (target == null)
			{
				return false;
			}
			if (remove)
			{
				if (!session.Queue.TryRemove(target))
				{
					return false;
				}
				session.SyncStateAfterSelectionChange();
				Log("Unqueued " + target.PrefabName + "  (" + session.Queue.Count + " selected)");
				return true;
			}
			if (!Eligibility.IsEligible(target, session.ActiveMode, session.Sampler.ActiveFilter, session.AllowEnvWithFilter, session.ExtraDeny(), session.ExtraAllow(), out var _))
			{
				return false;
			}
			if (!session.Queue.TryAdd(target, session.MaximumTargets))
			{
				return false;
			}
			session.SyncStateAfterSelectionChange();
			Log("Queued " + target.PrefabName + "  (" + session.Queue.Count + " selected)");
			return true;
		}

		private static void Log(string msg)
		{
			ManualLogSource modLogger = DismantleheimPlugin.ModLogger;
			if (modLogger != null)
			{
				modLogger.LogInfo((object)("Dismantleheim " + msg));
			}
		}

		private static bool IsCtrlHeld()
		{
			if (!Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)305) && !Input.GetKey((KeyCode)310))
			{
				return Input.GetKey((KeyCode)309);
			}
			return true;
		}
	}
	internal static class MouseButtons
	{
		public static bool Get(int button)
		{
			try
			{
				if (ZInput.GetMouseButton(button))
				{
					return true;
				}
			}
			catch
			{
			}
			return Input.GetMouseButton(button);
		}

		public static bool GetDown(int button)
		{
			try
			{
				if (ZInput.GetMouseButtonDown(button))
				{
					return true;
				}
			}
			catch
			{
			}
			return Input.GetMouseButtonDown(button);
		}

		public static bool GetUp(int button)
		{
			try
			{
				if (ZInput.GetMouseButtonUp(button))
				{
					return true;
				}
			}
			catch
			{
			}
			return Input.GetMouseButtonUp(button);
		}
	}
	internal static class TargetResolver
	{
		private static readonly FieldInfo RemoveRayMaskField = AccessTools.Field(typeof(Player), "m_removeRayMask");

		private static readonly FieldInfo MaxPlaceDistanceField = AccessTools.Field(typeof(Player), "m_maxPlaceDistance");

		public static string CurrentWorldSessionKey()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return "local-offline";
			}
			long worldUID = ZNet.instance.GetWorldUID();
			long uID = ZNet.GetUID();
			return "uid:" + worldUID + "|peer:" + uID;
		}

		public static bool TryResolveHover(Player player, out TargetIdentity identity, out string rejectDetail)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			identity = null;
			rejectDetail = null;
			if ((Object)player == (Object)null)
			{
				rejectDetail = "no-player";
				return false;
			}
			GameObject val = null;
			if (((Character)player).InPlaceMode())
			{
				Piece hoveringPiece = player.GetHoveringPiece();
				if ((Object)hoveringPiece != (Object)null)
				{
					val = ((Component)hoveringPiece).gameObject;
				}
			}
			if ((Object)val == (Object)null)
			{
				val = ((Humanoid)player).GetHoverObject();
			}
			if ((Object)val != (Object)null && !Player.IsPlacementGhost(val) && TryResolveObject(val, out identity, out rejectDetail) && identity != null && identity.Kind != TargetKind.Unsupported)
			{
				return true;
			}
			return TryResolveAim(player, out identity, out rejectDetail);
		}

		public static bool TryResolveAim(Player player, out TargetIdentity identity, out string rejectDetail)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_00c6: 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)
			identity = null;
			rejectDetail = null;
			if ((Object)player == (Object)null)
			{
				rejectDetail = "no-player";
				return false;
			}
			if ((Object)GameCamera.instance == (Object)null)
			{
				rejectDetail = "no-camera";
				return false;
			}
			Transform transform = ((Component)GameCamera.instance).transform;
			int num = ((RemoveRayMaskField != null) ? ((int)RemoveRayMaskField.GetValue(player)) : 0);
			float num2 = ((MaxPlaceDistanceField != null) ? ((float)MaxPlaceDistanceField.GetValue(player)) : 5f);
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(transform.position, transform.forward, ref val, 50f, num))
			{
				rejectDetail = "aim-miss";
				return false;
			}
			if ((Object)((Character)player).m_eye != (Object)null)
			{
				float num3 = Vector3.Distance(((Character)player).m_eye.position, ((RaycastHit)(ref val)).point);
				if (num3 >= num2)
				{
					rejectDetail = "aim-range";
					return false;
				}
			}
			GameObject val2 = ResolveRootFromCollider(((RaycastHit)(ref val)).collider);
			if ((Object)val2 == (Object)null)
			{
				rejectDetail = "aim-no-target";
				return false;
			}
			if (Player.IsPlacementGhost(val2))
			{
				rejectDetail = "placement-ghost";
				return false;
			}
			return TryResolveObject(val2, out identity, out rejectDetail);
		}

		private static GameObject ResolveRootFromCollider(Collider col)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			if ((Object)col == (Object)null)
			{
				return null;
			}
			ZNetView componentInParent = ((Component)col).GetComponentInParent<ZNetView>();
			if ((Object)componentInParent != (Object)null && componentInParent.IsValid())
			{
				return ((Component)componentInParent).gameObject;
			}
			Piece componentInParent2 = ((Component)col).GetComponentInParent<Piece>();
			if ((Object)componentInParent2 != (Object)null)
			{
				return ((Component)componentInParent2).gameObject;
			}
			TreeBase componentInParent3 = ((Component)col).GetComponentInParent<TreeBase>();
			if ((Object)componentInParent3 != (Object)null)
			{
				return ((Component)componentInParent3).gameObject;
			}
			TreeLog componentInParent4 = ((Component)col).GetComponentInParent<TreeLog>();
			if ((Object)componentInParent4 != (Object)null)
			{
				return ((Component)componentInParent4).gameObject;
			}
			MineRock componentInParent5 = ((Component)col).GetComponentInParent<MineRock>();
			if ((Object)componentInParent5 != (Object)null)
			{
				return ((Component)componentInParent5).gameObject;
			}
			MineRock5 componentInParent6 = ((Component)col).GetComponentInParent<MineRock5>();
			if ((Object)componentInParent6 != (Object)null)
			{
				return ((Component)componentInParent6).gameObject;
			}
			return null;
		}

		public static bool TryResolveObject(GameObject go, out TargetIdentity identity, out string rejectDetail)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_011a: 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)
			identity = null;
			rejectDetail = null;
			if ((Object)go == (Object)null)
			{
				rejectDetail = "null";
				return false;
			}
			ZNetView componentInParent = go.GetComponentInParent<ZNetView>();
			if ((Object)componentInParent == (Object)null || !componentInParent.IsValid())
			{
				rejectDetail = "no-znetview";
				return false;
			}
			GameObject gameObject = ((Component)componentInParent).gameObject;
			Piece val = gameObject.GetComponent<Piece>();
			if ((Object)val == (Object)null)
			{
				val = gameObject.GetComponentInChildren<Piece>();
			}
			bool flag = (Object)val != (Object)null;
			bool canBeRemoved = flag && val.m_canBeRemoved;
			bool flag2 = IsEnvironmentRoot(gameObject);
			WearNTear val2 = gameObject.GetComponent<WearNTear>();
			if ((Object)val2 == (Object)null)
			{
				val2 = gameObject.GetComponentInChildren<WearNTear>();
			}
			bool hasScopePreview = (Object)val2 != (Object)null || flag2;
			TargetKind kind = Eligibility.Classify(flag, canBeRemoved, flag2, hasScopePreview);
			if (!flag && !flag2)
			{
				kind = TargetKind.Unsupported;
			}
			string text = NormalizePrefabName(((Object)gameObject).name ?? string.Empty);
			if (!flag2 && LooksLikeEnvironmentPrefab(text))
			{
				flag2 = true;
				hasScopePreview = true;
				kind = TargetKind.Environment;
			}
			string worldSessionKey = CurrentWorldSessionKey();
			long userId = 0L;
			uint objectId = 0u;
			ZDO zDO = componentInParent.GetZDO();
			if (zDO != null)
			{
				ZDOID uid = zDO.m_uid;
				userId = ((ZDOID)(ref uid)).UserID;
				objectId = ((ZDOID)(ref uid)).ID;
			}
			identity = new TargetIdentity(userId, objectId, worldSessionKey, text, flag, canBeRemoved, flag2, kind, hasScopePreview);
			return true;
		}

		public static bool TryRevalidate(TargetIdentity queued, out TargetIdentity live, out string detail)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			live = null;
			detail = null;
			if (queued == null)
			{
				detail = "null";
				return false;
			}
			if (!string.Equals(queued.WorldSessionKey, CurrentWorldSessionKey(), StringComparison.Ordinal))
			{
				detail = "session-mismatch";
				return false;
			}
			GameObject val = ExactObjectExecutor.ResolveInstance(queued);
			if ((Object)val == (Object)null)
			{
				detail = "missing-instance";
				return false;
			}
			if (!TryResolveObject(val, out live, out detail))
			{
				return false;
			}
			if (!string.Equals(live.PrefabName, queued.PrefabName, StringComparison.OrdinalIgnoreCase))
			{
				detail = "prefab-mismatch";
				live = null;
				return false;
			}
			if (live.Kind != queued.Kind)
			{
				detail = "kind-mismatch";
				live = null;
				return false;
			}
			if (!live.HasScopePreview && live.Kind != TargetKind.Environment)
			{
				detail = "no-scope-preview";
				live = null;
				return false;
			}
			return true;
		}

		public static bool IsEnvironmentRoot(GameObject root)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			if ((Object)root == (Object)null)
			{
				return false;
			}
			if ((Object)root.GetComponentInChildren<TreeBase>(true) != (Object)null)
			{
				return true;
			}
			if ((Object)root.GetComponentInChildren<TreeLog>(true) != (Object)null)
			{
				return true;
			}
			if ((Object)root.GetComponentInChildren<MineRock>(true) != (Object)null)
			{
				return true;
			}
			if ((Object)root.GetComponentInChildren<MineRock5>(true) != (Object)null)
			{
				return true;
			}
			if ((Object)root.GetComponentInChildren<Destructible>(true) != (Object)null)
			{
				return true;
			}
			return LooksLikeEnvironmentPrefab(NormalizePrefabName(((Object)root).name ?? string.Empty));
		}

		public static bool LooksLikeEnvironmentPrefab(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return false;
			}
			if (prefab.StartsWith("prop_", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (prefab.StartsWith("Rock_", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("rock_", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("MineRock", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("stone_environment", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("Cliff", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return false;
		}

		public static string StripClone(string prefab)
		{
			return NormalizePrefabName(prefab);
		}

		public static string NormalizePrefabName(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return string.Empty;
			}
			string text = prefab.Trim();
			if (text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd();
			}
			int num = text.LastIndexOf('(');
			int num2 = text.LastIndexOf(')');
			if (num > 0 && num2 == text.Length - 1 && num2 > num + 1)
			{
				bool flag = true;
				for (int i = num + 1; i < num2; i++)
				{
					if (!char.IsDigit(text[i]))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					text = text.Substring(0, num).TrimEnd();
				}
			}
			return text;
		}
	}
}
namespace Dismantleheim.Removal
{
	internal static class AuthorizedExactDeletionAdapter
	{
		public static bool TryDelete(TargetIdentity target, out string error)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_002b: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			error = string.Empty;
			GameObject val = ExactObjectExecutor.ResolveInstance(target);
			if ((Object)val == (Object)null)
			{
				error = "instance missing";
				return false;
			}
			Vector3 position = val.transform.position;
			if (!PrivateArea.CheckAccess(position, 0f, true, false))
			{
				error = "ward denied";
				return false;
			}
			if ((Object)val.GetComponent<TeleportWorld>() != (Object)null)
			{
				error = "portal unprotected lifecycle";
				return false;
			}
			if ((Object)val.GetComponent<PrivateArea>() != (Object)null)
			{
				error = "ward object";
				return false;
			}
			Piece component = val.GetComponent<Piece>();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)component != (Object)null)
			{
				if (!component.m_canBeRemoved)
				{
					error = "m_canBeRemoved=false";
					return false;
				}
			}
			else if (target.Kind != TargetKind.Environment && target.Kind != TargetK