using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; [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("KeepInventoryMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("KeepInventoryMod")] [assembly: AssemblyTitle("KeepInventoryMod")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace KeepInventoryMod { [BepInPlugin("com.mods.keepinventory", "KeepInventory", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PLUGIN_GUID = "com.mods.keepinventory"; public const string PLUGIN_NAME = "KeepInventory"; public const string PLUGIN_VERSION = "1.0.0"; public static ConfigEntry KeepItemsOnDeath; private Harmony _harmony; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; KeepItemsOnDeath = ((BaseUnityPlugin)this).Config.Bind("General", "KeepItemsOnDeath", true, "Prevent items from dropping when the player dies"); _harmony = new Harmony("com.mods.keepinventory"); _harmony.PatchAll(); Log.LogInfo((object)"KeepInventory v1.0.0 loaded!"); Log.LogInfo((object)$" KeepItemsOnDeath = {KeepItemsOnDeath.Value}"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public static class PluginInfo { public const string PLUGIN_GUID = "com.mods.keepinventory"; public const string PLUGIN_NAME = "KeepInventory"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace KeepInventoryMod.Patches { [HarmonyPatch] public static class DeathDropPatch { [CompilerGenerated] private sealed class d__4 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable instructions; public IEnumerable <>3__instructions; private MethodInfo 5__2; private MethodInfo 5__3; private int 5__4; private IEnumerator <>7__wrap4; CodeInstruction IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__4(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } 5__2 = null; 5__3 = null; <>7__wrap4 = null; <>1__state = -2; } private bool MoveNext() { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = AccessTools.Method(typeof(Inventory), "ForceUnequip", (Type[])null, (Type[])null); 5__3 = AccessTools.Method(typeof(DeathDropPatch), "ConditionalForceUnequip", (Type[])null, (Type[])null); 5__4 = 0; <>7__wrap4 = instructions.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; 5__4++; break; case 2: <>1__state = -3; break; } if (<>7__wrap4.MoveNext()) { CodeInstruction current = <>7__wrap4.Current; if (5__2 != null && CodeInstructionExtensions.Calls(current, 5__2)) { <>2__current = new CodeInstruction(OpCodes.Call, (object)5__3); <>1__state = 1; return true; } <>2__current = current; <>1__state = 2; return true; } <>m__Finally1(); <>7__wrap4 = null; Plugin.Log.LogInfo((object)$"[KeepInventory] Transpiler: patched {5__4} ForceUnequip calls in PlayerDeathDone"); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap4 != null) { <>7__wrap4.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__4 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__4(0); } d__.instructions = <>3__instructions; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static bool _playerIsDead; [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeath")] [HarmonyPrefix] [HarmonyPriority(800)] private static void OnPlayerDeath() { if (Plugin.KeepItemsOnDeath.Value) { _playerIsDead = true; Plugin.Log.LogInfo((object)"[KeepInventory] PlayerDeath — dead flag ON"); } } [HarmonyPatch(typeof(PlayerAvatar), "ReviveRPC")] [HarmonyPostfix] private static void OnRevive() { _playerIsDead = false; Plugin.Log.LogInfo((object)"[KeepInventory] ReviveRPC — dead flag OFF"); } public static void ConditionalForceUnequip(Inventory inventory) { if (!Plugin.KeepItemsOnDeath.Value) { inventory.ForceUnequip(); } else { Plugin.Log.LogInfo((object)"[KeepInventory] BLOCKED Inventory.ForceUnequip — slot items kept!"); } } [IteratorStateMachine(typeof(d__4))] [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathDone")] [HarmonyTranspiler] private static IEnumerable TranspileDeathDone(IEnumerable instructions) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__4(-2) { <>3__instructions = instructions }; } [HarmonyPatch(typeof(StatsManager), "PlayerInventoryUpdate")] [HarmonyPrefix] private static bool PreventInventoryClear(string _steamID, string itemName, int spot, bool sync) { if (!Plugin.KeepItemsOnDeath.Value) { return true; } if (string.IsNullOrEmpty(itemName) && _playerIsDead) { Plugin.Log.LogInfo((object)$"[KeepInventory] BLOCKED inventory slot {spot} clear"); return false; } return true; } [HarmonyPatch(typeof(ItemEquippable), "RPC_ForceUnequip")] [HarmonyPrefix] private static bool BlockItemForceUnequip() { if (!Plugin.KeepItemsOnDeath.Value) { return true; } if (_playerIsDead) { Plugin.Log.LogInfo((object)"[KeepInventory] BLOCKED ItemEquippable.RPC_ForceUnequip"); return false; } return true; } public static void Reset() { _playerIsDead = false; } } [HarmonyPatch(typeof(MainMenuOpen), "Start")] public static class MainMenuClearPatch { [HarmonyPostfix] private static void Postfix() { DeathDropPatch.Reset(); Plugin.Log.LogInfo((object)"[KeepInventory] Main menu — state reset."); } } }