Decompiled source of ClearBattlefield v0.3.0

plugins/ClearBattlefield.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ClearBattlefield.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UIElements;

[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("ClearBattlefield")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0+7308a47e4a8b77959fecfffea2431d30a14545e7")]
[assembly: AssemblyProduct("ClearBattlefield")]
[assembly: AssemblyTitle("ClearBattlefield")]
[assembly: AssemblyVersion("0.3.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 ClearBattlefield
{
	internal static class BattlefieldClearer
	{
		public static readonly DropTracker Tracker = new DropTracker();

		private static readonly List<uint> EmptyIds = new List<uint>();

		public static double Now => Time.realtimeSinceStartupAsDouble;

		public static bool Available
		{
			get
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Invalid comparison between Unknown and I4
				if (NetworkServer.active && (Object)(object)GameManager.Instance != (Object)null)
				{
					return (int)GameManager.Instance.SceneType == 1;
				}
				return false;
			}
		}

		private static double MinAge => Math.Max(0f, Plugin.MinDropAgeSeconds.Value);

		public static void Reset(string reason)
		{
			int count = Tracker.Count;
			Tracker.Reset();
			if (count > 0)
			{
				Plugin.Log.LogInfo((object)$"{reason}; forgot {count} tracked drop(s)");
			}
		}

		public static (int drops, int scrap) CountClearable(bool includeDrops, bool includeScrap)
		{
			if (!NetworkServer.active)
			{
				return (drops: 0, scrap: 0);
			}
			return (drops: includeDrops ? Tracker.SelectClearable(Now, MinAge, StateOf).Count : 0, scrap: ScrapOnGround(includeScrap).Count);
		}

		public static int Clear(bool includeDrops, bool includeScrap)
		{
			if (!NetworkServer.active)
			{
				return 0;
			}
			List<uint> list = ScrapOnGround(includeScrap);
			int num = 0;
			foreach (uint item in includeDrops ? Tracker.SelectClearable(Now, MinAge, StateOf) : EmptyIds)
			{
				if (Destroy(item))
				{
					num++;
				}
				Tracker.Untrack(item);
			}
			int num2 = 0;
			foreach (uint item2 in list)
			{
				if (Destroy(item2))
				{
					num2++;
				}
			}
			Plugin.Log.LogInfo((object)$"Cleared {num} enemy drop(s) and {num2} scrap; {Tracker.Count} drop(s) still tracked");
			Notify(ClearText.Result(num, num2));
			return num + num2;
		}

		private static bool Destroy(uint netId)
		{
			if (!NetworkServer.spawned.TryGetValue(netId, out var value) || (Object)(object)value == (Object)null)
			{
				return false;
			}
			try
			{
				NetworkServer.Destroy(((Component)value).gameObject);
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not remove item {netId}: {arg}");
				return false;
			}
		}

		private static List<uint> ScrapOnGround(bool include)
		{
			List<uint> list = new List<uint>();
			if (!include)
			{
				return list;
			}
			ScrapPickableItem val = default(ScrapPickableItem);
			foreach (NetworkIdentity value in NetworkServer.spawned.Values)
			{
				if (!((Object)(object)value == (Object)null) && ((Component)value).TryGetComponent<ScrapPickableItem>(ref val) && !((Object)(object)val == (Object)null) && ((PickableItem)val).NetworkSyncPlayerID == 0L && !Tracker.IsTracked(value.netId))
				{
					list.Add(value.netId);
				}
			}
			return list;
		}

		private static DropState StateOf(uint netId)
		{
			PickableItem val = default(PickableItem);
			if (!NetworkServer.spawned.TryGetValue(netId, out var value) || (Object)(object)value == (Object)null || !((Component)value).TryGetComponent<PickableItem>(ref val) || (Object)(object)val == (Object)null)
			{
				return DropState.Gone;
			}
			if (val.NetworkSyncPlayerID == 0L)
			{
				return DropState.OnGround;
			}
			return DropState.Busy;
		}

		private static void Notify(string message)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			try
			{
				NotificationHolder instance = NotificationHolder.Instance;
				if (instance != null)
				{
					instance.CreateNotification((INotification)new BasicNotification
					{
						Title = "Clear Battlefield",
						Description = message,
						DisplayTime = 4f
					});
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not show the clear notification: " + ex.Message));
			}
		}
	}
	public static class ClearText
	{
		public static string Items(int count)
		{
			if (count != 1)
			{
				return $"{count} enemy drops";
			}
			return "1 enemy drop";
		}

		public static string Scrap(int count)
		{
			if (count != 1)
			{
				return $"{count} pieces of scrap";
			}
			return "1 piece of scrap";
		}

		public static string Describe(int drops, int scrap)
		{
			if (scrap == 0)
			{
				return Items(drops);
			}
			if (drops != 0)
			{
				return Items(drops) + " and " + Scrap(scrap);
			}
			return Scrap(scrap);
		}

		public static string Confirmation(int drops, int scrap)
		{
			if (drops + scrap != 0)
			{
				return "Remove " + Describe(drops, scrap) + "? Everything else on the ground stays.";
			}
			return "There is nothing on the ground to clear.";
		}

		public static string Result(int drops, int scrap)
		{
			if (drops + scrap != 0)
			{
				return "Cleared " + Describe(drops, scrap);
			}
			return "Nothing to clear";
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public string DispName;

		public int? Order;
	}
	public enum DropState
	{
		Gone,
		Busy,
		OnGround
	}
	public sealed class DropTracker
	{
		private readonly Dictionary<uint, double> _spawnTimes = new Dictionary<uint, double>();

		public int Count => _spawnTimes.Count;

		public bool IsTracked(uint netId)
		{
			return _spawnTimes.ContainsKey(netId);
		}

		public void Track(uint netId, double spawnTime)
		{
			if (netId != 0)
			{
				_spawnTimes[netId] = spawnTime;
			}
		}

		public bool Untrack(uint netId)
		{
			return _spawnTimes.Remove(netId);
		}

		public bool OnMerge(uint survivor, uint absorbed)
		{
			if (IsTracked(survivor) && IsTracked(absorbed))
			{
				return true;
			}
			Untrack(survivor);
			Untrack(absorbed);
			return false;
		}

		public void Reset()
		{
			_spawnTimes.Clear();
		}

		public List<uint> SelectClearable(double now, double minAgeSeconds, Func<uint, DropState> stateOf)
		{
			List<uint> list = new List<uint>();
			List<uint> list2 = new List<uint>();
			foreach (KeyValuePair<uint, double> spawnTime in _spawnTimes)
			{
				switch (stateOf(spawnTime.Key))
				{
				case DropState.Gone:
					list2.Add(spawnTime.Key);
					break;
				case DropState.OnGround:
					if (now - spawnTime.Value >= minAgeSeconds)
					{
						list.Add(spawnTime.Key);
					}
					break;
				}
			}
			foreach (uint item in list2)
			{
				_spawnTimes.Remove(item);
			}
			list.Sort();
			return list;
		}
	}
	internal static class Hotkey
	{
		private static bool? _legacyAvailable;

		private static readonly Dictionary<KeyCode, Key> Renamed = new Dictionary<KeyCode, Key>
		{
			[(KeyCode)13] = (Key)2,
			[(KeyCode)271] = (Key)77,
			[(KeyCode)306] = (Key)55,
			[(KeyCode)305] = (Key)56,
			[(KeyCode)310] = (Key)57,
			[(KeyCode)309] = (Key)58,
			[(KeyCode)96] = (Key)4,
			[(KeyCode)270] = (Key)80,
			[(KeyCode)269] = (Key)81,
			[(KeyCode)268] = (Key)79,
			[(KeyCode)267] = (Key)78,
			[(KeyCode)266] = (Key)82
		};

		private static bool LegacyAvailable
		{
			get
			{
				if (!_legacyAvailable.HasValue)
				{
					try
					{
						Input.GetKey((KeyCode)0);
						_legacyAvailable = true;
					}
					catch (InvalidOperationException)
					{
						_legacyAvailable = false;
					}
					Plugin.Log.LogInfo((object)(_legacyAvailable.Value ? "Reading hotkeys through the legacy Input manager" : "Legacy Input manager is disabled; reading hotkeys through the Input System package"));
				}
				return _legacyAvailable.Value;
			}
		}

		public static bool WasPressed(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0)
			{
				return false;
			}
			if (LegacyAvailable)
			{
				return ((KeyboardShortcut)(ref shortcut)).IsDown();
			}
			Keyboard current = Keyboard.current;
			if (current == null || !TryGetKey(((KeyboardShortcut)(ref shortcut)).MainKey, out var key) || !((ButtonControl)current[key]).wasPressedThisFrame)
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!TryGetKey(modifier, out var key2) || !((ButtonControl)current[key2]).isPressed)
				{
					return false;
				}
			}
			return true;
		}

		private unsafe static bool TryGetKey(KeyCode code, out Key key)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (Renamed.TryGetValue(code, out key))
			{
				return true;
			}
			string text = ((object)(*(KeyCode*)(&code))/*cast due to .constrained prefix*/).ToString();
			if (text.StartsWith("Alpha"))
			{
				text = "Digit" + text.Substring("Alpha".Length);
			}
			else if (text.StartsWith("Keypad"))
			{
				text = "Numpad" + text.Substring("Keypad".Length);
			}
			if (Enum.TryParse<Key>(text, ignoreCase: true, out key))
			{
				return (int)key != 0;
			}
			return false;
		}
	}
	[BepInPlugin("com.darkharasho.stonewards.clearbattlefield", "ClearBattlefield", "0.3.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.darkharasho.stonewards.clearbattlefield";

		public const string PluginName = "ClearBattlefield";

		public const string PluginVersion = "0.3.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> RequireConfirmation;

		internal static ConfigEntry<KeyboardShortcut> ClearKey;

		internal static ConfigEntry<KeyboardShortcut> ClearDropsKey;

		internal static ConfigEntry<KeyboardShortcut> ClearScrapKey;

		internal static ConfigEntry<float> MinDropAgeSeconds;

		internal static ConfigEntry<bool> ClearScrap;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			RequireConfirmation = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireConfirmation", true, new ConfigDescription("Ask before removing anything. Applies to the pause menu button and the keybind.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Ask for confirmation",
					Order = 20
				}
			}));
			MinDropAgeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MinDropAgeSeconds", 0f, new ConfigDescription("Enemy drops more recent than this many seconds are left on the ground. 0 clears every enemy drop. Scrap ignores this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Minimum drop age (seconds)",
					Order = 10
				}
			}));
			ClearScrap = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ClearScrap", false, new ConfigDescription("Also remove scrap (such as scrap wood from digging) that is still on the ground. It could have come from any player's digging.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Also clear scrap",
					Order = 5
				}
			}));
			ClearKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ClearKey", KeyboardShortcut.Empty, new ConfigDescription("Key that clears the battlefield: enemy drops, plus scrap if \"Also clear scrap\" is on. With confirmation on, it opens the pause menu on the confirmation. Host only; none by default.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Clear battlefield",
					Order = 30
				}
			}));
			ClearDropsKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ClearDropsKey", KeyboardShortcut.Empty, new ConfigDescription("Key that clears enemy drops only, never scrap. Host only; none by default.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Clear enemy drops",
					Order = 20
				}
			}));
			ClearScrapKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ClearScrapKey", KeyboardShortcut.Empty, new ConfigDescription("Key that clears scrap only, such as scrap wood from digging. It works whether or not \"Also clear scrap\" is on. Host only; none by default.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Clear scrap",
					Order = 10
				}
			}));
			_harmony = new Harmony("com.darkharasho.stonewards.clearbattlefield");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"ClearBattlefield 0.3.0 loaded. Only the host needs it.");
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (Hotkey.WasPressed(ClearKey.Value))
			{
				PauseMenuButton.OnHotkey(drops: true, ClearScrap.Value);
			}
			else if (Hotkey.WasPressed(ClearDropsKey.Value))
			{
				PauseMenuButton.OnHotkey(drops: true, scrap: false);
			}
			else if (Hotkey.WasPressed(ClearScrapKey.Value))
			{
				PauseMenuButton.OnHotkey(drops: false, scrap: true);
			}
			PauseMenuButton.Update();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace ClearBattlefield.Patches
{
	[HarmonyPatch(typeof(ItemManager), "ServerInstantiateEnemyDrop")]
	internal static class TrackEnemyDropPatch
	{
		private static void Postfix(PickableItem __result)
		{
			if (!((Object)(object)__result == (Object)null) && NetworkServer.active)
			{
				BattlefieldClearer.Tracker.Track(((NetworkBehaviour)__result).netId, BattlefieldClearer.Now);
			}
		}
	}
	[HarmonyPatch(typeof(PickableItem), "OnDestroy")]
	internal static class UntrackDestroyedPatch
	{
		private static void Postfix(PickableItem __instance)
		{
			if (((NetworkBehaviour)__instance).netId != 0)
			{
				BattlefieldClearer.Tracker.Untrack(((NetworkBehaviour)__instance).netId);
			}
		}
	}
	[HarmonyPatch(typeof(PickableItem), "Merge")]
	internal static class MergePatch
	{
		private static readonly FieldRef<PickableItem, PickableItem> MergeTarget = AccessTools.FieldRefAccess<PickableItem, PickableItem>("mergeTarget");

		private static void Postfix(PickableItem __instance, PickableItem _Other)
		{
			if (!((Object)(object)_Other == (Object)null) && !((Object)(object)MergeTarget.Invoke(_Other) != (Object)(object)__instance))
			{
				BattlefieldClearer.Tracker.OnMerge(((NetworkBehaviour)__instance).netId, ((NetworkBehaviour)_Other).netId);
			}
		}
	}
	internal static class ResetPatches
	{
		[HarmonyPatch(typeof(MetaProgressManager), "StartRun")]
		private static class StartRunPatch
		{
			private static void Prefix()
			{
				BattlefieldClearer.Reset("Run started");
			}
		}

		[HarmonyPatch(typeof(MetaProgressManager), "EndRun")]
		private static class EndRunPatch
		{
			private static void Postfix()
			{
				BattlefieldClearer.Reset("Run ended");
			}
		}

		[HarmonyPatch(typeof(NetworkServer), "Shutdown")]
		private static class ServerShutdownPatch
		{
			private static void Prefix()
			{
				BattlefieldClearer.Reset("Server stopped");
			}
		}
	}
	internal static class GameUi
	{
		public static Button CloneButton(Button source, string text)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			Button val = new Button
			{
				name = "ClearBattlefieldButton"
			};
			foreach (string @class in ((VisualElement)source).GetClasses())
			{
				((VisualElement)val).AddToClassList(@class);
			}
			CopyInlineStyle(((VisualElement)source).style, ((VisualElement)val).style);
			Label val2 = UQueryExtensions.Q<Label>((VisualElement)(object)source, (string)null, (string)null);
			if (string.IsNullOrEmpty(((TextElement)source).text) && val2 != null)
			{
				Label val3 = new Label(text)
				{
					pickingMode = (PickingMode)1
				};
				foreach (string class2 in ((VisualElement)val2).GetClasses())
				{
					((VisualElement)val3).AddToClassList(class2);
				}
				CopyInlineStyle(((VisualElement)val2).style, ((VisualElement)val3).style);
				((VisualElement)val).Add((VisualElement)(object)val3);
			}
			else
			{
				((TextElement)val).text = text;
			}
			return val;
		}

		private static void CopyInlineStyle(IStyle from, IStyle to)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			to.backgroundColor = from.backgroundColor;
			to.backgroundImage = from.backgroundImage;
			to.unityBackgroundImageTintColor = from.unityBackgroundImageTintColor;
			to.unitySliceLeft = from.unitySliceLeft;
			to.unitySliceRight = from.unitySliceRight;
			to.unitySliceTop = from.unitySliceTop;
			to.unitySliceBottom = from.unitySliceBottom;
			to.unitySliceScale = from.unitySliceScale;
			to.borderTopWidth = from.borderTopWidth;
			to.borderBottomWidth = from.borderBottomWidth;
			to.borderLeftWidth = from.borderLeftWidth;
			to.borderRightWidth = from.borderRightWidth;
			to.borderTopColor = from.borderTopColor;
			to.borderBottomColor = from.borderBottomColor;
			to.borderLeftColor = from.borderLeftColor;
			to.borderRightColor = from.borderRightColor;
			to.borderTopLeftRadius = from.borderTopLeftRadius;
			to.borderTopRightRadius = from.borderTopRightRadius;
			to.borderBottomLeftRadius = from.borderBottomLeftRadius;
			to.borderBottomRightRadius = from.borderBottomRightRadius;
			to.color = from.color;
			to.fontSize = from.fontSize;
			to.unityFont = from.unityFont;
			to.unityFontDefinition = from.unityFontDefinition;
			to.unityFontStyleAndWeight = from.unityFontStyleAndWeight;
			to.unityTextAlign = from.unityTextAlign;
			to.unityTextOutlineColor = from.unityTextOutlineColor;
			to.unityTextOutlineWidth = from.unityTextOutlineWidth;
			to.textShadow = from.textShadow;
			to.letterSpacing = from.letterSpacing;
			to.paddingTop = from.paddingTop;
			to.paddingBottom = from.paddingBottom;
			to.paddingLeft = from.paddingLeft;
			to.paddingRight = from.paddingRight;
		}
	}
	internal static class PauseMenuButton
	{
		private static readonly FieldRef<UIPauseMenu, Button> PlayButton = AccessTools.FieldRefAccess<UIPauseMenu, Button>("playButton");

		private static readonly FieldRef<UIPauseMenu, Button> SettingsButton = AccessTools.FieldRefAccess<UIPauseMenu, Button>("settingsButton");

		private static readonly FieldRef<UIPauseMenu, UIConfirmationPopup> ConfirmationPopup = AccessTools.FieldRefAccess<UIPauseMenu, UIConfirmationPopup>("confirmationPopup");

		private static readonly FieldRef<BaseMenu, List<VisualElement>> NavigableElements = AccessTools.FieldRefAccess<BaseMenu, List<VisualElement>>("navigableElements");

		private static readonly Action<BaseMenu, bool> SetNavigable = AccessTools.MethodDelegate<Action<BaseMenu, bool>>(AccessTools.Method(typeof(BaseMenu), "SetNavigable", (Type[])null, (Type[])null), (object)null, true);

		private static UIPauseMenu _menu;

		private static Button _button;

		private static bool _pendingDrops;

		private static bool _pendingScrap;

		public static void Attach(UIPauseMenu menu)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			Button val = SettingsButton.Invoke(menu);
			UIDocument component = ((Component)menu).GetComponent<UIDocument>();
			VisualElement val2 = ((component != null) ? component.rootVisualElement : null);
			if (val == null || val2 == null || ConfirmationPopup.Invoke(menu) == null)
			{
				Plugin.Log.LogWarning((object)"Pause menu layout not recognised; the Clear Battlefield button was not added");
				return;
			}
			Button button = _button;
			if (button != null)
			{
				((VisualElement)button).RemoveFromHierarchy();
			}
			_menu = menu;
			_button = GameUi.CloneButton(val, "Clear Battlefield");
			((VisualElement)_button).style.position = StyleEnum<Position>.op_Implicit((Position)1);
			((VisualElement)_button).style.top = StyleLength.op_Implicit(32f);
			((VisualElement)_button).style.right = StyleLength.op_Implicit(32f);
			((VisualElement)_button).style.width = StyleLength.op_Implicit((StyleKeyword)2);
			((VisualElement)_button).style.display = StyleEnum<DisplayStyle>.op_Implicit((DisplayStyle)1);
			_button.clicked += OnClick;
			val2.Add((VisualElement)(object)_button);
			NavigableElements.Invoke((BaseMenu)(object)menu).Add((VisualElement)(object)_button);
		}

		public static void Update()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if (_button != null)
			{
				Button val = (((Object)(object)_menu != (Object)null) ? PlayButton.Invoke(_menu) : null);
				DisplayStyle val2 = (DisplayStyle)((!((Object)(object)_menu != (Object)null) || !_menu.IsPauseMenuOpen || val == null || !((Focusable)val).focusable || !BattlefieldClearer.Available) ? 1 : 0);
				if (((VisualElement)_button).style.display != StyleEnum<DisplayStyle>.op_Implicit(val2))
				{
					((VisualElement)_button).style.display = StyleEnum<DisplayStyle>.op_Implicit(val2);
				}
			}
		}

		public static void OnHotkey(bool drops, bool scrap)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Invalid comparison between Unknown and I4
			if (!BattlefieldClearer.Available)
			{
				return;
			}
			if (!Plugin.RequireConfirmation.Value)
			{
				BattlefieldClearer.Clear(drops, scrap);
				return;
			}
			UIPauseMenu instance = UIPauseMenu.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance != (Object)(object)_menu) && !((Object)(object)InputManager.Instance == (Object)null))
			{
				InputState currentInputState = InputManager.Instance.CurrentInputState;
				if ((int)currentInputState == 2)
				{
					instance.OpenMenu(true);
				}
				else if ((int)currentInputState != 6 || !((Focusable)PlayButton.Invoke(instance)).focusable)
				{
					return;
				}
				ShowConfirmation(drops, scrap);
			}
		}

		private static void OnClick()
		{
			if (BattlefieldClearer.Available)
			{
				AudioManager instance = AudioManager.Instance;
				if (instance != null)
				{
					instance.PlayUIButton();
				}
				if (Plugin.RequireConfirmation.Value)
				{
					ShowConfirmation(includeDrops: true, Plugin.ClearScrap.Value);
				}
				else
				{
					BattlefieldClearer.Clear(includeDrops: true, Plugin.ClearScrap.Value);
				}
			}
		}

		private static void ShowConfirmation(bool includeDrops, bool includeScrap)
		{
			UIConfirmationPopup popup = ConfirmationPopup.Invoke(_menu);
			(int drops, int scrap) tuple = BattlefieldClearer.CountClearable(includeDrops, includeScrap);
			int item = tuple.drops;
			int item2 = tuple.scrap;
			_pendingDrops = includeDrops;
			_pendingScrap = includeScrap;
			SetNavigable((BaseMenu)(object)_menu, arg2: false);
			if (item + item2 == 0)
			{
				popup.Show(ClearText.Confirmation(0, 0), "OK", (VisualElement)(object)_button);
				VisualElement root = ((BaseMenu)popup).Root;
				if (root != null)
				{
					root.schedule.Execute((Action)RestoreWhenClosed).Every(100L).Until((Func<bool>)(() => !((BaseMenu)popup).IsOpen));
				}
			}
			else
			{
				popup.Show(ClearText.Confirmation(item, item2), "Clear", "Cancel", (VisualElement)(object)_button, (Action)OnConfirm, (Action)OnCancel);
			}
		}

		private static void RestoreWhenClosed()
		{
			UIConfirmationPopup val = (((Object)(object)_menu != (Object)null) ? ConfirmationPopup.Invoke(_menu) : null);
			if (val != null && !((BaseMenu)val).IsOpen && _menu.IsPauseMenuOpen)
			{
				SetNavigable((BaseMenu)(object)_menu, arg2: true);
			}
		}

		private static void OnConfirm()
		{
			ConfirmationPopup.Invoke(_menu).Hide();
			SetNavigable((BaseMenu)(object)_menu, arg2: true);
			BattlefieldClearer.Clear(_pendingDrops, _pendingScrap);
		}

		private static void OnCancel()
		{
			AudioManager instance = AudioManager.Instance;
			if (instance != null)
			{
				instance.PlayUIButton();
			}
			SetNavigable((BaseMenu)(object)_menu, arg2: true);
		}
	}
	[HarmonyPatch(typeof(UIPauseMenu), "Init")]
	internal static class PauseMenuInitPatch
	{
		private static void Postfix(UIPauseMenu __instance)
		{
			try
			{
				PauseMenuButton.Attach(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not add the Clear Battlefield button to the pause menu: {arg}");
			}
		}
	}
}