using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SaneSkills")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimStats")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("9b8fca2d-9424-4c21-9593-53e63ced4f59")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace SaneSkills; [BepInPlugin("com.Horpheus.valheim.SaneSkills", "SaneSkills", "2.0.0")] public class SaneSkills : BaseUnityPlugin { internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; _harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SaneSkills loaded"); SaneSkillsConfig.Init(((BaseUnityPlugin)this).Config); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] public static class Skills_Constructor_Patch { public static void Postfix(Skills __instance) { __instance.m_totalSkillCap = 2000f; } } public static class SkillGroups { private static readonly Dictionary InitGroups; private static readonly Dictionary InitMultipliers; private static readonly SkillType[][] GroupLookup; private static readonly float[] Multipliers; private static readonly int MaxSkillIndex; static SkillGroups() { //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Invalid comparison between Unknown and I4 //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Expected I4, but got Unknown //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) InitGroups = new Dictionary(); InitMultipliers = new Dictionary(); SkillType[] array = new SkillType[3]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); RegisterGroup((SkillType[])(object)array); RegisterGroup((SkillType)3, (SkillType)11); RegisterGroup((SkillType)4, (SkillType)5); RegisterGroup((SkillType)13, (SkillType)12); RegisterGroup((SkillType)8, (SkillType)14); RegisterGroup((SkillType)9, (SkillType)10); SkillType[] array2 = new SkillType[4]; RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); RegisterGroup((SkillType[])(object)array2); SkillType[] array3 = new SkillType[4]; RuntimeHelpers.InitializeArray(array3, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); RegisterGroup((SkillType[])(object)array3); SetMultiplier((SkillType)1, SaneSkillsConfig.SwordsMultiplier.Value); SetMultiplier((SkillType)2, SaneSkillsConfig.KnivesMultiplier.Value); SetMultiplier((SkillType)3, SaneSkillsConfig.ClubsMultiplier.Value); SetMultiplier((SkillType)4, SaneSkillsConfig.PolearmsMultiplier.Value); SetMultiplier((SkillType)5, SaneSkillsConfig.SpearsMultiplier.Value); SetMultiplier((SkillType)7, SaneSkillsConfig.AxesMultiplier.Value); SetMultiplier((SkillType)8, SaneSkillsConfig.BowsMultiplier.Value); SetMultiplier((SkillType)9, SaneSkillsConfig.ElementalMagicMultiplier.Value); SetMultiplier((SkillType)10, SaneSkillsConfig.BloodMagicMultiplier.Value); SetMultiplier((SkillType)11, SaneSkillsConfig.UnarmedMultiplier.Value); SetMultiplier((SkillType)12, SaneSkillsConfig.PickaxesMultiplier.Value); SetMultiplier((SkillType)13, SaneSkillsConfig.WoodCuttingMultiplier.Value); SetMultiplier((SkillType)14, SaneSkillsConfig.CrossbowsMultiplier.Value); SetMultiplier((SkillType)100, SaneSkillsConfig.JumpMultiplier.Value); SetMultiplier((SkillType)101, SaneSkillsConfig.SneakMultiplier.Value); SetMultiplier((SkillType)102, SaneSkillsConfig.RunMultiplier.Value); SetMultiplier((SkillType)103, SaneSkillsConfig.SwimMultiplier.Value); SetMultiplier((SkillType)104, SaneSkillsConfig.FishingMultiplier.Value); SetMultiplier((SkillType)105, SaneSkillsConfig.CookingMultiplier.Value); SetMultiplier((SkillType)106, SaneSkillsConfig.FarmingMultiplier.Value); SetMultiplier((SkillType)107, SaneSkillsConfig.CraftingMultiplier.Value); int num = 0; foreach (SkillType value in Enum.GetValues(typeof(SkillType))) { if ((int)value > num) { num = (int)value; } } MaxSkillIndex = num + 1; GroupLookup = new SkillType[MaxSkillIndex][]; Multipliers = new float[MaxSkillIndex]; foreach (KeyValuePair initGroup in InitGroups) { GroupLookup[initGroup.Key] = initGroup.Value; } foreach (KeyValuePair initMultiplier in InitMultipliers) { Multipliers[initMultiplier.Key] = initMultiplier.Value; } } private static void RegisterGroup(params SkillType[] skills) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected I4, but got Unknown foreach (SkillType val in skills) { SkillType[] array = (SkillType[])(object)new SkillType[skills.Length - 1]; int num = 0; foreach (SkillType val2 in skills) { if (val2 != val) { array[num++] = (SkillType)(int)val2; } } InitGroups[val] = array; } } private static void SetMultiplier(SkillType skill, float value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) InitMultipliers[skill] = value; } public static SkillType[] GetOtherSkills(SkillType skill) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Expected I4, but got Unknown int num = (int)skill; return (num >= 0 && num < MaxSkillIndex && GroupLookup[num] != null) ? GroupLookup[num] : Array.Empty(); } public static float GetMultiplier(SkillType skill) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Expected I4, but got Unknown int num = (int)skill; return (num >= 0 && num < MaxSkillIndex) ? Multipliers[num] : 1f; } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] public static class RaiseSkill_Patch { private static bool _isRaisingExtraSkills; public static void Postfix(Skills __instance, SkillType skillType, float factor) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!SaneSkillsConfig.EnableSaneSkills.Value || _isRaisingExtraSkills || (int)skillType == 0 || factor <= 0f) { return; } SkillType[] otherSkills = SkillGroups.GetOtherSkills(skillType); if (otherSkills.Length == 0) { return; } try { _isRaisingExtraSkills = true; foreach (SkillType val in otherSkills) { __instance.RaiseSkill(val, SkillGroups.GetMultiplier(val)); } } finally { _isRaisingExtraSkills = false; } } } public class SaneSkillsConfig { public static ConfigEntry EnableSaneSkills { get; private set; } public static ConfigEntry SwordsMultiplier { get; private set; } public static ConfigEntry KnivesMultiplier { get; private set; } public static ConfigEntry ClubsMultiplier { get; private set; } public static ConfigEntry PolearmsMultiplier { get; private set; } public static ConfigEntry SpearsMultiplier { get; private set; } public static ConfigEntry AxesMultiplier { get; private set; } public static ConfigEntry BowsMultiplier { get; private set; } public static ConfigEntry ElementalMagicMultiplier { get; private set; } public static ConfigEntry BloodMagicMultiplier { get; private set; } public static ConfigEntry UnarmedMultiplier { get; private set; } public static ConfigEntry PickaxesMultiplier { get; private set; } public static ConfigEntry WoodCuttingMultiplier { get; private set; } public static ConfigEntry CrossbowsMultiplier { get; private set; } public static ConfigEntry JumpMultiplier { get; private set; } public static ConfigEntry SneakMultiplier { get; private set; } public static ConfigEntry RunMultiplier { get; private set; } public static ConfigEntry SwimMultiplier { get; private set; } public static ConfigEntry FishingMultiplier { get; private set; } public static ConfigEntry CookingMultiplier { get; private set; } public static ConfigEntry FarmingMultiplier { get; private set; } public static ConfigEntry CraftingMultiplier { get; private set; } public static void Init(ConfigFile config) { EnableSaneSkills = config.Bind("General", "EnableSaneSkills", true, "Whether to enable the Sane Skills functionality."); SwordsMultiplier = config.Bind("Multipliers", "SwordsMultiplier", 1f, "Multiplier for Swords skill when related skills are raised."); KnivesMultiplier = config.Bind("Multipliers", "KnivesMultiplier", 1f, "Multiplier for Knives skill when related skills are raised."); ClubsMultiplier = config.Bind("Multipliers", "ClubsMultiplier", 1.1f, "Multiplier for Clubs skill when related skills are raised."); PolearmsMultiplier = config.Bind("Multipliers", "PolearmsMultiplier", 1.3f, "Multiplier for Polearms skill when related skills are raised."); SpearsMultiplier = config.Bind("Multipliers", "SpearsMultiplier", 1f, "Multiplier for Spears skill when related skills are raised."); AxesMultiplier = config.Bind("Multipliers", "AxesMultiplier", 1f, "Multiplier for Axes skill when related skills are raised."); BowsMultiplier = config.Bind("Multipliers", "BowsMultiplier", 1f, "Multiplier for Bows skill when related skills are raised."); ElementalMagicMultiplier = config.Bind("Multipliers", "ElementalMagicMultiplier", 1f, "Multiplier for Elemental Magic skill when related skills are raised."); BloodMagicMultiplier = config.Bind("Multipliers", "BloodMagicMultiplier", 1f, "Multiplier for Blood Magic skill when related skills are raised."); UnarmedMultiplier = config.Bind("Multipliers", "UnarmedMultiplier", 1.1f, "Multiplier for Unarmed skill when related skills are raised."); PickaxesMultiplier = config.Bind("Multipliers", "PickaxesMultiplier", 1f, "Multiplier for Pickaxes skill when related skills are raised."); WoodCuttingMultiplier = config.Bind("Multipliers", "WoodCuttingMultiplier", 1f, "Multiplier for Wood Cutting skill when related skills are raised."); CrossbowsMultiplier = config.Bind("Multipliers", "CrossbowsMultiplier", 1.2f, "Multiplier for Crossbows skill when related skills are raised."); JumpMultiplier = config.Bind("Multipliers", "JumpMultiplier", 0.35f, "Multiplier for Jump skill when related skills are raised."); SneakMultiplier = config.Bind("Multipliers", "SneakMultiplier", 0.35f, "Multiplier for Sneak skill when related skills are raised."); RunMultiplier = config.Bind("Multipliers", "RunMultiplier", 1.2f, "Multiplier for Run skill when related skills are raised."); SwimMultiplier = config.Bind("Multipliers", "SwimMultiplier", 0.55f, "Multiplier for Swim skill when related skills are raised."); FishingMultiplier = config.Bind("Multipliers", "FishingMultiplier", 1f, "Multiplier for Fishing skill when related skills are raised."); CookingMultiplier = config.Bind("Multipliers", "CookingMultiplier", 1f, "Multiplier for Cooking skill when related skills are raised."); FarmingMultiplier = config.Bind("Multipliers", "FarmingMultiplier", 1f, "Multiplier for Farming skill when related skills are raised."); CraftingMultiplier = config.Bind("Multipliers", "CraftingMultiplier", 1f, "Multiplier for Crafting skill when related skills are raised."); } }