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 SelfSortingStoragePLUS v1.0.0
plugins/bobabulker.SelfSortingStoragePLUS.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; 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 SelfSortingStorage.Cupboard; using SelfSortingStoragePLUS.Patches; using Unity.Netcode; 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("bobabulker.SelfSortingStoragePLUS")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+7fd6b554aaf8bef849a0586ca749b5ec5b1a56d0")] [assembly: AssemblyProduct("SelfSortingStoragePLUS")] [assembly: AssemblyTitle("bobabulker.SelfSortingStoragePLUS")] [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.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] [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] [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 SelfSortingStoragePLUS { [BepInPlugin("bobabulker.SelfSortingStoragePLUS", "SelfSortingStoragePLUS", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SelfSortingStoragePLUS : BaseUnityPlugin { public static SelfSortingStoragePLUS Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } internal static Harmony? Harmony { get; private set; } internal static ConfigEntry<string> AutoStoreMoons { get; private set; } internal static ConfigEntry<bool> ProtectCupboardItems { get; private set; } internal static ConfigEntry<bool> VerboseLogging { get; private set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; AutoStoreMoons = ((BaseUnityPlugin)this).Config.Bind<string>("Terminal Purchases", "AutoStoreMoons", "71 Gordion", "Comma-separated list of moons where terminal purchases should be automatically stored in the SelfSortingStorage cupboard when possible (e.g. \"71 Gordion, Experimentation\"). A moon matches if its name contains any entry in this list, case-insensitive, so \"Gordion\" also matches \"71 Gordion\". Leave blank to disable AutoStore on every moon."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Verbose Logging", "Log Info", false, "Enable to get information logging on different stages of the patch."); ProtectCupboardItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Team Wipe Protection", "ProtectCupboardItems", true, "If enabled, items stored in the Smart Cupboard are hidden from RoundManager's end-of-round despawn sweep, so they're never destroyed by it for any reason -- including the team wipe case, where vanilla destroys all scrap regardless of whether it's safely on the ship."); Patch(); Logger.LogInfo((object)"bobabulker.SelfSortingStoragePLUS v1.0.0 has loaded!"); } internal static void Patch() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("bobabulker.SelfSortingStoragePLUS"); } Harmony.PatchAll(); EndOfRoundCupboardEffectsPatch.TryPatch(Harmony); Logger.LogDebug((object)"Finished patching!"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } internal static bool IsAutoStoreEnabledOnCurrentMoon() { string value = AutoStoreMoons.Value; if (string.IsNullOrWhiteSpace(value)) { return false; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (!instance.shipHasLanded) { if (VerboseLogging.Value) { Logger.LogInfo((object)"[AutoStoreMoons] Ship has not landed yet. Using normal dropship storage."); } return false; } string text = instance.currentLevel?.PlanetName; if (string.IsNullOrEmpty(text)) { if (VerboseLogging.Value) { Logger.LogInfo((object)"[AutoStoreMoons] Could not determine the current moon. Using normal dropship storage."); } return false; } string[] array = value.Split(','); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.Length != 0 && text.IndexOf(text3, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } if (VerboseLogging.Value) { Logger.LogInfo((object)("[AutoStoreMoons] AutoStore is not enabled for the current moon \"" + text + "\". Using normal dropship storage.")); } return false; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "bobabulker.SelfSortingStoragePLUS"; public const string PLUGIN_NAME = "SelfSortingStoragePLUS"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace SelfSortingStoragePLUS.Patches { [HarmonyPatch(typeof(Terminal))] internal static class BuyItemsServerRpcPatch { private static FieldInfo? PlacedItemsField; private static MethodInfo? SpawnItemMethod; private static MethodInfo? PlayDropSFXMethod; private static MethodInfo? UpdateNetworkQuantityMethod; private static MethodInfo? UpdateDisplayedQuantityMethod; private static MethodInfo? SetSizeMethod; private static bool ResolveSssMembers() { if (PlacedItemsField != null && SpawnItemMethod != null && PlayDropSFXMethod != null && UpdateNetworkQuantityMethod != null && UpdateDisplayedQuantityMethod != null && SetSizeMethod != null) { return true; } Type typeFromHandle = typeof(SmartCupboard); PlacedItemsField = AccessTools.Field(typeFromHandle, "placedItems"); SpawnItemMethod = AccessTools.Method(typeFromHandle, "SpawnItem", new Type[3] { typeof(Data), typeof(int), typeof(bool) }, (Type[])null); PlayDropSFXMethod = AccessTools.Method(typeFromHandle, "PlayDropSFXClientRpc", new Type[1] { typeof(NetworkObjectReference) }, (Type[])null); UpdateNetworkQuantityMethod = AccessTools.Method(typeFromHandle, "UpdateNetworkQuantityClientRpc", new Type[2] { typeof(ulong), typeof(bool) }, (Type[])null); UpdateDisplayedQuantityMethod = AccessTools.Method(typeFromHandle, "UpdateDisplayedQuantityClientRpc", new Type[2] { typeof(int), typeof(int) }, (Type[])null); SetSizeMethod = AccessTools.Method(typeFromHandle, "SetSizeClientRpc", new Type[1] { typeof(int) }, (Type[])null); bool flag = PlacedItemsField != null && SpawnItemMethod != null && PlayDropSFXMethod != null && UpdateNetworkQuantityMethod != null && UpdateDisplayedQuantityMethod != null && SetSizeMethod != null; if (!flag) { SelfSortingStoragePLUS.Logger.LogError((object)"[AutoStoreTerminalPurchases] Could not resolve one or more SelfSortingStorage 1.5.3 private methods/fields."); SelfSortingStoragePLUS.Logger.LogError((object)($"[AutoStoreTerminalPurchases] placedItems={PlacedItemsField != null}, " + $"SpawnItem={SpawnItemMethod != null}, " + $"PlayDropSFXClientRpc={PlayDropSFXMethod != null}, " + $"UpdateNetworkQuantityClientRpc={UpdateNetworkQuantityMethod != null}, " + $"UpdateDisplayedQuantityClientRpc={UpdateDisplayedQuantityMethod != null}, " + $"SetSizeClientRpc={SetSizeMethod != null}")); } return flag; } private static SmartCupboard? FindCupboard() { SmartCupboard[] array = Object.FindObjectsOfType<SmartCupboard>(); SmartCupboard[] array2 = array; foreach (SmartCupboard val in array2) { if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).IsSpawned && ((NetworkBehaviour)val).IsServer) { return val; } } return null; } [HarmonyPatch("BuyItemsServerRpc")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(List<int>), "AddRange", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(BuyItemsServerRpcPatch), "HandlePurchasedItems", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { SelfSortingStoragePLUS.Logger.LogError((object)"[AutoStoreTerminalPurchases] Could not resolve terminal purchase patch methods."); return list; } for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], methodInfo)) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo2); SelfSortingStoragePLUS.Logger.LogDebug((object)"[AutoStoreTerminalPurchases] Successfully replaced terminal purchase AddRange()."); return list; } } SelfSortingStoragePLUS.Logger.LogWarning((object)"[AutoStoreTerminalPurchases] Could not find terminal purchase AddRange()."); return list; } [HarmonyPatch("LoadNewNodeIfAffordable")] [HarmonyPrefix] private static void LoadNewNodeIfAffordablePrefix(Terminal __instance, TerminalNode node, out int __state) { __state = ((((NetworkBehaviour)__instance).IsServer && node.buyItemIndex != -1) ? __instance.orderedItemsFromTerminal.Count : (-1)); } [HarmonyPatch("LoadNewNodeIfAffordable")] [HarmonyPostfix] private static void LoadNewNodeIfAffordablePostfix(Terminal __instance, TerminalNode node, int __state) { if (__state < 0) { return; } int num = __instance.orderedItemsFromTerminal.Count - __state; if (num > 0) { List<int> range = __instance.orderedItemsFromTerminal.GetRange(__state, num); __instance.orderedItemsFromTerminal.RemoveRange(__state, num); int count = __instance.orderedItemsFromTerminal.Count; HandlePurchasedItems(__instance.orderedItemsFromTerminal, range); int num2 = __instance.orderedItemsFromTerminal.Count - count; int num3 = num - num2; if (num3 > 0) { __instance.numberOfItemsInDropship -= num3; __instance.SyncGroupCreditsClientRpc(__instance.groupCredits, __instance.numberOfItemsInDropship); } } } private static void HandlePurchasedItems(List<int> orderedItems, List<int> boughtItems) { //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown if (boughtItems == null || boughtItems.Count == 0) { return; } if (!SelfSortingStoragePLUS.IsAutoStoreEnabledOnCurrentMoon()) { orderedItems.AddRange(boughtItems); return; } if (!ResolveSssMembers()) { orderedItems.AddRange(boughtItems); return; } SmartCupboard val = FindCupboard(); if ((Object)(object)val == (Object)null) { SelfSortingStoragePLUS.Logger.LogWarning((object)"[AutoStoreTerminalPurchases] No spawned server-side Smart Cupboard found. Using normal dropship storage."); orderedItems.AddRange(boughtItems); return; } Terminal val2 = Object.FindObjectOfType<Terminal>(); if ((Object)(object)val2 == (Object)null) { orderedItems.AddRange(boughtItems); return; } Dictionary<int, int> dictionary = new Dictionary<int, int>(); List<int> list = new List<int>(); foreach (int boughtItem in boughtItems) { if (dictionary.TryGetValue(boughtItem, out var value)) { dictionary[boughtItem] = value + 1; continue; } dictionary[boughtItem] = 1; list.Add(boughtItem); } int num6 = default(int); foreach (int item in list) { int num = dictionary[item]; try { if (item < 0 || item >= val2.buyableItemsList.Length) { for (int i = 0; i < num; i++) { orderedItems.Add(item); } continue; } Item val3 = val2.buyableItemsList[item]; if ((Object)(object)val3 == (Object)null || (Object)(object)val3.spawnPrefab == (Object)null) { for (int j = 0; j < num; j++) { orderedItems.Add(item); } continue; } GrabbableObject component = val3.spawnPrefab.GetComponent<GrabbableObject>(); if ((Object)(object)component == (Object)null) { for (int k = 0; k < num; k++) { orderedItems.Add(item); } continue; } Data val4 = new Data(component); List<Data> list2 = new List<Data>(num); for (int l = 0; l < num; l++) { Data val5 = new Data(component); if (val3.isScrap) { int num2 = Mathf.Min(val3.minValue, val3.maxValue); int num3 = Mathf.Max(val3.minValue, val3.maxValue); int num4 = Random.Range(num2, num3 + 1); val5.Values[0] = (((Object)(object)RoundManager.Instance != (Object)null) ? Mathf.RoundToInt((float)num4 * RoundManager.Instance.scrapValueMultiplier) : num4); } list2.Add(val5); } bool flag = false; int num5 = -1; for (int m = 0; m < list2.Count; m++) { bool flag2 = val.memory.StoreData(list2[m], ref num6, false); if (m == 0) { flag = flag2; num5 = num6; } else if (flag2) { SelfSortingStoragePLUS.Logger.LogWarning((object)("[AutoStoreTerminalPurchases] Batch purchase for " + val3.itemName + " unexpectedly created another " + $"cupboard slot at index {num6}.")); orderedItems.Add(item); } } if (val.memory.IsFull()) { SetSizeMethod.Invoke(val, new object[1] { val.memory.Size }); } if (flag) { val4 = list2[0]; val4.Quantity = num; SpawnItemMethod.Invoke(val, new object[3] { val4, num5, false }); } else { HandleStackedItem(val, num5, num); } } catch (Exception arg) { SelfSortingStoragePLUS.Logger.LogError((object)("[AutoStoreTerminalPurchases] Failed to store purchased " + $"item index {item}: {arg}")); for (int n = 0; n < num; n++) { orderedItems.Add(item); } } } } private static void HandleStackedItem(SmartCupboard cupboard, int spawnIndex, int quantityToAdd) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (PlacedItemsField == null) { return; } object value = PlacedItemsField.GetValue(cupboard); if (!(value is Dictionary<int, GrabbableObject> dictionary) || !dictionary.TryGetValue(spawnIndex, out var value2) || (Object)(object)value2 == (Object)null) { return; } if (PlayDropSFXMethod != null && (Object)(object)((NetworkBehaviour)value2).NetworkObject != (Object)null) { PlayDropSFXMethod.Invoke(cupboard, new object[1] { (object)new NetworkObjectReference(((NetworkBehaviour)value2).NetworkObject) }); } if (UpdateNetworkQuantityMethod != null && (Object)(object)((NetworkBehaviour)value2).NetworkObject != (Object)null) { for (int i = 0; i < quantityToAdd; i++) { UpdateNetworkQuantityMethod.Invoke(cupboard, new object[2] { ((NetworkBehaviour)value2).NetworkObjectId, false }); } } if (!(UpdateDisplayedQuantityMethod != null)) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(SmartMemory), "ItemList"); if (!(fieldInfo != null)) { return; } object value3 = fieldInfo.GetValue(cupboard.memory); if (!(value3 is List<List<Data>> { Count: >0 } list) || list[0].Count <= 0) { return; } int count = list[0].Count; int num = spawnIndex / count; int num2 = spawnIndex % count; if (num >= 0 && num < list.Count && num2 >= 0 && num2 < list[num].Count) { Data val = list[num][num2]; if (val.IsValid()) { UpdateDisplayedQuantityMethod.Invoke(cupboard, new object[2] { spawnIndex, val.Quantity }); } } } private static bool TryGetDisplayedQuantity(SmartCupboard cupboard, int spawnIndex, out int quantity) { quantity = 0; if (PlacedItemsField == null) { return false; } object value = PlacedItemsField.GetValue(cupboard); if (!(value is Dictionary<int, GrabbableObject> dictionary)) { return false; } if (!dictionary.TryGetValue(spawnIndex, out var value2) || (Object)(object)value2 == (Object)null) { return false; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(SmartMemory), "ItemList"); if (fieldInfo == null) { return false; } object value3 = fieldInfo.GetValue(cupboard.memory); if (!(value3 is List<List<Data>> list)) { return false; } int num = ((list.Count > 0) ? list[0].Count : 0); if (num <= 0) { return false; } int num2 = spawnIndex / num; int num3 = spawnIndex % num; if (num2 < 0 || num2 >= list.Count || num3 < 0 || num3 >= list[num2].Count) { return false; } Data val = list[num2][num3]; if (!val.IsValid()) { return false; } quantity = Math.Max(0, val.Quantity - GetCurrentPurchaseQuantity(cupboard)); return true; } catch { return false; } } private static int GetCurrentPurchaseQuantity(SmartCupboard cupboard) { return 0; } } [HarmonyPatch(typeof(RoundManager))] internal static class DespawnPropsAtEndOfRoundPatch { private static FieldInfo? PlacedItemsField; private static FieldInfo? SpawnedSyncedObjectsField; private static bool ResolvedSpawnedSyncedObjectsField; private static readonly List<GameObject> HiddenItems = new List<GameObject>(); private static bool ResolvePlacedItemsField() { if (PlacedItemsField != null) { return true; } PlacedItemsField = AccessTools.Field(typeof(SmartCupboard), "placedItems"); if (PlacedItemsField == null) { SelfSortingStoragePLUS.Logger.LogError((object)"[ProtectCupboardItems] Could not resolve SelfSortingStorage's private placedItems field. Cupboard contents will not be protected from the end-of-round despawn sweep."); } return PlacedItemsField != null; } [HarmonyPatch("DespawnPropsAtEndOfRound")] [HarmonyPrefix] private static void Prefix() { HiddenItems.Clear(); if (!SelfSortingStoragePLUS.ProtectCupboardItems.Value || !ResolvePlacedItemsField()) { return; } SmartCupboard[] array = Object.FindObjectsOfType<SmartCupboard>(); foreach (SmartCupboard obj in array) { if (!(PlacedItemsField.GetValue(obj) is Dictionary<int, GrabbableObject> dictionary)) { continue; } foreach (GrabbableObject value in dictionary.Values) { if (!((Object)(object)value == (Object)null) && !((Object)(object)((Component)value).gameObject == (Object)null) && ((Component)value).gameObject.activeSelf) { ((Component)value).gameObject.SetActive(false); HiddenItems.Add(((Component)value).gameObject); } } } if (HiddenItems.Count > 0 && SelfSortingStoragePLUS.VerboseLogging.Value) { SelfSortingStoragePLUS.Logger.LogInfo((object)($"[ProtectCupboardItems] Hiding {HiddenItems.Count} stored item(s) " + "from the end-of-round despawn sweep.")); } } [HarmonyPatch("DespawnPropsAtEndOfRound")] [HarmonyPostfix] private static void Postfix(RoundManager __instance) { if (HiddenItems.Count == 0) { return; } if (!ResolvedSpawnedSyncedObjectsField) { SpawnedSyncedObjectsField = AccessTools.Field(typeof(RoundManager), "spawnedSyncedObjects"); ResolvedSpawnedSyncedObjectsField = true; } ICollection<GameObject> collection = SpawnedSyncedObjectsField?.GetValue(__instance) as ICollection<GameObject>; foreach (GameObject hiddenItem in HiddenItems) { if (!((Object)(object)hiddenItem == (Object)null)) { hiddenItem.SetActive(true); collection?.Remove(hiddenItem); } } HiddenItems.Clear(); } } internal static class EndOfRoundCupboardEffectsPatch { private static ConfigEntry<bool>? PreventMemoryResetConfigEntry; private static bool SavedOriginalValue; internal static void TryPatch(Harmony harmony) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("SelfSortingStorage.Utils.RoundManagerPatch"); if (type == null) { SelfSortingStoragePLUS.Logger.LogError((object)"[ProtectCupboardItems] Could not resolve SelfSortingStorage.Utils.RoundManagerPatch. Team wipe scrap-clearing will not be prevented (cupboard contents may still be cleared by SelfSortingStorage itself on a team wipe)."); return; } MethodInfo methodInfo = AccessTools.Method(type, "EndOfRoundCupboardEffects", (Type[])null, (Type[])null); if (methodInfo == null) { SelfSortingStoragePLUS.Logger.LogError((object)"[ProtectCupboardItems] Could not resolve EndOfRoundCupboardEffects on SelfSortingStorage.Utils.RoundManagerPatch. Team wipe scrap-clearing will not be prevented."); return; } HarmonyMethod val = new HarmonyMethod(typeof(EndOfRoundCupboardEffectsPatch), "Prefix", (Type[])null); HarmonyMethod val2 = new HarmonyMethod(typeof(EndOfRoundCupboardEffectsPatch), "Finalizer", (Type[])null); harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null); SelfSortingStoragePLUS.Logger.LogDebug((object)"[ProtectCupboardItems] Patched SelfSortingStorage's EndOfRoundCupboardEffects."); } catch (Exception ex) { SelfSortingStoragePLUS.Logger.LogError((object)("[ProtectCupboardItems] Failed to patch SelfSortingStorage's EndOfRoundCupboardEffects. Team wipe scrap-clearing will not be prevented. Exception: " + ex)); } } private static bool ResolvePreventMemoryResetConfigEntry() { if (PreventMemoryResetConfigEntry != null) { return true; } try { Type type = AccessTools.TypeByName("SelfSortingStorage.Plugin"); object obj = AccessTools.Property(type, "config")?.GetValue(null); if (obj == null) { SelfSortingStoragePLUS.Logger.LogError((object)"[ProtectCupboardItems] Could not resolve SelfSortingStorage's config instance. Team wipe scrap-clearing will not be prevented."); return false; } Type type2 = obj.GetType(); object obj2 = AccessTools.Property(type2, "preventMemoryReset")?.GetValue(obj) ?? AccessTools.Field(type2, "preventMemoryReset")?.GetValue(obj); PreventMemoryResetConfigEntry = obj2 as ConfigEntry<bool>; if (PreventMemoryResetConfigEntry == null) { SelfSortingStoragePLUS.Logger.LogError((object)"[ProtectCupboardItems] Could not resolve SelfSortingStorage's preventMemoryReset config entry. Team wipe scrap-clearing will not be prevented."); } } catch (Exception ex) { SelfSortingStoragePLUS.Logger.LogError((object)("[ProtectCupboardItems] Error resolving preventMemoryReset config entry: " + ex)); return false; } return PreventMemoryResetConfigEntry != null; } private static void Prefix() { if (SelfSortingStoragePLUS.ProtectCupboardItems.Value && ResolvePreventMemoryResetConfigEntry()) { SavedOriginalValue = PreventMemoryResetConfigEntry.Value; PreventMemoryResetConfigEntry.Value = true; if (SelfSortingStoragePLUS.VerboseLogging.Value) { SelfSortingStoragePLUS.Logger.LogInfo((object)"[ProtectCupboardItems] Temporarily forcing SelfSortingStorage's preventMemoryReset on for the team wipe cleanup pass."); } } } private static Exception? Finalizer(Exception? __exception) { if (SelfSortingStoragePLUS.ProtectCupboardItems.Value && PreventMemoryResetConfigEntry != null) { PreventMemoryResetConfigEntry.Value = SavedOriginalValue; } return __exception; } } }