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 PreviousStates = new Dictionary(); 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 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 _menuKey; private ConfigEntry _showHud; private ConfigEntry _showInCart; private ConfigEntry _showDestroyed; private ConfigEntry _hudRightOffset; private ConfigEntry _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("Controls", "MenuKey", (KeyCode)285, "Key used to open ValuableTracker settings."); _showHud = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowHUD", true, "Show the valuable tracking HUD."); _showInCart = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowInCart", true, "Show valuables that are currently in carts."); _showDestroyed = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowDestroyed", true, "Show valuables that were destroyed or removed before sale."); _hudRightOffset = ((BaseUnityPlugin)this).Config.Bind("HUD", "RightOffset", 18f, "HUD distance from the right side of the screen."); _hudTopOffset = ((BaseUnityPlugin)this).Config.Bind("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)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 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 BuildHudLines() { List list = new List(); int collected = _snapshot.Collected; string item = ((collected >= _snapshot.Total && _snapshot.Total > 0) ? $"Sold ({collected}) / {_snapshot.Total} valuables" : $"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($"Destroyed: {_snapshot.Destroyed}"); } 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()); _showInCart.Value = GUILayout.Toggle(_showInCart.Value, "Track In Cart", Array.Empty()); _showDestroyed.Value = GUILayout.Toggle(_showDestroyed.Value, "Track Destroyed", Array.Empty()); GUILayout.Space(8f); GUILayout.Label($"Sold: {_snapshot.Sold} In Cart: {_snapshot.InCart} Destroyed: {_snapshot.Destroyed}", Array.Empty()); GUILayout.Label($"Collected: {_snapshot.Collected} / {_snapshot.Total}", Array.Empty()); 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()); } GUILayout.FlexibleSpace(); GUILayout.Label($"Press {_menuKey.Value} or Escape to close.", Array.Empty()); 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)SemiFunc.NoTextInputsActive); } private static bool SafeGameCheck(Func check) { try { return check(); } catch { return false; } } } internal static class ValuableTrackerState { private static readonly List TrackedValuables = new List(); 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(); 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 valuablesInCarts = GetValuablesInCarts(); List 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 GetValuablesInCarts() { HashSet hashSet = new HashSet(); if (CartItemsField == null) { return hashSet; } PhysGrabCart[] array = Object.FindObjectsOfType(); 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(); if (IsAlive(component)) { hashSet.Add(((Object)component).GetInstanceID()); } } } } return hashSet; } private static bool IsInHaulList(ValuableObject valuable, List 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(); 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(); } } }