Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValuableTracker v1.0.3
BepInEx\plugins\MechGaming-ValuableTracker\ValuableTracker.dll
Decompiled 8 hours agousing 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(); } } }