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 WeenieHutJrDifficultyManager v1.0.0
WeenieHutJrDifficultyManager.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("WeenieHutJrDifficultyManager")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+58202811ff20d819581d750e23d60c517d78c78d")] [assembly: AssemblyProduct("WeenieHutJrDifficultyManager")] [assembly: AssemblyTitle("WeenieHutJrDifficultyManager")] [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; } } } namespace WeenieHutJrDifficultyManager { public enum DeathMode { Vanilla, WeenieHutJr, SuperWeenieHutJr } internal static class DeathPenalty { public const int HotbarSlots = 8; public static bool Handles(Player player) { if (Plugin.Enabled.Value && Plugin.Mode.Value != DeathMode.Vanilla && (Object)(object)player != (Object)null) { return (Object)(object)player == (Object)(object)Player.m_localPlayer; } return false; } public static void OnDeath(Player player) { //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) bool flag = player.m_timeSinceDeath > player.m_hardDeathCooldown; Plugin.Log.LogInfo((object)string.Format("Death: {0} ({1:0} s of play since the last death, {2:0} s needed); skills {3}", flag ? "hard" : "soft", player.m_timeSinceDeath, player.m_hardDeathCooldown, flag ? "are checked" : "are not touched by the game, so no skill is lowered")); Inventory inventory = ((Humanoid)player).m_inventory; if (inventory == null || inventory.NrOfItems() == 0) { return; } if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)23)) { Plugin.Log.LogInfo((object)"Death: the world keeps every item (no item loss), so nothing goes to a grave"); return; } DeathMode value = Plugin.Mode.Value; if (value == DeathMode.SuperWeenieHutJr) { Plugin.Log.LogInfo((object)$"Death: {value}, {inventory.NrOfItems()} item(s) kept, no grave"); return; } List<ItemData> list = new List<ItemData>(); Dictionary<string, int> dictionary = new Dictionary<string, int>(); int num = 0; foreach (ItemData allItem in inventory.GetAllItems()) { string text = KeepReason(allItem); if (text == null) { list.Add(allItem); Plugin.Log.LogDebug((object)$"Death: {allItem.m_shared.m_name} x{allItem.m_stack} at ({allItem.m_gridPos.x}, {allItem.m_gridPos.y}) goes to the grave"); } else { num++; dictionary.TryGetValue(text, out var value2); dictionary[text] = value2 + 1; Plugin.Log.LogDebug((object)$"Death: {allItem.m_shared.m_name} x{allItem.m_stack} at ({allItem.m_gridPos.x}, {allItem.m_gridPos.y}) kept: {text}"); } } if (list.Count == 0) { Plugin.Log.LogInfo((object)$"Death: {value}, {num} item(s) kept ({Describe(dictionary)}), nothing for a grave"); return; } foreach (ItemData item in list) { if (item.m_equipped) { ((Humanoid)player).UnequipItem(item, false); } } GameObject obj = Object.Instantiate<GameObject>(player.m_tombstone, ((Character)player).GetCenterPoint(), ((Component)player).transform.rotation); MoveToGrave(obj.GetComponent<Container>().GetInventory(), inventory, list); PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); obj.GetComponent<TombStone>().Setup(playerProfile.GetName(), playerProfile.GetPlayerID()); Plugin.Log.LogInfo((object)$"Death: {value}, {num} item(s) kept ({Describe(dictionary)}), {list.Count} to the grave"); } internal static string KeepReason(ItemData item) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (item.m_shared.m_questItem) { return "quest item"; } if (Plugin.KeepEquipped.Value && item.m_equipped) { return "equipped"; } Vector2i gridPos = item.m_gridPos; if (gridPos.y == 0 && gridPos.x >= 0 && gridPos.x < 8) { if (!Plugin.KeepSlots[gridPos.x].Value) { return null; } return "slot " + (gridPos.x + 1); } switch (DraggableUILink.ExtraSlotKindAt(gridPos.x, gridPos.y)) { case "Arrow": if (!Plugin.KeepArrows.Value) { return null; } return "arrow slot"; case "Consumable": if (!Plugin.KeepConsumables.Value) { return null; } return "consumable slot"; case "Food": if (!Plugin.KeepFood.Value) { return null; } return "food slot"; default: return null; } } private static void MoveToGrave(Inventory grave, Inventory from, List<ItemData> items) { grave.m_inventory.Clear(); grave.m_width = from.m_width; grave.m_height = from.m_height; foreach (ItemData item in items) { grave.m_inventory.Add(item); from.m_inventory.Remove(item); } from.Changed(false, false); grave.Changed(false, false); } private static string Describe(Dictionary<string, int> counts) { if (counts.Count == 0) { return "none"; } List<string> list = new List<string>(); foreach (KeyValuePair<string, int> count in counts) { list.Add(count.Key + " " + count.Value); } return string.Join(", ", list.ToArray()); } } internal static class DraggableUILink { public const string DraggableUIGuid = "rhenn.draggableui"; private const string ApiTypeName = "DraggableUI.DraggableApi"; private static bool resolved; private static MethodInfo extraSlotKindAt; public static string ExtraSlotKindAt(int x, int y) { if (!Resolve()) { return null; } try { return (string)extraSlotKindAt.Invoke(null, new object[2] { x, y }); } catch (Exception ex) { Plugin.Log.LogWarning((object)$"DraggableUI refused ExtraSlotKindAt({x}, {y}): {ex.Message}"); return null; } } private static bool Resolve() { if (resolved) { return extraSlotKindAt != null; } resolved = true; if (!Chainloader.PluginInfos.TryGetValue("rhenn.draggableui", out var value) || (Object)(object)value.Instance == (Object)null) { Plugin.Log.LogInfo((object)"DraggableUI is not installed: the Arrows, Consumables and Food settings match nothing"); return false; } try { Type type = ((object)value.Instance).GetType().Assembly.GetType("DraggableUI.DraggableApi"); if (type != null) { extraSlotKindAt = type.GetMethod("ExtraSlotKindAt", BindingFlags.Static | BindingFlags.Public); } if (extraSlotKindAt == null) { Plugin.Log.LogWarning((object)$"DraggableUI {value.Metadata.Version} has no ExtraSlotKindAt (added in 1.1.1): the Arrows, Consumables and Food settings match nothing until it is updated"); return false; } Plugin.Log.LogDebug((object)$"DraggableUI {value.Metadata.Version} found; its Extra slots are asked about on death"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("DraggableUI could not be reached: " + ex.Message)); extraSlotKindAt = null; return false; } } } [BepInPlugin("rhenn.weeniehutjrdifficultymanager", "WeenieHutJrDifficultyManager", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "rhenn.weeniehutjrdifficultymanager"; public const string PluginName = "WeenieHutJrDifficultyManager"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<DeathMode> Mode; internal static ConfigEntry<bool> KeepEquipped; internal static ConfigEntry<bool>[] KeepSlots; internal static ConfigEntry<bool> KeepArrows; internal static ConfigEntry<bool> KeepConsumables; internal static ConfigEntry<bool> KeepFood; internal static ConfigEntry<bool> KeepAllSkills; internal static ConfigEntry<bool> KeepCombatSkills; internal static ConfigEntry<bool> KeepLifeSkills; internal static ConfigEntry<bool> KeepMovementSkills; internal static ConfigEntry<bool> KeepModdedSkills; private readonly Harmony harmony = new Harmony("rhenn.weeniehutjrdifficultymanager"); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Set to false and the game's own death penalty applies, whatever the settings below say."); Mode = ((BaseUnityPlugin)this).Config.Bind<DeathMode>("General", "DeathMode", DeathMode.WeenieHutJr, "What happens to your inventory when you die. Vanilla: the world's own death penalty setting decides, as without this mod. WeenieHutJr: everything ticked in the KeepOnDeath section stays with you, the rest goes to your grave. Named for the player who asked for it, like the Super mode. SuperWeenieHutJr: nothing goes to a grave, you keep every item, the grid too."); KeepEquipped = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepOnDeath", "Equipped", true, "Keep what you are wearing and holding: armour, cape, belt, trinket, the weapon and shield in your hands and the arrows loaded in your bow. This is what the game's Casual preset keeps."); KeepSlots = new ConfigEntry<bool>[8]; for (int i = 0; i < KeepSlots.Length; i++) { int num = i + 1; KeepSlots[i] = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepOnDeath", "Slot" + num, true, $"Keep whatever sits in hotbar slot {num} (the top row of the inventory, key {num}), equipped or not."); } KeepArrows = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepOnDeath", "Arrows", true, "Keep the arrows and bolts in DraggableUI's three Arrow slots. Needs DraggableUI 1.1.1 or later with its Extra slots on; does nothing otherwise."); KeepConsumables = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepOnDeath", "Consumables", true, "Keep the mead and potions in DraggableUI's three Consumable slots. Needs DraggableUI 1.1.1 or later with its Extra slots on; does nothing otherwise."); KeepFood = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepOnDeath", "Food", true, "Keep the food in DraggableUI's three Food slots. Needs DraggableUI 1.1.1 or later with its Extra slots on; does nothing otherwise."); KeepAllSkills = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepSkillsOnDeath", "All", false, "Keep every skill on death: no skill is ever lowered, whatever the group and skill switches say. (Independent of DeathMode, which is about items.)"); KeepCombatSkills = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepSkillsOnDeath", "Combat", false, "Keep the Combat skills: Swords, Knives, Clubs, Polearms, Spears, Axes, Unarmed, Bows, Crossbows, Elemental magic, Blood magic, Blocking, Dodge. On keeps them all; off lets each skill's own switch decide."); KeepLifeSkills = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepSkillsOnDeath", "Life", false, "Keep the Life skills: Pickaxes, Wood cutting, Fishing, Cooking, Farming, Crafting, Riding. On keeps them all; off lets each skill's own switch decide."); KeepMovementSkills = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepSkillsOnDeath", "Movement", false, "Keep the Movement skills: Jump, Sneak, Run, Swim. On keeps them all; off lets each skill's own switch decide."); KeepModdedSkills = ((BaseUnityPlugin)this).Config.Bind<bool>("KeepSkillsOnDeath", "ModdedSkills", false, "Keep skills added by other mods, which this mod cannot list by name. On keeps them all."); SkillLoss.Bind(((BaseUnityPlugin)this).Config); harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)string.Format("{0} {1} loaded. Enabled = {2}, DeathMode = {3}", "WeenieHutJrDifficultyManager", "1.0.0", Enabled.Value, Mode.Value)); } private void OnDestroy() { harmony.UnpatchSelf(); } } public enum SkillGroup { Combat, Life, Movement, Other } internal static class SkillLoss { public static readonly (SkillType Type, SkillGroup Group)[] GameSkills = new(SkillType, SkillGroup)[24] { ((SkillType)1, SkillGroup.Combat), ((SkillType)2, SkillGroup.Combat), ((SkillType)3, SkillGroup.Combat), ((SkillType)4, SkillGroup.Combat), ((SkillType)5, SkillGroup.Combat), ((SkillType)7, SkillGroup.Combat), ((SkillType)11, SkillGroup.Combat), ((SkillType)8, SkillGroup.Combat), ((SkillType)14, SkillGroup.Combat), ((SkillType)9, SkillGroup.Combat), ((SkillType)10, SkillGroup.Combat), ((SkillType)6, SkillGroup.Combat), ((SkillType)108, SkillGroup.Combat), ((SkillType)12, SkillGroup.Life), ((SkillType)13, SkillGroup.Life), ((SkillType)104, SkillGroup.Life), ((SkillType)105, SkillGroup.Life), ((SkillType)106, SkillGroup.Life), ((SkillType)107, SkillGroup.Life), ((SkillType)110, SkillGroup.Life), ((SkillType)100, SkillGroup.Movement), ((SkillType)101, SkillGroup.Movement), ((SkillType)102, SkillGroup.Movement), ((SkillType)103, SkillGroup.Movement) }; private static readonly Dictionary<SkillType, SkillGroup> groupOf = new Dictionary<SkillType, SkillGroup>(); private static readonly Dictionary<SkillType, ConfigEntry<bool>> keepSkill = new Dictionary<SkillType, ConfigEntry<bool>>(); public unsafe static void Bind(ConfigFile config) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) (SkillType, SkillGroup)[] gameSkills = GameSkills; for (int i = 0; i < gameSkills.Length; i++) { var (val, skillGroup) = gameSkills[i]; groupOf[val] = skillGroup; keepSkill[val] = config.Bind<bool>("KeepSkillsPerSkill", ((object)(*(SkillType*)(&val))/*cast due to .constrained prefix*/).ToString(), false, $"Keep {Words(val)} on death. A {skillGroup} skill: with the {skillGroup} switch on it is kept whatever this says."); } } public static SkillGroup GroupOf(SkillType type) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (!groupOf.TryGetValue(type, out var value)) { return SkillGroup.Other; } return value; } public static bool Lowers(SkillType type) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (Plugin.KeepAllSkills.Value || GroupKept(GroupOf(type))) { return false; } if (keepSkill.TryGetValue(type, out var value)) { return !value.Value; } return true; } private static bool GroupKept(SkillGroup group) { return group switch { SkillGroup.Combat => Plugin.KeepCombatSkills.Value, SkillGroup.Life => Plugin.KeepLifeSkills.Value, SkillGroup.Movement => Plugin.KeepMovementSkills.Value, _ => Plugin.KeepModdedSkills.Value, }; } public static bool Handles(Skills skills) { if (Plugin.Enabled.Value && (Object)(object)skills != (Object)null && (Object)(object)skills.m_player != (Object)null) { return (Object)(object)skills.m_player == (Object)(object)Player.m_localPlayer; } return false; } public static void OnDeath(Skills skills) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) float num = skills.m_DeathLowerFactor * Game.m_skillReductionRate; List<string> list = new List<string>(); List<string> list2 = new List<string>(); foreach (KeyValuePair<SkillType, Skill> skillDatum in skills.m_skillData) { Skill value = skillDatum.Value; if (Lowers(skillDatum.Key)) { float level = value.m_level; value.m_level -= value.m_level * num; value.m_accumulator = 0f; list.Add($"{skillDatum.Key} {level:0.#}>{value.m_level:0.#}"); } else { list2.Add(((object)skillDatum.Key/*cast due to .constrained prefix*/).ToString()); } } if (list.Count > 0) { ((Character)skills.m_player).Message((MessageType)1, "$msg_skills_lowered", 0, (Sprite)null, false); } Plugin.Log.LogInfo((object)$"Death: {list.Count} skill(s) lowered by {num:P0} ({Join(list)}), {list2.Count} kept ({Join(list2)})"); } private static string Join(List<string> parts) { if (parts.Count != 0) { return string.Join(", ", parts); } return "none"; } private unsafe static string Words(SkillType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 switch (type - 9) { default: if ((int)type != 110) { break; } return "Riding"; case 0: return "Elemental magic"; case 1: return "Blood magic"; case 4: return "Wood cutting"; case 2: case 3: break; } return ((object)(*(SkillType*)(&type))/*cast due to .constrained prefix*/).ToString(); } } } namespace WeenieHutJrDifficultyManager.Patches { [HarmonyPatch(typeof(Player), "CreateTombStone")] internal static class PlayerCreateTombStonePatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(Player __instance) { if (!DeathPenalty.Handles(__instance)) { return true; } try { DeathPenalty.OnDeath(__instance); return false; } catch (Exception arg) { Plugin.Log.LogError((object)$"Death handling failed, the game's own death penalty runs instead: {arg}"); return true; } } } [HarmonyPatch(typeof(Skills), "OnDeath")] internal static class SkillsOnDeathPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(Skills __instance) { if (!SkillLoss.Handles(__instance)) { return true; } try { SkillLoss.OnDeath(__instance); return false; } catch (Exception arg) { Plugin.Log.LogError((object)$"Skill loss handling failed, the game's own skill loss runs instead: {arg}"); return true; } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }