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 FinalSunsetPermadeath v1.4.1
plugins\FinalSunsetPermadeath.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using HarmonyLib; using Jotunn.Utils; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("fix.permadeath.finalsunset", "FinalSunsetPermadeath", "1.4.1")] public class FinalSunsetPermadeath : BaseUnityPlugin { [HarmonyPatch(typeof(Player), "CreateTombStone")] private static class Patch_CreateTombStone { [HarmonyPrefix] private static void Prefix(Player __instance, ref HashSet<int> __state) { __state = null; if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } __state = new HashSet<int>(); TombStone[] array = Object.FindObjectsOfType<TombStone>(); for (int i = 0; i < array.Length; i++) { __state.Add(((Object)array[i]).GetInstanceID()); } KeepAtDeath.Clear(); Inventory inventory = ((Humanoid)__instance).GetInventory(); if (inventory != null) { List<ItemData> allItems = inventory.GetAllItems(); for (int j = 0; j < allItems.Count; j++) { if (allItems[j] != null && allItems[j].m_equipped) { KeepAtDeath.Add(allItems[j]); } } } if (!(MGetAllExtraSlotsItems != null)) { return; } try { if (!(MGetAllExtraSlotsItems.Invoke(null, null) is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { ItemData val = (ItemData)((item is ItemData) ? item : null); if (val != null) { KeepAtDeath.Add(val); } } } catch (Exception ex) { Debug.LogWarning((object)("[FinalSunsetPermadeath] ExtraSlots API query failed: " + ex.Message)); } } [HarmonyPostfix] private static void Postfix(Player __instance, HashSet<int> __state) { if (__state == null) { return; } RealDeath = true; TombStone[] array = Object.FindObjectsOfType<TombStone>(); TombStone val = null; for (int i = 0; i < array.Length; i++) { if (!__state.Contains(((Object)array[i]).GetInstanceID())) { val = array[i]; break; } } if ((Object)(object)val == (Object)null) { Debug.Log((object)"[FinalSunsetPermadeath] No new tombstone detected — items may survive"); KeepAtDeath.Clear(); return; } Container component = ((Component)val).GetComponent<Container>(); if ((Object)(object)component == (Object)null) { KeepAtDeath.Clear(); return; } Inventory inventory = component.GetInventory(); if (inventory == null) { KeepAtDeath.Clear(); return; } List<ItemData> list = new List<ItemData>(inventory.GetAllItems()); int num = 0; int num2 = 0; int num3 = 0; for (int j = 0; j < list.Count; j++) { ItemData val2 = list[j]; if (val2 != null && (KeepAtDeath.Contains(val2) || val2.m_equipped)) { int num4 = ClearBackpackContents(val2); if (num4 > 0) { num3 += num4; } num2++; } else { inventory.RemoveItem(val2); num++; } } if (num3 > 0 && FInvOnChanged != null && FInvOnChanged.GetValue(inventory) is Action action) { action(); } KeepAtDeath.Clear(); Debug.Log((object)("[FinalSunsetPermadeath] Tombstone [id=" + ((Object)val).GetInstanceID() + "]: kept " + num2 + " item(s) (equipped + extra slots) in grave, destroyed " + num + " item(s), wiped " + num3 + " item(s) from backpack(s)")); } } [HarmonyPatch(typeof(Player), "OnDeath")] [HarmonyAfter(new string[] { "shudnal.ExtraSlots", "balrond.astafaraios.BalrondSecondChance" })] private static class Patch_OnDeath { [HarmonyPrefix] private static void Prefix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { RealDeath = false; } } [HarmonyPostfix] private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !RealDeath) { return; } RealDeath = false; if (FSkillData == null || FSkillLevel == null) { return; } Skills skills = ((Character)__instance).GetSkills(); if ((Object)(object)skills == (Object)null) { return; } object value = FSkillData.GetValue(skills); if (!(value is IDictionary dictionary)) { return; } int num = 0; foreach (object value2 in dictionary.Values) { if (FSkillLevel != null) { FSkillLevel.SetValue(value2, 0f); } if (FSkillAcc != null) { FSkillAcc.SetValue(value2, 0f); } num++; } Debug.Log((object)("[FinalSunsetPermadeath] Reset " + num + " skill(s) to level 0")); } } [HarmonyPatch] private static class Patch_NeutralizeDeathDeleteModifier { private static readonly string[] Suppressed = new string[2] { "deathdeleteitems", "deathdeleteunequipped" }; private static IEnumerable<MethodBase> TargetMethods() { BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; List<MethodBase> list = new List<MethodBase>(); MethodInfo[] methods = typeof(ZoneSystem).GetMethods(bindingAttr); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == "GetGlobalKey" && methodInfo.ReturnType == typeof(bool) && methodInfo.GetParameters().Length == 1) { list.Add(methodInfo); } } return list; } private static bool Prefix(object[] __args, ref bool __result) { if (__args == null || __args.Length < 1 || __args[0] == null) { return true; } string a = __args[0].ToString(); for (int i = 0; i < Suppressed.Length; i++) { if (string.Equals(a, Suppressed[i], StringComparison.OrdinalIgnoreCase)) { __result = false; return false; } } return true; } } public const string PluginGUID = "fix.permadeath.finalsunset"; public const string PluginName = "FinalSunsetPermadeath"; public const string PluginVersion = "1.4.1"; internal static bool RealDeath; internal static readonly HashSet<ItemData> KeepAtDeath = new HashSet<ItemData>(); internal static FieldInfo FSkillData; internal static FieldInfo FSkillLevel; internal static FieldInfo FSkillAcc; internal static MethodInfo MGetAllExtraSlotsItems; internal static MethodInfo MGetBackpack; internal static FieldInfo FBackpackStructInv; internal static MethodInfo MItemInfoData; internal static MethodInfo MItemInfoSave; internal static FieldInfo FInvOnChanged; private void Awake() { //IL_014f: Unknown result type (might be due to invalid IL or missing references) BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; FSkillData = typeof(Skills).GetField("m_skillData", bindingAttr); Type nestedType = typeof(Skills).GetNestedType("Skill", BindingFlags.Public | BindingFlags.NonPublic); if (nestedType != null) { FSkillLevel = nestedType.GetField("m_level", bindingAttr); FSkillAcc = nestedType.GetField("m_accumulator", bindingAttr); } MethodInfo method = typeof(Player).GetMethod("CreateTombStone", bindingAttr); Type type = AccessTools.TypeByName("ExtraSlots.API"); if (type != null) { MGetAllExtraSlotsItems = AccessTools.Method(type, "GetAllExtraSlotsItems", (Type[])null, (Type[])null); } Type type2 = AccessTools.TypeByName("AdventureBackpacks.API.ABAPI"); if (type2 != null) { MGetBackpack = AccessTools.Method(type2, "GetBackpack", (Type[])null, (Type[])null); } Type type3 = AccessTools.TypeByName("Vapok.Common.Managers.ItemExtensions"); if (type3 != null) { MItemInfoData = AccessTools.Method(type3, "Data", new Type[1] { typeof(ItemData) }, (Type[])null); } Type type4 = AccessTools.TypeByName("Vapok.Common.Managers.ItemInfo"); if (type4 != null) { MItemInfoSave = AccessTools.Method(type4, "Save", Type.EmptyTypes, (Type[])null); } FInvOnChanged = AccessTools.Field(typeof(Inventory), "m_onChanged"); new Harmony("fix.permadeath.finalsunset").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("FinalSunsetPermadeath v1.4.1 loaded | skillData=" + R(FSkillData) + " level=" + R(FSkillLevel) + " acc=" + R(FSkillAcc) + " createTombStone=" + R(method) + " extraSlotsApi=" + R(MGetAllExtraSlotsItems) + " backpackApi=" + R(MGetBackpack) + " itemInfoData=" + R(MItemInfoData))); } private static int ClearBackpackContents(ItemData item) { if (MGetBackpack == null || item == null) { return -1; } object obj; try { obj = MGetBackpack.Invoke(null, new object[1] { item }); } catch (Exception ex) { Debug.LogWarning((object)("[FinalSunsetPermadeath] GetBackpack failed: " + ex.Message)); return -1; } if (obj == null) { return -1; } if (FBackpackStructInv == null) { FBackpackStructInv = obj.GetType().GetField("Inventory"); } if (FBackpackStructInv == null) { return -1; } object? value = FBackpackStructInv.GetValue(obj); Inventory val = (Inventory)((value is Inventory) ? value : null); if (val == null) { return -1; } int count = val.GetAllItems().Count; if (count == 0) { return 0; } val.RemoveAll(); if (MItemInfoData != null && MItemInfoSave != null) { try { object obj2 = MItemInfoData.Invoke(null, new object[1] { item }); if (obj2 != null) { MItemInfoSave.Invoke(obj2, null); } } catch (Exception ex2) { Debug.LogWarning((object)("[FinalSunsetPermadeath] backpack content save failed: " + ex2.Message)); } } return count; } private static string R(object o) { if (o == null) { return "NULL"; } return "ok"; } }