using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Pigeon; using Sparroh.UI; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.UI; [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("Sparroh")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.1.3.0")] [assembly: AssemblyInformationalVersion("2.1.3")] [assembly: AssemblyProduct("BatchScrapping")] [assembly: AssemblyTitle("BatchScrapping")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.1.3.0")] [module: UnverifiableCode] [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; } } } public static class ConfigManager { private const float DebounceSeconds = 0.25f; private static ConfigFile config; private static ManualLogSource logger; private static FileSystemWatcher configWatcher; private static volatile bool reloadPending; private static float lastReloadTime; public static ConfigEntry TrashMarkKey { get; private set; } public static ConfigEntry EnableInstantScrapping { get; private set; } public static ConfigEntry EnableFixedTimer { get; private set; } public static ConfigEntry FixedTimerDuration { get; private set; } public static void Initialize(ConfigFile configFile, ManualLogSource log) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) config = configFile; logger = log; TrashMarkKey = config.Bind("Keybinds", "Trash Mark Keybind", (Key)34, "Key to toggle trash mark on upgrades"); EnableInstantScrapping = config.Bind("General", "Instant Scrap", false, "Enable instant scrapping without hold timer"); EnableFixedTimer = config.Bind("General", "Fixed Scrap Time", false, "Use fixed scrap timer instead of default (ignored when Instant Scrap is on)"); FixedTimerDuration = config.Bind("General", "Scrap Duration", 1f, "Duration in seconds for fixed scrap timer"); ScrapHandlingMod.currentTrashKey = TrashMarkKey.Value; TrashMarkKey.SettingChanged += OnTrashMarkKeyChanged; try { SetupFileWatcher(); } catch (Exception ex) { logger.LogError((object)("Error setting up config file watcher: " + ex.Message)); } } public static void Tick() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!reloadPending || Time.unscaledTime - lastReloadTime < 0.25f) { return; } reloadPending = false; lastReloadTime = Time.unscaledTime; try { config.Reload(); ScrapHandlingMod.currentTrashKey = TrashMarkKey.Value; logger.LogInfo((object)"Config reloaded from disk."); } catch (Exception ex) { logger.LogError((object)("Error reloading config: " + ex.Message)); } } public static void Dispose() { if (TrashMarkKey != null) { TrashMarkKey.SettingChanged -= OnTrashMarkKeyChanged; } if (configWatcher != null) { configWatcher.EnableRaisingEvents = false; configWatcher.Changed -= OnConfigFileChanged; configWatcher.Created -= OnConfigFileChanged; configWatcher.Renamed -= OnConfigFileChanged; configWatcher.Dispose(); configWatcher = null; } } private static void SetupFileWatcher() { configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.batchscrapping.cfg"); configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; configWatcher.Changed += OnConfigFileChanged; configWatcher.Created += OnConfigFileChanged; configWatcher.Renamed += OnConfigFileChanged; configWatcher.EnableRaisingEvents = true; } private static void OnConfigFileChanged(object sender, FileSystemEventArgs e) { reloadPending = true; } private static void OnTrashMarkKeyChanged(object sender, EventArgs e) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) ScrapHandlingMod.currentTrashKey = TrashMarkKey.Value; } } public static class InstantPatches { private const float InstantDuration = 0.05f; private static Harmony _harmony; public static bool ShouldModifyDuration { get { if (ConfigManager.EnableInstantScrapping == null || !ConfigManager.EnableInstantScrapping.Value) { if (ConfigManager.EnableFixedTimer != null) { return ConfigManager.EnableFixedTimer.Value; } return false; } return true; } } public static void Initialize() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown try { _harmony = new Harmony("sparroh.batchscrapping.instant"); MethodInfo methodInfo = AccessTools.Method(typeof(GearUpgradeUI), "HasUnlockAction", new Type[1] { typeof(UnlockActionParams).MakeByRefType() }, (Type[])null); if (methodInfo != null) { try { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(InstantScrapPatches), "HasUnlockActionPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); SparrohPlugin.Logger.LogInfo((object)"Instant Scrap: patched GearUpgradeUI.HasUnlockAction"); return; } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Failed to patch HasUnlockAction: " + ex.Message)); return; } } SparrohPlugin.Logger.LogError((object)"Instant Scrap: could not find GearUpgradeUI.HasUnlockAction(out UnlockActionParams). Instant scrap disabled."); } catch (Exception ex2) { SparrohPlugin.Logger.LogError((object)("Critical error during Instant Scrap initialization: " + ex2.Message)); } } public static void Destroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; } public static float GetModifiedDuration(float original) { if (ConfigManager.EnableInstantScrapping != null && ConfigManager.EnableInstantScrapping.Value) { return 0.05f; } if (ConfigManager.EnableFixedTimer != null && ConfigManager.EnableFixedTimer.Value) { return Mathf.Max(0.05f, ConfigManager.FixedTimerDuration.Value); } return original; } } public static class InstantScrapPatches { public static void HasUnlockActionPostfix(ref UnlockActionParams data) { try { if (data.OnSecondaryComplete != null && InstantPatches.ShouldModifyDuration) { data.SecondaryDuration = InstantPatches.GetModifiedDuration(data.SecondaryDuration); } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Error in HasUnlockActionPostfix: " + ex.Message)); } } } [BepInPlugin("sparroh.batchscrapping", "BatchScrapping", "2.1.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [MycoMod(/*Could not decode attribute arguments.*/)] public class SparrohPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.batchscrapping"; public const string PluginName = "BatchScrapping"; public const string PluginVersion = "2.1.3"; internal static ManualLogSource Logger; public static SparrohPlugin Instance; private bool _barRegistered; private bool _lastUndoCan; private int _lastUndoCount = -1; private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Expected O, but got Unknown //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Expected O, but got Unknown //IL_025b: Expected O, but got Unknown //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Expected O, but got Unknown try { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; Harmony val = new Harmony("sparroh.batchscrapping"); try { ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger); ScrapHandlingMod.ScrapMarkedAction = delegate { ScrapHandlingMod.TryScrapMarkedUpgrades((MonoBehaviour)(object)this); }; ScrapHandlingMod.ScrapNonFavoriteAction = delegate { ScrapHandlingMod.TryScrapNonFavoriteUpgrades((MonoBehaviour)(object)this); }; ScrapHandlingMod.LoadTrashSprite(); } catch (Exception ex) { Logger.LogError((object)("Failed to setup configuration bindings: " + ex.Message)); } try { InstantPatches.Initialize(); } catch (Exception ex2) { Logger.LogError((object)("Failed to initialize Instant Scrap: " + ex2.Message)); } try { val.PatchAll(); } catch (Exception ex3) { Logger.LogError((object)("Failed to apply Harmony patches: " + ex3.Message)); } try { MethodInfo methodInfo = AccessTools.Method(typeof(GearDetailsWindow), "Update", (Type[])null, (Type[])null); if (methodInfo != null) { val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ScrapUIPatches), "UpdatePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo2 = AccessTools.Method(typeof(GearUpgradeUI), "UpdateFavoriteIcon", (Type[])null, (Type[])null); if (methodInfo2 != null) { val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(ScrapUIPatches), "UpdateFavoriteIconPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo3 = AccessTools.Method(typeof(GearUpgradeUI), "OnAdditionalAction", new Type[2] { typeof(int), typeof(bool).MakeByRefType() }, (Type[])null); if (methodInfo3 != null) { val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(ScrapUIPatches), "OnAdditionalActionPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo4 = AccessTools.Method(typeof(GearUpgradeUI), "EnableGridView", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo4 != null) { val.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(ScrapUIPatches), "EnableGridViewPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo5 = AccessTools.Method(typeof(GearUpgradeUI), "Dismantle", (Type[])null, (Type[])null); if (methodInfo5 != null) { val.Patch((MethodBase)methodInfo5, new HarmonyMethod(typeof(ScrapUndoPatches), "DismantlePrefix", (Type[])null), new HarmonyMethod(typeof(ScrapUndoPatches), "DismantlePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)"Patched GearUpgradeUI.Dismantle for scrap undo."); } else { Logger.LogError((object)"Could not find GearUpgradeUI.Dismantle — single-scrap undo unavailable."); } HarmonyMethod val2 = new HarmonyMethod(typeof(BatchPickupFeedbackPatches), "ShowPickupInfoPrefix", (Type[])null); int num = 0; foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(GameManager))) { if (!(declaredMethod == null) && !(declaredMethod.Name != "ShowPickupInfo")) { try { val.Patch((MethodBase)declaredMethod, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } catch (Exception ex4) { Logger.LogWarning((object)$"Failed to patch ShowPickupInfo ({declaredMethod}): {ex4.Message}"); } } } if (num > 0) { Logger.LogInfo((object)$"Patched {num} GameManager.ShowPickupInfo overload(s) for batch toast consolidation."); } else { Logger.LogWarning((object)"Could not find GameManager.ShowPickupInfo — batch pickup toasts may spam."); } MethodInfo methodInfo6 = AccessTools.Method(typeof(PlayerResource), "PlayPickupSound", (Type[])null, (Type[])null); if (methodInfo6 != null) { val.Patch((MethodBase)methodInfo6, new HarmonyMethod(typeof(BatchPickupFeedbackPatches), "PlayPickupSoundPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)"Patched PlayerResource.PlayPickupSound for batch scrap."); } } catch (Exception ex5) { Logger.LogError((object)("Failed to apply scrap patches: " + ex5.Message)); } } catch (Exception ex6) { Logger.LogError((object)("Critical error during mod initialization: " + ex6.Message + "\n" + ex6.StackTrace)); } Logger.LogInfo((object)"BatchScrapping v2.1.3 loaded successfully."); } private void Update() { ConfigManager.Tick(); GearActionBar.Tick(); if (!GearActionBar.IsGearMenuOpen()) { return; } if (!_barRegistered) { GearActionBar.Register("scrap_marked", "Scrap Marked", 120, (Action)delegate { UIDialog.Confirm("Scrap Marked", "Scrap all trash-marked upgrades? This can be undone.", (Action)delegate { ScrapHandlingMod.ScrapMarkedAction?.Invoke(); }, (Action)null, "Confirm", "Cancel"); }, (UIButtonStyle)0); GearActionBar.Register("scrap_nonfav", "Scrap No-Fav", 130, (Action)delegate { UIDialog.Confirm("Scrap Non-Favorite", "Scrap ALL non-favorite upgrades? This can be undone.", (Action)delegate { ScrapHandlingMod.ScrapNonFavoriteAction?.Invoke(); }, (Action)null, "Confirm", "Cancel"); }, (UIButtonStyle)2); GearActionBar.Register("undo_scrap", "Undo Scrap", 140, (Action)delegate { UndoPatches.TryUndo(); }, (UIButtonStyle)1); _barRegistered = true; _lastUndoCan = !UndoPatches.CanUndo; _lastUndoCount = -1; } bool canUndo = UndoPatches.CanUndo; int undoCount = UndoPatches.UndoCount; if (canUndo != _lastUndoCan || undoCount != _lastUndoCount) { _lastUndoCan = canUndo; _lastUndoCount = undoCount; GearActionBar.SetInteractable("undo_scrap", canUndo); GearActionBar.SetText("undo_scrap", canUndo ? $"Undo ({undoCount})" : "Undo"); } } private void OnDestroy() { try { ConfigManager.Dispose(); InstantPatches.Destroy(); UndoPatches.Clear(); GearActionBar.Unregister("scrap_marked"); GearActionBar.Unregister("scrap_nonfav"); GearActionBar.Unregister("undo_scrap"); _barRegistered = false; } catch (Exception ex) { Logger.LogError((object)("Failed to destroy BatchScrapping UI: " + ex.Message)); } } } public static class ScrapHandlingMod { private const float HOLD_DURATION = 1f; private const int BATCH_SIZE = 1000000; private const float BATCH_INTERVAL = 0f; private const byte FavoriteFlag = 1; private const byte TrashMarkFlag = 32; private static bool wasScrappingSkins; public static Key currentTrashKey; public static Action ScrapMarkedAction; public static Action ScrapNonFavoriteAction; public static Sprite starSprite; public static Sprite trashSprite; public static bool IsScrapping { get; private set; } public static bool SuppressPickupFeedback { get; private set; } public static void LoadTrashSprite() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)trashSprite != (Object)null) { return; } try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = null; string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (text2.EndsWith("trashcan.png", StringComparison.OrdinalIgnoreCase)) { text = text2; break; } } if (text == null) { SparrohPlugin.Logger.LogWarning((object)"trashcan.png embedded resource not found; trash marks will use red star."); return; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { SparrohPlugin.Logger.LogWarning((object)"Failed to open trashcan.png resource stream."); return; } byte[] array = new byte[stream.Length]; int num; for (int j = 0; j < array.Length; j += num) { if ((num = stream.Read(array, j, array.Length - j)) <= 0) { break; } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array, false)) { SparrohPlugin.Logger.LogWarning((object)"Failed to decode trashcan.png."); Object.Destroy((Object)(object)val); return; } ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Object)val).name = "BatchScrapping_Trashcan"; trashSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)trashSprite).name = "BatchScrapping_Trashcan"; SparrohPlugin.Logger.LogInfo((object)$"Loaded trashcan sprite ({((Texture)val).width}x{((Texture)val).height})."); } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Failed to load trashcan sprite: " + ex.Message)); } } public static Sprite GetTrashIconSprite() { Sprite obj; if (!((Object)(object)trashSprite != (Object)null)) { obj = starSprite; if (obj == null) { return Resources.Load("favorite star"); } } else { obj = trashSprite; } return obj; } public static void ApplyMarkIcon(Image favoriteIcon, UpgradeInstance upgrade) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)favoriteIcon == (Object)null || upgrade == null) { return; } if (IsFavorite(upgrade)) { if ((Object)(object)starSprite == (Object)null && (Object)(object)favoriteIcon.sprite != (Object)null && (Object)(object)favoriteIcon.sprite != (Object)(object)trashSprite) { starSprite = favoriteIcon.sprite; } favoriteIcon.sprite = starSprite ?? favoriteIcon.sprite; ((Component)favoriteIcon).gameObject.SetActive(true); ((Graphic)favoriteIcon).color = Color.white; } else if (IsTrashMarked(upgrade)) { if ((Object)(object)starSprite == (Object)null && (Object)(object)favoriteIcon.sprite != (Object)null && (Object)(object)favoriteIcon.sprite != (Object)(object)trashSprite) { starSprite = favoriteIcon.sprite; } favoriteIcon.sprite = GetTrashIconSprite(); ((Component)favoriteIcon).gameObject.SetActive(true); ((Graphic)favoriteIcon).color = Color.red; } else { ((Component)favoriteIcon).gameObject.SetActive(false); } } private static bool TryScrapInstance(UpgradeInstance inst) { if (inst == null) { return false; } Upgrade upgrade; try { upgrade = inst.Upgrade; } catch { return false; } if ((Object)(object)upgrade == (Object)null) { return false; } try { PlayerData.UnequipFromAll(inst); } catch { } try { if (!inst.Destroy()) { return false; } upgrade.GiveDismantleResources(inst); return true; } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("TryScrapInstance failed: " + ex.Message)); return false; } } private static IEnumerator FinishBatchScrapCoroutine(bool success, bool isSkinsMode) { try { if (success) { UndoPatches.EndBatch(); } else { UndoPatches.CancelBatch(); } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("FinishBatchScrap EndBatch failed: " + ex.Message)); UndoPatches.CancelBatch(); success = false; } SuppressPickupFeedback = false; if (success) { try { wasScrappingSkins = isSkinsMode; RefreshOpenWindows(); } catch (Exception ex2) { SparrohPlugin.Logger.LogError((object)("FinishBatchScrap refresh failed: " + ex2.Message)); } yield return null; try { BatchPickupFeedbackPatches.FlushAccumulatedPickups(); } catch (Exception ex3) { SparrohPlugin.Logger.LogWarning((object)("FinishBatchScrap popup flush failed: " + ex3.Message)); } } else { BatchPickupFeedbackPatches.ClearAccumulated(); } IsScrapping = false; } public static IEnumerator ScrapMarkedUpgrades() { int num = 0; bool flag; List list; bool flag2; try { if (IsScrapping) { SparrohPlugin.Logger.LogWarning((object)"ScrapMarkedUpgrades: Already scrapping, aborting."); yield break; } IsScrapping = true; SuppressPickupFeedback = true; BatchPickupFeedbackPatches.ClearAccumulated(); SparrohPlugin.Logger.LogInfo((object)"Starting ScrapMarkedUpgrades operation."); GearDetailsWindow val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { SparrohPlugin.Logger.LogError((object)"ScrapMarkedUpgrades: GearDetailsWindow not found."); SuppressPickupFeedback = false; IsScrapping = false; yield break; } IUpgradable upgradablePrefab = val.UpgradablePrefab; if (upgradablePrefab == null) { SparrohPlugin.Logger.LogError((object)"ScrapMarkedUpgrades: UpgradablePrefab is null."); SuppressPickupFeedback = false; IsScrapping = false; yield break; } flag = (bool)AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode").GetValue(val); IEnumerable enumerable = (flag ? PlayerData.GetAllSkins(upgradablePrefab, true) : PlayerData.GetAllUpgrades(upgradablePrefab, true)); int num2 = 0; foreach (UpgradeInfo item in enumerable) { if (item?.Instances != null) { num2 += item.Instances.Count; } } list = new List(num2); foreach (UpgradeInfo item2 in enumerable) { if (item2?.Instances == null) { continue; } foreach (UpgradeInstance instance in item2.Instances) { if (instance != null && IsTrashMarked(instance)) { list.Add(instance); } } } if (list.Count == 0) { SparrohPlugin.Logger.LogInfo((object)"ScrapMarkedUpgrades: No marked upgrades found."); SuppressPickupFeedback = false; IsScrapping = false; yield break; } UndoPatches.BeginBatch($"Scrap Marked ({list.Count})"); foreach (UpgradeInstance item3 in list) { UndoPatches.AddToBatch(item3); } SparrohPlugin.Logger.LogInfo((object)$"ScrapMarkedUpgrades: Processing {list.Count} upgrades."); flag2 = true; } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("ScrapMarkedUpgrades: Setup failed: " + ex.Message)); UndoPatches.CancelBatch(); SuppressPickupFeedback = false; IsScrapping = false; yield break; } if (flag2 && list != null) { for (int i = 0; i < list.Count; i += 1000000) { int num3 = Mathf.Min(i + 1000000, list.Count); for (int j = i; j < num3; j++) { if (TryScrapInstance(list[j])) { num++; } } } } yield return FinishBatchScrapCoroutine(num > 0, flag); } public static bool IsFavorite(UpgradeInstance instance) { if (instance == null) { return false; } return ((byte)AccessTools.Field(typeof(UpgradeInstance), "flags").GetValue(instance) & 1) != 0; } public static bool IsTrashMarked(UpgradeInstance instance) { if (instance == null) { return false; } return ((byte)AccessTools.Field(typeof(UpgradeInstance), "flags").GetValue(instance) & 0x20) != 0; } public static void SetTrashMark(UpgradeInstance instance, bool marked) { if (instance != null) { FieldInfo fieldInfo = AccessTools.Field(typeof(UpgradeInstance), "flags"); byte b = (byte)fieldInfo.GetValue(instance); if (marked) { b |= 0x20; b &= 0xFE; } else { b &= 0xDF; } fieldInfo.SetValue(instance, b); } } public static void SetFavorite(UpgradeInstance instance, bool favorite) { if (instance != null) { FieldInfo fieldInfo = AccessTools.Field(typeof(UpgradeInstance), "flags"); byte b = (byte)fieldInfo.GetValue(instance); if (favorite) { b |= 1; b &= 0xDF; } else { b &= 0xFE; } fieldInfo.SetValue(instance, b); } } public static void TryScrapMarkedUpgrades(MonoBehaviour owner) { GearDetailsWindow val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } IUpgradable upgradablePrefab = val.UpgradablePrefab; if (upgradablePrefab == null) { return; } List obj = (((bool)AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode").GetValue(val)) ? PlayerData.GetAllSkins(upgradablePrefab, true) : PlayerData.GetAllUpgrades(upgradablePrefab, true)); bool flag = false; foreach (UpgradeInfo item in obj) { if (item?.Instances != null && item.Instances.Any((UpgradeInstance inst) => inst != null && IsTrashMarked(inst))) { flag = true; break; } } if (flag) { owner.StartCoroutine(ScrapMarkedUpgrades()); } } public static IEnumerator ScrapNonFavoriteUpgrades() { int num = 0; bool flag; List list; bool flag2; try { if (IsScrapping) { SparrohPlugin.Logger.LogWarning((object)"ScrapNonFavoriteUpgrades: Already scrapping, aborting."); yield break; } IsScrapping = true; SuppressPickupFeedback = true; BatchPickupFeedbackPatches.ClearAccumulated(); SparrohPlugin.Logger.LogInfo((object)"Starting ScrapNonFavoriteUpgrades operation."); GearDetailsWindow val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { SparrohPlugin.Logger.LogError((object)"ScrapNonFavoriteUpgrades: GearDetailsWindow not found."); SuppressPickupFeedback = false; IsScrapping = false; yield break; } IUpgradable upgradablePrefab = val.UpgradablePrefab; if (upgradablePrefab == null) { SparrohPlugin.Logger.LogError((object)"ScrapNonFavoriteUpgrades: UpgradablePrefab is null."); SuppressPickupFeedback = false; IsScrapping = false; yield break; } flag = (bool)AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode").GetValue(val); IEnumerable enumerable = (flag ? PlayerData.GetAllSkins(upgradablePrefab, true) : PlayerData.GetAllUpgrades(upgradablePrefab, true)); int num2 = 0; foreach (UpgradeInfo item in enumerable) { if (item?.Instances != null) { num2 += item.Instances.Count; } } list = new List(num2); foreach (UpgradeInfo item2 in enumerable) { if (item2?.Instances == null) { continue; } foreach (UpgradeInstance instance in item2.Instances) { if (instance != null && !IsFavorite(instance)) { list.Add(instance); } } } if (list.Count == 0) { SparrohPlugin.Logger.LogInfo((object)"ScrapNonFavoriteUpgrades: No non-favorite upgrades found."); SuppressPickupFeedback = false; IsScrapping = false; yield break; } UndoPatches.BeginBatch($"Scrap Non-Favorite ({list.Count})"); foreach (UpgradeInstance item3 in list) { UndoPatches.AddToBatch(item3); } SparrohPlugin.Logger.LogInfo((object)$"ScrapNonFavoriteUpgrades: Processing {list.Count} upgrades."); flag2 = true; } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("ScrapNonFavoriteUpgrades: Setup failed: " + ex.Message)); UndoPatches.CancelBatch(); SuppressPickupFeedback = false; IsScrapping = false; yield break; } if (flag2 && list != null) { for (int i = 0; i < list.Count; i += 1000000) { int num3 = Mathf.Min(i + 1000000, list.Count); for (int j = i; j < num3; j++) { if (TryScrapInstance(list[j])) { num++; } } } } yield return FinishBatchScrapCoroutine(num > 0, flag); } public static void TryScrapNonFavoriteUpgrades(MonoBehaviour owner) { GearDetailsWindow val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } IUpgradable upgradablePrefab = val.UpgradablePrefab; if (upgradablePrefab == null) { return; } List obj = (((bool)AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode").GetValue(val)) ? PlayerData.GetAllSkins(upgradablePrefab, true) : PlayerData.GetAllUpgrades(upgradablePrefab, true)); bool flag = false; foreach (UpgradeInfo item in obj) { if (item?.Instances != null && item.Instances.Any((UpgradeInstance inst) => inst != null && !IsFavorite(inst))) { flag = true; break; } } if (flag) { owner.StartCoroutine(ScrapNonFavoriteUpgrades()); } } private static void RefreshOpenWindows() { if (!((Object)(object)Menu.Instance != (Object)null) || !Menu.Instance.IsOpen) { return; } Window top = Menu.Instance.WindowSystem.GetTop(); if (!((Object)(object)top != (Object)null)) { return; } top.OnOpen(Menu.Instance.WindowSystem); if (wasScrappingSkins) { GearDetailsWindow val = (GearDetailsWindow)(object)((top is GearDetailsWindow) ? top : null); if ((Object)(object)val != (Object)null) { AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode").SetValue(val, true); } wasScrappingSkins = false; } } } public class ScrapUIPatches { private static readonly HashSet toggledThisSession = new HashSet(); private static void AddScrapButton(GearDetailsWindow window) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)window).transform.Find("ModScrapButtonMarked"); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } Transform val2 = ((Component)window).transform.Find("ModScrapButtonNonFavorite"); if ((Object)(object)val2 != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val2).gameObject); } RectTransform component = ((Component)((Component)window).transform).GetComponent(); GameObject val3 = new GameObject("ModScrapButtonMarked"); val3.transform.SetParent(((Component)window).transform, false); RectTransform val4 = val3.AddComponent(); val4.sizeDelta = new Vector2(200f, 50f); val4.anchorMin = new Vector2(1f, 0f); val4.anchorMax = new Vector2(1f, 0f); val4.pivot = new Vector2(1f, 0f); Rect rect = component.rect; val4.anchoredPosition = new Vector2((0f - ((Rect)(ref rect)).width) * 0.25f, 10f); Image obj = val3.AddComponent(); ((Graphic)obj).color = Color.gray; ((Graphic)obj).raycastTarget = true; Button obj2 = val3.AddComponent