Decompiled source of ValuableTracker v1.0.3

BepInEx\plugins\MechGaming-ValuableTracker\ValuableTracker.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
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("MechGaming")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ValuableTracker")]
[assembly: AssemblyTitle("ValuableTracker")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 MechGaming.REPO.ValuableTracker
{
	internal static class HotkeyInput
	{
		private const int KeyDownMask = 32768;

		private const float TextInputScanInterval = 0.15f;

		private static readonly Dictionary<KeyCode, bool> PreviousStates = new Dictionary<KeyCode, bool>();

		private static readonly Type? UnityInputFieldType = Type.GetType("UnityEngine.UI.InputField, UnityEngine.UI");

		private static readonly Type? TmpInputFieldType = Type.GetType("TMPro.TMP_InputField, Unity.TextMeshPro");

		private static int _currentProcessId;

		private static float _nextTextInputScanTime;

		private static bool _cachedNoTextInputActive = true;

		private static int CurrentProcessId
		{
			get
			{
				if (_currentProcessId == 0)
				{
					_currentProcessId = Process.GetCurrentProcess().Id;
				}
				return _currentProcessId;
			}
		}

		internal static bool GetKeyDown(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			bool flag = GetUnityKeyDown(key) || GetWindowsKey(key);
			bool value;
			bool flag2 = PreviousStates.TryGetValue(key, out value) && value;
			PreviousStates[key] = flag;
			if (flag)
			{
				return !flag2;
			}
			return false;
		}

		internal static bool NoTextInputActive(Func<bool> gameCheck)
		{
			try
			{
				if (gameCheck())
				{
					_cachedNoTextInputActive = true;
					return true;
				}
			}
			catch
			{
			}
			if (Time.unscaledTime < _nextTextInputScanTime)
			{
				return _cachedNoTextInputActive;
			}
			_nextTextInputScanTime = Time.unscaledTime + 0.15f;
			_cachedNoTextInputActive = !AnyFocusedTextInput();
			return _cachedNoTextInputActive;
		}

		private static bool GetUnityKeyDown(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return Input.GetKeyDown(key);
			}
			catch
			{
				return false;
			}
		}

		private static bool GetWindowsKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num = ToVirtualKey(key);
			if (num != 0 && IsForegroundProcess())
			{
				return IsVirtualKeyDown(num);
			}
			return false;
		}

		private static bool IsVirtualKeyDown(int virtualKey)
		{
			try
			{
				return (GetAsyncKeyState(virtualKey) & 0x8000) != 0;
			}
			catch
			{
				return false;
			}
		}

		private static bool IsForegroundProcess()
		{
			try
			{
				IntPtr foregroundWindow = GetForegroundWindow();
				if (foregroundWindow == IntPtr.Zero)
				{
					return false;
				}
				GetWindowThreadProcessId(foregroundWindow, out var processId);
				return processId == CurrentProcessId;
			}
			catch
			{
				return false;
			}
		}

		private static int ToVirtualKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected I4, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			//IL_0036: 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_003f: Expected I4, but got Unknown
			//IL_008c: 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_00bc: Expected I4, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_00bc: 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_00e0: Expected I4, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Invalid comparison between Unknown and I4
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_00e0: 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_00f8: Expected I4, but got Unknown
			if ((int)key >= 97 && (int)key <= 122)
			{
				return 65 + (key - 97);
			}
			if ((int)key >= 48 && (int)key <= 57)
			{
				return 48 + (key - 48);
			}
			if ((int)key >= 282 && (int)key <= 678)
			{
				return 112 + (key - 282);
			}
			if ((int)key <= 27)
			{
				if ((int)key <= 9)
				{
					if ((int)key == 8)
					{
						return 8;
					}
					if ((int)key == 9)
					{
						return 9;
					}
				}
				else
				{
					if ((int)key == 13)
					{
						return 13;
					}
					if ((int)key == 27)
					{
						return 27;
					}
				}
			}
			else if ((int)key <= 127)
			{
				if ((int)key == 32)
				{
					return 32;
				}
				if ((int)key == 127)
				{
					return 46;
				}
			}
			else
			{
				switch (key - 273)
				{
				case 7:
					return 33;
				case 8:
					return 34;
				case 6:
					return 35;
				case 5:
					return 36;
				case 3:
					return 37;
				case 0:
					return 38;
				case 2:
					return 39;
				case 1:
					return 40;
				case 4:
					return 45;
				}
				switch (key - 303)
				{
				case 1:
					return 160;
				case 0:
					return 161;
				case 3:
					return 162;
				case 2:
					return 163;
				case 5:
					return 164;
				case 4:
					return 165;
				}
				switch (key - 323)
				{
				case 0:
					return 1;
				case 1:
					return 2;
				case 2:
					return 4;
				}
			}
			return 0;
		}

		private static bool AnyFocusedTextInput()
		{
			if (!TypeHasFocusedInput(UnityInputFieldType))
			{
				return TypeHasFocusedInput(TmpInputFieldType);
			}
			return true;
		}

		private static bool TypeHasFocusedInput(Type? inputType)
		{
			if (inputType == null)
			{
				return false;
			}
			try
			{
				Object[] array = Resources.FindObjectsOfTypeAll(inputType);
				for (int i = 0; i < array.Length; i++)
				{
					if (IsFocusedInput(array[i]))
					{
						return true;
					}
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		private static bool IsFocusedInput(Object input)
		{
			Component val = (Component)(object)((input is Component) ? input : null);
			if (val == null || !val.gameObject.activeInHierarchy)
			{
				return false;
			}
			Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
			if (val2 != null && !val2.enabled)
			{
				return false;
			}
			PropertyInfo property = ((object)input).GetType().GetProperty("isFocused", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.PropertyType == typeof(bool))
			{
				try
				{
					return (bool)property.GetValue(input, null);
				}
				catch
				{
					return false;
				}
			}
			return false;
		}

		[DllImport("user32.dll")]
		private static extern short GetAsyncKeyState(int virtualKey);

		[DllImport("user32.dll")]
		private static extern IntPtr GetForegroundWindow();

		[DllImport("user32.dll")]
		private static extern uint GetWindowThreadProcessId(IntPtr windowHandle, out uint processId);
	}
	[BepInPlugin("MechGaming.REPO.ValuableTracker", "ValuableTracker", "1.0.3")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "MechGaming.REPO.ValuableTracker";

		public const string PluginName = "ValuableTracker";

		public const string PluginVersion = "1.0.3";

		private const float SnapshotInterval = 0.25f;

		private const int MenuWidth = 360;

		private const int MenuHeight = 250;

		private Harmony? _harmony;

		private ConfigEntry<KeyCode> _menuKey;

		private ConfigEntry<bool> _showHud;

		private ConfigEntry<bool> _showInCart;

		private ConfigEntry<bool> _showDestroyed;

		private ConfigEntry<float> _hudRightOffset;

		private ConfigEntry<float> _hudTopOffset;

		private TrackerSnapshot _snapshot;

		private Rect _menuRect = new Rect(30f, 30f, 360f, 250f);

		private float _nextSnapshotTime;

		private float _statusMessageUntil;

		private string _statusMessage = string.Empty;

		private bool _menuOpen;

		private bool _storedCursorVisible;

		private CursorLockMode _storedCursorLockMode;

		internal static Plugin? Instance { get; private set; }

		private void Awake()
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			Instance = this;
			_menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "MenuKey", (KeyCode)285, "Key used to open ValuableTracker settings.");
			_showHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowHUD", true, "Show the valuable tracking HUD.");
			_showInCart = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowInCart", true, "Show valuables that are currently in carts.");
			_showDestroyed = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowDestroyed", true, "Show valuables that were destroyed or removed before sale.");
			_hudRightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "RightOffset", 18f, "HUD distance from the right side of the screen.");
			_hudTopOffset = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "TopOffset", 275f, "HUD distance from the top of the screen.");
			ValuableTrackerState.Init(((BaseUnityPlugin)this).Logger);
			_harmony = new Harmony("MechGaming.REPO.ValuableTracker");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ValuableTracker 1.0.3 loaded.");
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (HotkeyInput.GetKeyDown(_menuKey.Value))
			{
				SetMenuOpen(!_menuOpen);
			}
			else if (_menuOpen && HotkeyInput.GetKeyDown((KeyCode)27))
			{
				SetMenuOpen(open: false);
			}
			if (Time.unscaledTime >= _nextSnapshotTime)
			{
				_snapshot = ValuableTrackerState.CreateSnapshot();
				_nextSnapshotTime = Time.unscaledTime + 0.25f;
			}
		}

		private void LateUpdate()
		{
			if (_menuOpen)
			{
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
		}

		private void OnDestroy()
		{
			SetMenuOpen(open: false);
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			ValuableTrackerState.Clear();
			Instance = null;
		}

		private void OnGUI()
		{
			//IL_002b: 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_0046: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (_showHud.Value && ShouldDrawHud())
			{
				DrawHud();
			}
			if (_menuOpen)
			{
				_menuRect = GUI.Window(((Object)this).GetInstanceID(), _menuRect, new WindowFunction(DrawMenuWindow), "ValuableTracker");
			}
		}

		private bool ShouldDrawHud()
		{
			if (_snapshot.Total > 0)
			{
				return SafeGameCheck((Func<bool>)SemiFunc.RunIsLevel);
			}
			return false;
		}

		private void DrawHud()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = BuildHudLines();
			if (list.Count == 0)
			{
				return;
			}
			float num = 14f + (float)list.Count * 23f;
			float num2 = Mathf.Max(8f, (float)Screen.width - 300f - _hudRightOffset.Value);
			float num3 = Mathf.Clamp(_hudTopOffset.Value, 8f, Mathf.Max(8f, (float)Screen.height - num - 8f));
			Rect val = new Rect(num2, num3, 300f, num);
			GUI.color = new Color(0f, 0f, 0f, 0.66f);
			GUI.Box(val, GUIContent.none);
			GUI.color = Color.white;
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 18,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)2,
				richText = true
			};
			val2.normal.textColor = new Color(0.78f, 0.91f, 0.9f, 1f);
			float num4 = num3 + 7f;
			foreach (string item in list)
			{
				GUI.Label(new Rect(num2 + 8f, num4, 284f, 24f), item, val2);
				num4 += 23f;
			}
		}

		private List<string> BuildHudLines()
		{
			List<string> list = new List<string>();
			int collected = _snapshot.Collected;
			string item = ((collected >= _snapshot.Total && _snapshot.Total > 0) ? $"<color=#58ff79>Sold ({collected}) / {_snapshot.Total} valuables</color>" : $"Sold: {_snapshot.Sold} ({collected}) / {_snapshot.Total} valuables");
			list.Add(item);
			if (_showInCart.Value && _snapshot.InCart > 0)
			{
				list.Add($"In Cart: {_snapshot.InCart}");
			}
			if (_showDestroyed.Value && _snapshot.Destroyed > 0)
			{
				list.Add($"<color=#ff5555>Destroyed: {_snapshot.Destroyed}</color>");
			}
			return list;
		}

		private void DrawMenuWindow(int windowId)
		{
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Space(8f);
			_showHud.Value = GUILayout.Toggle(_showHud.Value, "Show HUD", Array.Empty<GUILayoutOption>());
			_showInCart.Value = GUILayout.Toggle(_showInCart.Value, "Track In Cart", Array.Empty<GUILayoutOption>());
			_showDestroyed.Value = GUILayout.Toggle(_showDestroyed.Value, "Track Destroyed", Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			GUILayout.Label($"Sold: {_snapshot.Sold}   In Cart: {_snapshot.InCart}   Destroyed: {_snapshot.Destroyed}", Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Collected: {_snapshot.Collected} / {_snapshot.Total}", Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			if (GUILayout.Button("Discover All Valuables", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
			{
				int num = ValuableTrackerState.DiscoverAll();
				_snapshot = ValuableTrackerState.CreateSnapshot();
				_statusMessage = ((num == 1) ? "Discovered 1 valuable." : $"Discovered {num} valuables.");
				_statusMessageUntil = Time.unscaledTime + 4f;
			}
			if (Time.unscaledTime < _statusMessageUntil)
			{
				GUILayout.Label(_statusMessage, Array.Empty<GUILayoutOption>());
			}
			GUILayout.FlexibleSpace();
			GUILayout.Label($"Press {_menuKey.Value} or Escape to close.", Array.Empty<GUILayoutOption>());
			GUI.DragWindow(new Rect(0f, 0f, 360f, 24f));
		}

		private void SetMenuOpen(bool open)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (_menuOpen != open)
			{
				_menuOpen = open;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ValuableTracker menu " + (open ? "opened" : "closed") + "."));
				if (open)
				{
					_storedCursorVisible = Cursor.visible;
					_storedCursorLockMode = Cursor.lockState;
					Cursor.visible = true;
					Cursor.lockState = (CursorLockMode)0;
				}
				else
				{
					Cursor.visible = _storedCursorVisible;
					Cursor.lockState = _storedCursorLockMode;
				}
			}
		}

		private static bool NoTextInputActive()
		{
			return HotkeyInput.NoTextInputActive((Func<bool>)SemiFunc.NoTextInputsActive);
		}

		private static bool SafeGameCheck(Func<bool> check)
		{
			try
			{
				return check();
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class ValuableTrackerState
	{
		private static readonly List<TrackedValuable> TrackedValuables = new List<TrackedValuable>();

		private static readonly FieldInfo? CartItemsField = AccessTools.Field(typeof(PhysGrabCart), "itemsInCart");

		private static readonly FieldInfo? DiscoveredField = AccessTools.Field(typeof(ValuableObject), "discovered");

		private static ManualLogSource? _logger;

		internal static void Init(ManualLogSource logger)
		{
			_logger = logger;
		}

		internal static void Clear()
		{
			TrackedValuables.Clear();
		}

		internal static void Rebuild()
		{
			Clear();
			ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>();
			for (int i = 0; i < array.Length; i++)
			{
				Register(array[i]);
			}
			ManualLogSource? logger = _logger;
			if (logger != null)
			{
				logger.LogInfo((object)$"Tracking {TrackedValuables.Count} valuables.");
			}
		}

		internal static void Register(ValuableObject? valuable)
		{
			if (!IsAlive(valuable))
			{
				return;
			}
			int instanceID = ((Object)valuable).GetInstanceID();
			foreach (TrackedValuable trackedValuable in TrackedValuables)
			{
				if (trackedValuable.InstanceId == instanceID)
				{
					return;
				}
			}
			TrackedValuables.Add(new TrackedValuable(valuable, instanceID));
		}

		internal static void MarkCurrentHaulAsSold()
		{
			RoundDirector instance = RoundDirector.instance;
			if ((Object)(object)instance == (Object)null || instance.dollarHaulList == null)
			{
				return;
			}
			foreach (TrackedValuable trackedValuable in TrackedValuables)
			{
				ValuableObject item = trackedValuable.Item;
				if (IsAlive(item) && IsInHaulList(item, instance.dollarHaulList))
				{
					trackedValuable.Sold = true;
				}
			}
		}

		internal static TrackerSnapshot CreateSnapshot()
		{
			HashSet<int> valuablesInCarts = GetValuablesInCarts();
			List<GameObject> list = (((Object)(object)RoundDirector.instance != (Object)null) ? RoundDirector.instance.dollarHaulList : null);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (TrackedValuable trackedValuable in TrackedValuables)
			{
				ValuableObject item = trackedValuable.Item;
				bool flag = IsAlive(item);
				if (trackedValuable.Sold)
				{
					num++;
					continue;
				}
				if (flag)
				{
					ValuableObject valuable = item;
					if (list != null && IsInHaulList(valuable, list))
					{
						num++;
						continue;
					}
				}
				if (!flag)
				{
					trackedValuable.Destroyed = true;
				}
				if (trackedValuable.Destroyed)
				{
					num3++;
				}
				else if (flag && valuablesInCarts.Contains(((Object)item).GetInstanceID()))
				{
					num2++;
				}
			}
			return new TrackerSnapshot(TrackedValuables.Count, num, num2, num3);
		}

		internal static int DiscoverAll()
		{
			int num = 0;
			foreach (TrackedValuable trackedValuable in TrackedValuables)
			{
				ValuableObject item = trackedValuable.Item;
				if (IsAlive(item))
				{
					ValuableObject valuable = item;
					if (!IsDiscovered(valuable))
					{
						SetDiscovered(valuable, discovered: true);
						num++;
					}
					EnsureMapMarker(valuable);
				}
			}
			return num;
		}

		private static HashSet<int> GetValuablesInCarts()
		{
			HashSet<int> hashSet = new HashSet<int>();
			if (CartItemsField == null)
			{
				return hashSet;
			}
			PhysGrabCart[] array = Object.FindObjectsOfType<PhysGrabCart>();
			foreach (PhysGrabCart obj in array)
			{
				if (!(CartItemsField.GetValue(obj) is IEnumerable enumerable))
				{
					continue;
				}
				foreach (object item in enumerable)
				{
					PhysGrabObject val = (PhysGrabObject)((item is PhysGrabObject) ? item : null);
					if (val != null)
					{
						ValuableObject component = ((Component)val).GetComponent<ValuableObject>();
						if (IsAlive(component))
						{
							hashSet.Add(((Object)component).GetInstanceID());
						}
					}
				}
			}
			return hashSet;
		}

		private static bool IsInHaulList(ValuableObject valuable, List<GameObject> dollarHaulList)
		{
			GameObject gameObject = ((Component)valuable).gameObject;
			if (dollarHaulList.Contains(gameObject))
			{
				return true;
			}
			Transform parent = ((Component)valuable).transform.parent;
			if ((Object)(object)parent != (Object)null)
			{
				return dollarHaulList.Contains(((Component)parent).gameObject);
			}
			return false;
		}

		private static bool IsAlive(ValuableObject? valuable)
		{
			if ((Object)(object)valuable != (Object)null && ((Component)valuable).gameObject.activeInHierarchy)
			{
				return ((Behaviour)valuable).enabled;
			}
			return false;
		}

		private static bool IsDiscovered(ValuableObject valuable)
		{
			try
			{
				object obj = DiscoveredField?.GetValue(valuable);
				return obj is bool && (bool)obj;
			}
			catch (Exception ex)
			{
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogDebug((object)("Could not read discovered state for " + ((Object)valuable).name + ": " + ex.Message));
				}
				return false;
			}
		}

		private static void SetDiscovered(ValuableObject valuable, bool discovered)
		{
			try
			{
				DiscoveredField?.SetValue(valuable, discovered);
			}
			catch (Exception ex)
			{
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogWarning((object)("Could not set discovered state for " + ((Object)valuable).name + ": " + ex.Message));
				}
			}
		}

		private static void EnsureMapMarker(ValuableObject valuable)
		{
			Map instance = Map.Instance;
			if ((Object)(object)instance == (Object)null || MapAlreadyHasMarker(valuable))
			{
				return;
			}
			try
			{
				instance.AddValuable(valuable);
			}
			catch (Exception ex)
			{
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogWarning((object)("Could not add map marker for " + ((Object)valuable).name + ": " + ex.Message));
				}
			}
		}

		private static bool MapAlreadyHasMarker(ValuableObject valuable)
		{
			MapValuable[] array = Resources.FindObjectsOfTypeAll<MapValuable>();
			foreach (MapValuable val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.target == (Object)(object)valuable)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal sealed class TrackedValuable
	{
		internal ValuableObject? Item { get; }

		internal int InstanceId { get; }

		internal bool Sold { get; set; }

		internal bool Destroyed { get; set; }

		internal TrackedValuable(ValuableObject item, int instanceId)
		{
			Item = item;
			InstanceId = instanceId;
		}
	}
	internal readonly struct TrackerSnapshot
	{
		internal int Total { get; }

		internal int Sold { get; }

		internal int InCart { get; }

		internal int Destroyed { get; }

		internal int Collected => Mathf.Min(Total, Sold + InCart + Destroyed);

		internal TrackerSnapshot(int total, int sold, int inCart, int destroyed)
		{
			Total = total;
			Sold = sold;
			InCart = inCart;
			Destroyed = destroyed;
		}
	}
	[HarmonyPatch(typeof(LevelGenerator), "GenerateDone")]
	internal static class LevelGeneratorGenerateDonePatch
	{
		private static void Postfix()
		{
			ValuableTrackerState.Rebuild();
		}
	}
	[HarmonyPatch(typeof(ValuableObject), "Start")]
	internal static class ValuableObjectStartPatch
	{
		private static void Postfix(ValuableObject __instance)
		{
			if (SafeLevelGenDone())
			{
				ValuableTrackerState.Register(__instance);
			}
		}

		private static bool SafeLevelGenDone()
		{
			try
			{
				return SemiFunc.LevelGenDone();
			}
			catch
			{
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(RoundDirector), "HaulCheck")]
	internal static class RoundDirectorHaulCheckPatch
	{
		private static void Postfix()
		{
			ValuableTrackerState.MarkCurrentHaulAsSold();
		}
	}
	[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
	internal static class RunManagerChangeLevelPatch
	{
		private static void Postfix()
		{
			ValuableTrackerState.Clear();
		}
	}
}