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(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("BatchScrapping")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BatchScrapping")]
[assembly: AssemblyTitle("BatchScrapping")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 InstantPatches
{
internal static ConfigEntry<bool> EnableFixedTimer;
internal static ConfigEntry<float> FixedTimerDuration;
internal static ConfigEntry<bool> EnableInstantScrapping;
internal static bool s_EnableInstantScrapping;
internal static bool s_EnableFixedTimer;
internal static float s_FixedTimerDuration;
private static FileSystemWatcher configWatcher;
private static Harmony _harmony;
private const float InstantDuration = 0.05f;
public static bool ShouldModifyDuration
{
get
{
if (EnableInstantScrapping == null || !EnableInstantScrapping.Value)
{
if (EnableFixedTimer != null)
{
return EnableFixedTimer.Value;
}
return false;
}
return true;
}
}
public static void Initialize(ConfigEntry<bool> enableFixed, ConfigEntry<float> fixedDur, ConfigEntry<bool> enableInst)
{
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Expected O, but got Unknown
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Expected O, but got Unknown
try
{
EnableFixedTimer = enableFixed;
FixedTimerDuration = fixedDur;
EnableInstantScrapping = enableInst;
s_EnableInstantScrapping = EnableInstantScrapping.Value;
s_EnableFixedTimer = EnableFixedTimer.Value;
s_FixedTimerDuration = FixedTimerDuration.Value;
try
{
SetupFileWatchers();
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("Failed to setup file watchers: " + ex.Message));
}
_harmony = new Harmony("sparroh.instantscrapping");
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)"InstantScrapping: patched GearUpgradeUI.HasUnlockAction");
return;
}
catch (Exception ex2)
{
SparrohPlugin.Logger.LogError((object)("Failed to patch HasUnlockAction: " + ex2.Message));
return;
}
}
SparrohPlugin.Logger.LogError((object)"InstantScrapping: could not find GearUpgradeUI.HasUnlockAction(out UnlockActionParams). Instant scrap disabled.");
}
catch (Exception ex3)
{
SparrohPlugin.Logger.LogError((object)("Critical error during InstantScrapping initialization: " + ex3.Message));
}
}
private static void SetupFileWatchers()
{
configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.batchscrapping.cfg");
configWatcher.Changed += delegate
{
try
{
((ConfigEntryBase)EnableInstantScrapping).ConfigFile.Reload();
s_EnableInstantScrapping = EnableInstantScrapping.Value;
s_EnableFixedTimer = EnableFixedTimer.Value;
s_FixedTimerDuration = FixedTimerDuration.Value;
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogWarning((object)("Config reload failed: " + ex.Message));
}
};
configWatcher.EnableRaisingEvents = true;
}
public static void Destroy()
{
if (configWatcher != null)
{
configWatcher.EnableRaisingEvents = false;
configWatcher.Dispose();
configWatcher = null;
}
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
_harmony = null;
}
public static float GetModifiedDuration(float original)
{
if (EnableInstantScrapping != null && EnableInstantScrapping.Value)
{
return 0.05f;
}
if (EnableFixedTimer != null && EnableFixedTimer.Value)
{
return Mathf.Max(0.05f, 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.0")]
[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.0";
private ConfigEntry<Key> TrashMarkKey;
private ConfigEntry<bool> EnableInstantScrapping;
private ConfigEntry<bool> EnableFixedTimer;
private ConfigEntry<float> FixedTimerDuration;
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_0044: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Expected O, but got Unknown
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_01f2: Expected O, but got Unknown
//IL_024d: Unknown result type (might be due to invalid IL or missing references)
//IL_025a: Expected O, but got Unknown
//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
//IL_02b0: Expected O, but got Unknown
//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0308: Expected O, but got Unknown
//IL_0308: Expected O, but got Unknown
try
{
Logger = ((BaseUnityPlugin)this).Logger;
Instance = this;
Harmony val = new Harmony("sparroh.batchscrapping");
try
{
TrashMarkKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Keybinds", "Mark for Trash", (Key)34, "Key to toggle trash mark on upgrades");
ScrapHandlingMod.currentTrashKey = TrashMarkKey.Value;
TrashMarkKey.SettingChanged += delegate
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
ScrapHandlingMod.currentTrashKey = TrashMarkKey.Value;
};
ScrapHandlingMod.ScrapMarkedAction = delegate
{
ScrapHandlingMod.TryScrapMarkedUpgrades((MonoBehaviour)(object)this);
};
ScrapHandlingMod.ScrapNonFavoriteAction = delegate
{
ScrapHandlingMod.TryScrapNonFavoriteUpgrades((MonoBehaviour)(object)this);
};
EnableInstantScrapping = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Instant Scrap", false, "Enable instant scrapping without hold timer");
EnableFixedTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Fixed Scrap Time", false, "Use fixed scrap timer instead of default (ignored when Instant Scrap is on)");
FixedTimerDuration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Scrap Duration", 1f, "Duration in seconds for fixed scrap timer");
}
catch (Exception ex)
{
Logger.LogError((object)("Failed to setup configuration bindings: " + ex.Message));
}
try
{
InstantPatches.Initialize(EnableFixedTimer, FixedTimerDuration, EnableInstantScrapping);
}
catch (Exception ex2)
{
Logger.LogError((object)("Failed to initialize InstantScrapping: " + 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(Patches), "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(Patches), "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(Patches), "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(Patches), "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.");
}
}
catch (Exception ex4)
{
Logger.LogError((object)("Failed to apply scrap patches: " + ex4.Message));
}
}
catch (Exception ex5)
{
Logger.LogError((object)("Critical error during mod initialization: " + ex5.Message + "\n" + ex5.StackTrace));
}
Logger.LogInfo((object)"BatchScrapping v2.1.0 loaded successfully.");
}
private void Update()
{
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
{
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 static bool isScrapping;
private static bool wasScrappingSkins;
private const float HOLD_DURATION = 1f;
private const int BATCH_SIZE = 1000000;
private const float BATCH_INTERVAL = 0f;
private const float SPECIAL_REWARD_CHANCE = 0.02f;
public static Key currentTrashKey;
public static Action ScrapMarkedAction;
public static Action ScrapNonFavoriteAction;
public static Sprite starSprite;
private const byte FavoriteFlag = 1;
private const byte TrashMarkFlag = 32;
public static bool IsScrapping => isScrapping;
public static IEnumerator ScrapMarkedUpgrades()
{
Dictionary<PlayerResource, int> dictionary = new Dictionary<PlayerResource, int>();
int num = 0;
bool flag;
List<UpgradeInstance> list;
bool flag2;
try
{
if (isScrapping)
{
SparrohPlugin.Logger.LogWarning((object)"ScrapMarkedUpgrades: Already scrapping, aborting.");
yield break;
}
isScrapping = true;
SparrohPlugin.Logger.LogInfo((object)"Starting ScrapMarkedUpgrades operation.");
GearDetailsWindow val = Object.FindObjectOfType<GearDetailsWindow>();
if ((Object)(object)val == (Object)null)
{
SparrohPlugin.Logger.LogError((object)"ScrapMarkedUpgrades: GearDetailsWindow not found.");
isScrapping = false;
yield break;
}
IUpgradable upgradablePrefab = val.UpgradablePrefab;
if (upgradablePrefab == null)
{
SparrohPlugin.Logger.LogError((object)"ScrapMarkedUpgrades: UpgradablePrefab is null.");
isScrapping = false;
yield break;
}
bool num2 = (bool)AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode").GetValue(val);
flag = num2;
IEnumerable<UpgradeInfo> enumerable = (num2 ? PlayerData.GetAllSkins(upgradablePrefab, true) : PlayerData.GetAllUpgrades(upgradablePrefab, true));
int num3 = 0;
foreach (UpgradeInfo item in enumerable)
{
if (item?.Instances != null)
{
num3 += item.Instances.Count;
}
}
list = new List<UpgradeInstance>(num3);
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.");
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.");
PlayerResource key2 = default(PlayerResource);
PlayerResource key3 = default(PlayerResource);
foreach (KeyValuePair<Rarity, List<UpgradeInstance>> item4 in (from inst in list
group inst by inst.Upgrade.Rarity).ToDictionary((IGrouping<Rarity, UpgradeInstance> g) => g.Key, (IGrouping<Rarity, UpgradeInstance> g) => g.ToList()))
{
Rarity key = item4.Key;
int count = item4.Value.Count;
ref RarityData rarity = ref Global.GetRarity(key);
int num4 = rarity.upgradeScripCost / 6;
dictionary.TryGetValue(Global.Instance.ScripResource, out var value);
dictionary[Global.Instance.ScripResource] = value + num4 * count;
if (!flag)
{
dictionary.TryGetValue(rarity.scrapResource, out var value2);
dictionary[rarity.scrapResource] = value2 + 2 * count;
if (PlayerResource.TryGetResource("strange_comp", ref key2))
{
int num5 = Mathf.FloorToInt((float)count * 0.02f);
dictionary.TryGetValue(key2, out var value3);
dictionary[key2] = value3 + num5;
}
}
else if (PlayerResource.TryGetResource("oyster", ref key3))
{
int num6 = Mathf.FloorToInt((float)count * 0.02f);
dictionary.TryGetValue(key3, out var value4);
dictionary[key3] = value4 + num6;
}
}
flag2 = true;
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapMarkedUpgrades: Setup failed: " + ex.Message));
UndoPatches.CancelBatch();
isScrapping = false;
yield break;
}
if (flag2 && list != null)
{
for (int num7 = 0; num7 < list.Count; num7 += 1000000)
{
int num8 = Mathf.Min(num7 + 1000000, list.Count);
for (int num9 = num7; num9 < num8; num9++)
{
UpgradeInstance val2 = list[num9];
if (val2 != null && !((Object)(object)val2.Upgrade == (Object)null))
{
try
{
PlayerData.UnequipFromAll(val2);
}
catch
{
}
val2.Destroy();
num++;
}
}
}
}
try
{
foreach (KeyValuePair<PlayerResource, int> item5 in dictionary)
{
PlayerData.Instance.AddResource(item5.Key, item5.Value, true);
}
}
catch (Exception ex2)
{
SparrohPlugin.Logger.LogError((object)("ScrapMarkedUpgrades: Failed to add resources: " + ex2.Message));
}
if (num > 0)
{
UndoPatches.EndBatch();
try
{
wasScrappingSkins = flag;
RefreshOpenWindows();
}
catch (Exception ex3)
{
SparrohPlugin.Logger.LogError((object)("ScrapMarkedUpgrades: Failed to refresh windows: " + ex3.Message));
}
}
else
{
UndoPatches.CancelBatch();
}
isScrapping = false;
}
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<GearDetailsWindow>();
if ((Object)(object)val == (Object)null)
{
return;
}
IUpgradable upgradablePrefab = val.UpgradablePrefab;
if (upgradablePrefab == null)
{
return;
}
List<UpgradeInfo> 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()
{
Dictionary<PlayerResource, int> dictionary = new Dictionary<PlayerResource, int>();
int num = 0;
bool flag;
List<UpgradeInstance> list;
bool flag2;
try
{
if (isScrapping)
{
SparrohPlugin.Logger.LogWarning((object)"ScrapNonFavoriteUpgrades: Already scrapping, aborting.");
yield break;
}
isScrapping = true;
SparrohPlugin.Logger.LogInfo((object)"Starting ScrapNonFavoriteUpgrades operation.");
GearDetailsWindow val = Object.FindObjectOfType<GearDetailsWindow>();
if ((Object)(object)val == (Object)null)
{
SparrohPlugin.Logger.LogError((object)"ScrapNonFavoriteUpgrades: GearDetailsWindow not found.");
isScrapping = false;
yield break;
}
IUpgradable upgradablePrefab = val.UpgradablePrefab;
if (upgradablePrefab == null)
{
SparrohPlugin.Logger.LogError((object)"ScrapNonFavoriteUpgrades: UpgradablePrefab is null.");
isScrapping = false;
yield break;
}
bool num2 = (bool)AccessTools.Field(typeof(GearDetailsWindow), "inSkinMode").GetValue(val);
flag = num2;
IEnumerable<UpgradeInfo> enumerable = (num2 ? PlayerData.GetAllSkins(upgradablePrefab, true) : PlayerData.GetAllUpgrades(upgradablePrefab, true));
int num3 = 0;
foreach (UpgradeInfo item in enumerable)
{
if (item?.Instances != null)
{
num3 += item.Instances.Count;
}
}
list = new List<UpgradeInstance>(num3);
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.");
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.");
PlayerResource key2 = default(PlayerResource);
PlayerResource key3 = default(PlayerResource);
foreach (KeyValuePair<Rarity, List<UpgradeInstance>> item4 in (from inst in list
group inst by inst.Upgrade.Rarity).ToDictionary((IGrouping<Rarity, UpgradeInstance> g) => g.Key, (IGrouping<Rarity, UpgradeInstance> g) => g.ToList()))
{
Rarity key = item4.Key;
int count = item4.Value.Count;
ref RarityData rarity = ref Global.GetRarity(key);
int num4 = rarity.upgradeScripCost / 6;
dictionary.TryGetValue(Global.Instance.ScripResource, out var value);
dictionary[Global.Instance.ScripResource] = value + num4 * count;
if (!flag)
{
dictionary.TryGetValue(rarity.scrapResource, out var value2);
dictionary[rarity.scrapResource] = value2 + 2 * count;
if (PlayerResource.TryGetResource("strange_comp", ref key2))
{
int num5 = Mathf.FloorToInt((float)count * 0.02f);
dictionary.TryGetValue(key2, out var value3);
dictionary[key2] = value3 + num5;
}
}
else if (PlayerResource.TryGetResource("oyster", ref key3))
{
int num6 = Mathf.FloorToInt((float)count * 0.02f);
dictionary.TryGetValue(key3, out var value4);
dictionary[key3] = value4 + num6;
}
}
flag2 = true;
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapNonFavoriteUpgrades: Setup failed: " + ex.Message));
UndoPatches.CancelBatch();
isScrapping = false;
yield break;
}
if (flag2 && list != null)
{
for (int num7 = 0; num7 < list.Count; num7 += 1000000)
{
int num8 = Mathf.Min(num7 + 1000000, list.Count);
for (int num9 = num7; num9 < num8; num9++)
{
UpgradeInstance val2 = list[num9];
if (val2 != null && !((Object)(object)val2.Upgrade == (Object)null))
{
try
{
PlayerData.UnequipFromAll(val2);
}
catch
{
}
val2.Destroy();
num++;
}
}
}
}
try
{
foreach (KeyValuePair<PlayerResource, int> item5 in dictionary)
{
PlayerData.Instance.AddResource(item5.Key, item5.Value, true);
}
}
catch (Exception ex2)
{
SparrohPlugin.Logger.LogError((object)("ScrapNonFavoriteUpgrades: Failed to add resources: " + ex2.Message));
}
if (num > 0)
{
UndoPatches.EndBatch();
try
{
wasScrappingSkins = flag;
RefreshOpenWindows();
}
catch (Exception ex3)
{
SparrohPlugin.Logger.LogError((object)("ScrapNonFavoriteUpgrades: Failed to refresh windows: " + ex3.Message));
}
}
else
{
UndoPatches.CancelBatch();
}
isScrapping = false;
}
public static void TryScrapNonFavoriteUpgrades(MonoBehaviour owner)
{
GearDetailsWindow val = Object.FindObjectOfType<GearDetailsWindow>();
if ((Object)(object)val == (Object)null)
{
return;
}
IUpgradable upgradablePrefab = val.UpgradablePrefab;
if (upgradablePrefab == null)
{
return;
}
List<UpgradeInfo> 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 Patches
{
private static HashSet<UpgradeInstance> toggledThisSession = new HashSet<UpgradeInstance>();
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<RectTransform>();
GameObject val3 = new GameObject("ModScrapButtonMarked");
val3.transform.SetParent(((Component)window).transform, false);
RectTransform val4 = val3.AddComponent<RectTransform>();
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<Image>();
((Graphic)obj).color = Color.gray;
((Graphic)obj).raycastTarget = true;
Button obj2 = val3.AddComponent<Button>();
((Selectable)obj2).transition = (Transition)1;
ColorBlock colors = ((Selectable)obj2).colors;
((ColorBlock)(ref colors)).normalColor = Color.gray;
((ColorBlock)(ref colors)).highlightedColor = Color.white;
((ColorBlock)(ref colors)).pressedColor = Color.blue;
((Selectable)obj2).colors = colors;
GameObject val5 = new GameObject("Text");
val5.transform.SetParent(val3.transform, false);
val5.AddComponent<RectTransform>().sizeDelta = val4.sizeDelta;
TextMeshProUGUI obj3 = val5.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj3).text = "Scrap Marked";
((TMP_Text)obj3).alignment = (TextAlignmentOptions)514;
((Graphic)obj3).color = Color.white;
((TMP_Text)obj3).fontSize = 24f;
val3.AddComponent<HoldButtonHandler>().onHoldComplete = ScrapHandlingMod.ScrapMarkedAction;
GameObject val6 = new GameObject("ModScrapButtonNonFavorite");
val6.transform.SetParent(((Component)window).transform, false);
RectTransform val7 = val6.AddComponent<RectTransform>();
val7.sizeDelta = new Vector2(250f, 50f);
val7.anchorMin = new Vector2(1f, 0f);
val7.anchorMax = new Vector2(1f, 0f);
val7.pivot = new Vector2(1f, 0f);
val7.anchoredPosition = new Vector2(val4.anchoredPosition.x + 210f, 50f);
Image obj4 = val6.AddComponent<Image>();
((Graphic)obj4).color = Color.red;
((Graphic)obj4).raycastTarget = true;
Button obj5 = val6.AddComponent<Button>();
((Selectable)obj5).transition = (Transition)1;
ColorBlock colors2 = ((Selectable)obj5).colors;
((ColorBlock)(ref colors2)).normalColor = Color.red;
((ColorBlock)(ref colors2)).highlightedColor = Color.white;
((ColorBlock)(ref colors2)).pressedColor = Color.blue;
((Selectable)obj5).colors = colors2;
GameObject val8 = new GameObject("Text");
val8.transform.SetParent(val6.transform, false);
val8.AddComponent<RectTransform>().sizeDelta = val7.sizeDelta;
TextMeshProUGUI obj6 = val8.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj6).text = "Scrap All Non-Favorite";
((TMP_Text)obj6).alignment = (TextAlignmentOptions)514;
((Graphic)obj6).color = Color.white;
((TMP_Text)obj6).fontSize = 20f;
val6.AddComponent<HoldButtonHandler>().onHoldComplete = ScrapHandlingMod.ScrapNonFavoriteAction;
}
public static void UpdateFavoriteIconPostfix(GearUpgradeUI __instance)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Expected O, but got Unknown
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (ScrapHandlingMod.IsScrapping)
{
return;
}
Image val = (Image)AccessTools.Field(typeof(GearUpgradeUI), "favoriteIcon").GetValue(__instance);
if ((Object)(object)val != (Object)null && ((HoverInfoUpgrade)__instance).Upgrade != null)
{
bool num = ScrapHandlingMod.IsFavorite(((HoverInfoUpgrade)__instance).Upgrade);
bool flag = ScrapHandlingMod.IsTrashMarked(((HoverInfoUpgrade)__instance).Upgrade);
if (num)
{
ScrapHandlingMod.starSprite = val.sprite;
((Component)val).gameObject.SetActive(true);
((Graphic)val).color = Color.white;
}
else if (flag)
{
val.sprite = ScrapHandlingMod.starSprite ?? Resources.Load<Sprite>("favorite star");
((Component)val).gameObject.SetActive(true);
((Graphic)val).color = Color.red;
Canvas.ForceUpdateCanvases();
}
else
{
((Component)val).gameObject.SetActive(false);
}
}
}
public static void OnAdditionalActionPostfix(GearUpgradeUI __instance, int index, ref bool refreshUI)
{
if (index == 0 && ((HoverInfoUpgrade)__instance).Upgrade != null)
{
ScrapHandlingMod.SetFavorite(((HoverInfoUpgrade)__instance).Upgrade, ((HoverInfoUpgrade)__instance).Upgrade.Favorite);
}
}
public static void EnableGridViewPostfix(GearUpgradeUI __instance, bool grid)
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
if (!ScrapHandlingMod.IsScrapping && ((HoverInfoUpgrade)__instance).Upgrade != null)
{
Image val = (Image)AccessTools.Field(typeof(GearUpgradeUI), "favoriteIcon").GetValue(__instance);
if (((Component)val).gameObject.activeSelf)
{
((Graphic)val).color = (ScrapHandlingMod.IsFavorite(((HoverInfoUpgrade)__instance).Upgrade) ? Color.white : Color.red);
}
}
}
public static void UpdatePrefix(GearDetailsWindow __instance)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Expected O, but got Unknown
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
if (ScrapHandlingMod.IsScrapping || Keyboard.current == null)
{
return;
}
if (!((ButtonControl)Keyboard.current[ScrapHandlingMod.currentTrashKey]).isPressed)
{
if (toggledThisSession.Count > 0)
{
toggledThisSession.Clear();
}
return;
}
GearUpgradeUI val = null;
if (!UIRaycaster.RaycastForComponent<GearUpgradeUI>(ref val))
{
return;
}
UpgradeInstance upgrade = ((HoverInfoUpgrade)val).Upgrade;
if (upgrade == null || ScrapHandlingMod.IsFavorite(upgrade) || toggledThisSession.Contains(upgrade))
{
return;
}
bool flag = ScrapHandlingMod.IsTrashMarked(upgrade);
ScrapHandlingMod.SetTrashMark(upgrade, !flag);
toggledThisSession.Add(upgrade);
Image val2 = (Image)(AccessTools.Field(typeof(GearUpgradeUI), "favoriteIcon")?.GetValue(val));
if ((Object)(object)val2 != (Object)null)
{
if (ScrapHandlingMod.IsFavorite(upgrade))
{
val2.sprite = ScrapHandlingMod.starSprite;
((Component)val2).gameObject.SetActive(true);
((Graphic)val2).color = Color.white;
}
else if (ScrapHandlingMod.IsTrashMarked(upgrade))
{
val2.sprite = ScrapHandlingMod.starSprite;
((Component)val2).gameObject.SetActive(true);
((Graphic)val2).color = Color.red;
}
else
{
((Component)val2).gameObject.SetActive(false);
}
Canvas.ForceUpdateCanvases();
}
}
}
public class HoldButtonHandler : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IPointerUpHandler
{
private bool isHolding;
private float holdTimer;
private const float HOLD_DURATION = 1f;
public Action onHoldComplete;
public void OnPointerDown(PointerEventData eventData)
{
isHolding = true;
holdTimer = 0f;
}
public void OnPointerUp(PointerEventData eventData)
{
isHolding = false;
}
private void Update()
{
if (isHolding)
{
holdTimer += Time.deltaTime;
if (holdTimer >= 1f)
{
onHoldComplete?.Invoke();
isHolding = false;
}
}
}
}
public static class UndoPatches
{
public sealed class UpgradeSnapshot
{
public IUpgradable Gear;
public Upgrade Upgrade;
public int Seed;
public byte Flags;
public bool IsUnlocked;
public bool HasBeenSeen;
public bool RemoveOnQuit;
public UpgradeID OverriddenPattern;
public bool WasEquipped;
public IUpgradable EquippedOnGear;
public sbyte EquipX;
public sbyte EquipY;
public byte EquipRotation;
}
public sealed class ScrapAction
{
public List<UpgradeSnapshot> Upgrades = new List<UpgradeSnapshot>();
public Dictionary<PlayerResource, int> ResourcesGranted = new Dictionary<PlayerResource, int>();
public string Description;
}
public const int MaxDepth = 5;
private static readonly List<ScrapAction> undoList = new List<ScrapAction>(5);
private static readonly FieldInfo flagsField = AccessTools.Field(typeof(UpgradeInstance), "flags");
private static readonly PropertyInfo hasBeenSeenProp = AccessTools.Property(typeof(UpgradeInstance), "HasBeenSeen");
private static readonly PropertyInfo seedProp = AccessTools.Property(typeof(UpgradeInstance), "Seed");
private static readonly PropertyInfo removeOnQuitProp = AccessTools.Property(typeof(UpgradeInstance), "RemoveOnQuit");
private static ScrapAction pendingBatch;
private static Dictionary<PlayerResource, int> resourceBaseline;
private static readonly Queue<ScrapAction> deferredActions = new Queue<ScrapAction>();
private static bool flushScheduled;
public static int UndoCount => undoList.Count;
public static bool CanUndo => undoList.Count > 0;
public static void Clear()
{
undoList.Clear();
deferredActions.Clear();
flushScheduled = false;
pendingBatch = null;
resourceBaseline = null;
}
public static UpgradeSnapshot CaptureUpgrade(UpgradeInstance instance)
{
//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)
if (instance == null)
{
return null;
}
Upgrade upgrade;
try
{
upgrade = instance.Upgrade;
}
catch
{
return null;
}
if ((Object)(object)upgrade == (Object)null)
{
return null;
}
UpgradeSnapshot upgradeSnapshot = new UpgradeSnapshot
{
Gear = instance.Gear,
Upgrade = upgrade,
Seed = instance.Seed,
Flags = (byte)((flagsField != null) ? ((byte)flagsField.GetValue(instance)) : 0),
IsUnlocked = instance.IsUnlocked,
HasBeenSeen = instance.HasBeenSeen,
RemoveOnQuit = instance.RemoveOnQuit,
OverriddenPattern = instance.OverriddenPattern,
WasEquipped = false
};
try
{
IUpgradable gear = instance.Gear;
sbyte equipX = default(sbyte);
sbyte equipY = default(sbyte);
byte equipRotation = default(byte);
if (gear != null && instance.IsEquipped(gear) && instance.GetPosition(gear, ref equipX, ref equipY, ref equipRotation))
{
upgradeSnapshot.WasEquipped = true;
upgradeSnapshot.EquippedOnGear = gear;
upgradeSnapshot.EquipX = equipX;
upgradeSnapshot.EquipY = equipY;
upgradeSnapshot.EquipRotation = equipRotation;
}
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogWarning((object)("ScrapUndo: failed to capture equip state: " + ex.Message));
}
return upgradeSnapshot;
}
public static Dictionary<PlayerResource, int> SnapshotResources()
{
Dictionary<PlayerResource, int> dictionary = new Dictionary<PlayerResource, int>();
try
{
if (PlayerData.Instance == null)
{
return dictionary;
}
if (Global.Instance?.PlayerResources != null)
{
PlayerResource[] playerResources = Global.Instance.PlayerResources;
foreach (PlayerResource val in playerResources)
{
if (!((Object)(object)val == (Object)null))
{
dictionary[val] = PlayerData.Instance.GetResource(val);
}
}
}
TryTrack(dictionary, "strange_comp");
TryTrack(dictionary, "oyster");
TryTrack(dictionary, "ouroscrap");
TryTrack(dictionary, "ourosample");
Global instance = Global.Instance;
if ((Object)(object)((instance != null) ? instance.ScripResource : null) != (Object)null)
{
dictionary[Global.Instance.ScripResource] = PlayerData.Instance.GetResource(Global.Instance.ScripResource);
}
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogWarning((object)("ScrapUndo: resource snapshot failed: " + ex.Message));
}
return dictionary;
}
private static void TryTrack(Dictionary<PlayerResource, int> dict, string name)
{
PlayerResource val = default(PlayerResource);
if (PlayerResource.TryGetResource(name, ref val) && (Object)(object)val != (Object)null)
{
dict[val] = PlayerData.Instance.GetResource(val);
}
}
public static Dictionary<PlayerResource, int> DiffResources(Dictionary<PlayerResource, int> before, Dictionary<PlayerResource, int> after)
{
Dictionary<PlayerResource, int> dictionary = new Dictionary<PlayerResource, int>();
if (before == null || after == null)
{
return dictionary;
}
foreach (KeyValuePair<PlayerResource, int> item in after)
{
before.TryGetValue(item.Key, out var value);
int num = item.Value - value;
if (num > 0)
{
dictionary[item.Key] = num;
}
}
return dictionary;
}
public static void PushAction(ScrapAction action)
{
if (action == null || action.Upgrades == null || action.Upgrades.Count == 0)
{
return;
}
try
{
while (undoList.Count >= 5)
{
undoList.RemoveAt(0);
}
undoList.Add(action);
SparrohPlugin.Logger.LogInfo((object)$"ScrapUndo: recorded action ({action.Upgrades.Count} upgrade(s)). Stack depth: {undoList.Count}/{5}");
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo PushAction failed: " + ex.Message));
}
}
public static void PushSingle(UpgradeSnapshot snap, Dictionary<PlayerResource, int> resourcesGranted)
{
if (snap != null)
{
PushAction(new ScrapAction
{
Description = (((Object)(object)snap.Upgrade != (Object)null) ? snap.Upgrade.Name : "upgrade"),
ResourcesGranted = (resourcesGranted ?? new Dictionary<PlayerResource, int>()),
Upgrades = { snap }
});
}
}
public static void QueueSingleDeferred(UpgradeSnapshot snap, Dictionary<PlayerResource, int> resourcesBefore)
{
if (snap == null)
{
return;
}
try
{
Dictionary<PlayerResource, int> after = SnapshotResources();
Dictionary<PlayerResource, int> resourcesGranted = DiffResources(resourcesBefore, after);
ScrapAction scrapAction = new ScrapAction
{
Description = (((Object)(object)snap.Upgrade != (Object)null) ? snap.Upgrade.Name : "upgrade"),
ResourcesGranted = resourcesGranted
};
scrapAction.Upgrades.Add(snap);
deferredActions.Enqueue(scrapAction);
ScheduleFlush();
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo QueueSingleDeferred failed: " + ex.Message));
}
}
private static void ScheduleFlush()
{
if (!flushScheduled && !((Object)(object)SparrohPlugin.Instance == (Object)null))
{
flushScheduled = true;
((MonoBehaviour)SparrohPlugin.Instance).StartCoroutine(FlushDeferredNextFrame());
}
}
private static IEnumerator FlushDeferredNextFrame()
{
yield return null;
flushScheduled = false;
try
{
while (deferredActions.Count > 0)
{
PushAction(deferredActions.Dequeue());
}
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo flush failed: " + ex.Message));
deferredActions.Clear();
}
}
public static void BeginBatch(string description)
{
pendingBatch = new ScrapAction
{
Description = description
};
resourceBaseline = SnapshotResources();
}
public static void AddToBatch(UpgradeInstance instance)
{
if (pendingBatch != null)
{
UpgradeSnapshot upgradeSnapshot = CaptureUpgrade(instance);
if (upgradeSnapshot != null)
{
pendingBatch.Upgrades.Add(upgradeSnapshot);
}
}
}
public static void EndBatch()
{
if (pendingBatch == null)
{
return;
}
try
{
Dictionary<PlayerResource, int> after = SnapshotResources();
pendingBatch.ResourcesGranted = DiffResources(resourceBaseline, after);
if (pendingBatch.Upgrades.Count > 0)
{
PushAction(pendingBatch);
}
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo EndBatch failed: " + ex.Message));
}
pendingBatch = null;
resourceBaseline = null;
}
public static void CancelBatch()
{
pendingBatch = null;
resourceBaseline = null;
}
public static bool TryUndo()
{
if (undoList.Count == 0)
{
SparrohPlugin.Logger.LogInfo((object)"ScrapUndo: nothing to undo.");
return false;
}
int index = undoList.Count - 1;
ScrapAction scrapAction = undoList[index];
undoList.RemoveAt(index);
int num = 0;
try
{
if (scrapAction?.Upgrades != null)
{
foreach (UpgradeSnapshot upgrade in scrapAction.Upgrades)
{
if (RestoreUpgrade(upgrade))
{
num++;
}
}
}
if (scrapAction?.ResourcesGranted != null)
{
foreach (KeyValuePair<PlayerResource, int> item in scrapAction.ResourcesGranted)
{
if (!((Object)(object)item.Key == (Object)null) && item.Value > 0)
{
int num2 = Mathf.Min(PlayerData.Instance.GetResource(item.Key), item.Value);
if (num2 > 0)
{
PlayerData.Instance.TryRemoveResource(item.Key, num2);
}
}
}
}
RefreshOpenWindows();
SparrohPlugin.Logger.LogInfo((object)$"ScrapUndo: restored {num}/{(scrapAction?.Upgrades?.Count).GetValueOrDefault()} upgrade(s). Remaining stack: {undoList.Count}");
return num > 0;
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo: undo failed: " + ex.Message + "\n" + ex.StackTrace));
return false;
}
}
private static bool RestoreUpgrade(UpgradeSnapshot snap)
{
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (snap == null || snap.Gear == null || (Object)(object)snap.Upgrade == (Object)null)
{
return false;
}
try
{
UpgradeInstance val = PlayerData.CreateUpgradeInstance(snap.Gear, snap.Upgrade, false);
if (val == null)
{
return false;
}
if (seedProp != null)
{
seedProp.SetValue(val, snap.Seed);
}
if (flagsField != null)
{
flagsField.SetValue(val, snap.Flags);
}
if (removeOnQuitProp != null)
{
removeOnQuitProp.SetValue(val, snap.RemoveOnQuit);
}
val.OverriddenPattern = snap.OverriddenPattern;
PlayerData.CollectInstance(val, (UnlockFlags)1);
if (snap.IsUnlocked)
{
val.Unlock(true);
}
else
{
val.Lock();
}
if (hasBeenSeenProp != null)
{
hasBeenSeenProp.SetValue(val, snap.HasBeenSeen);
}
if (flagsField != null)
{
flagsField.SetValue(val, snap.Flags);
}
if (snap.WasEquipped && snap.EquippedOnGear != null)
{
try
{
val.Equip(snap.EquippedOnGear, snap.EquipX, snap.EquipY, snap.EquipRotation, true, false);
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogWarning((object)("ScrapUndo: re-equip failed: " + ex.Message));
}
}
return true;
}
catch (Exception ex2)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo: restore upgrade failed: " + ex2.Message));
return false;
}
}
private static void RefreshOpenWindows()
{
try
{
if ((Object)(object)Menu.Instance != (Object)null && Menu.Instance.IsOpen)
{
Window top = Menu.Instance.WindowSystem.GetTop();
if ((Object)(object)top != (Object)null)
{
top.OnOpen(Menu.Instance.WindowSystem);
}
}
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogWarning((object)("ScrapUndo: window refresh failed: " + ex.Message));
}
}
}
public static class ScrapUndoPatches
{
private struct Pending
{
public UpgradeInstance Instance;
public UndoPatches.UpgradeSnapshot Snap;
public Dictionary<PlayerResource, int> ResourcesBefore;
}
private static readonly Stack<Pending> pendingStack = new Stack<Pending>();
public static void DismantlePrefix(GearUpgradeUI __instance)
{
try
{
if ((Object)(object)__instance == (Object)null)
{
return;
}
UpgradeInstance upgrade = ((HoverInfoUpgrade)__instance).Upgrade;
if (upgrade != null && !upgrade.Favorite)
{
UndoPatches.UpgradeSnapshot upgradeSnapshot = UndoPatches.CaptureUpgrade(upgrade);
if (upgradeSnapshot != null)
{
pendingStack.Push(new Pending
{
Instance = upgrade,
Snap = upgradeSnapshot,
ResourcesBefore = UndoPatches.SnapshotResources()
});
}
}
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo DismantlePrefix: " + ex.Message));
}
}
public static void DismantlePostfix(GearUpgradeUI __instance)
{
try
{
if (pendingStack.Count == 0)
{
return;
}
Pending pending = pendingStack.Pop();
if (pending.Instance != null && pending.Snap != null)
{
bool flag;
try
{
flag = pending.Instance.IsDestroyed();
}
catch
{
flag = true;
}
if (flag)
{
UndoPatches.QueueSingleDeferred(pending.Snap, pending.ResourcesBefore);
}
}
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("ScrapUndo DismantlePostfix: " + ex.Message));
if (pendingStack.Count > 0)
{
try
{
pendingStack.Pop();
return;
}
catch
{
return;
}
}
}
}
}
namespace BatchScrapping
{
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "BatchScrapping";
public const string PLUGIN_NAME = "BatchScrapping";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}