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 balrond extra skills v0.4.5
plugins/BalrondExtraSkills.dll
Decompiled 10 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BalrondExtraSkills.Compatibility; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using LitJson2; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BalrondExtraSkills")] [assembly: AssemblyProduct("BalrondExtraSkills")] [assembly: ComVisible(false)] [assembly: AssemblyFileVersion("0.4.4.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.4.0")] [module: UnverifiableCode] public static class BalrondHashCompat { public static int StableHash(string value) { return (value != null) ? StringExtensionMethods.GetStableHashCode(value) : 0; } } namespace BalrondExtraSkills { public static class BalrondDamageHub { [HarmonyPatch(typeof(Character), "ApplyDamage")] private static class Character_ApplyDamage_Patch { [HarmonyPrefix] private static void Prefix(Character __instance, out float __state) { __state = -1f; Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { __state = ((Character)val).GetHealth(); } } [HarmonyPostfix] private static void Postfix(Character __instance, HitData hit, float __state) { if (__state < 0f) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { float num = __state - ((Character)val).GetHealth(); if (!(num <= 0f)) { FortitudeSkill.OnDamageTaken(val, hit, num); } } } } } internal static class BalrondIconUtil { private static Sprite _placeholder; private static bool _attempted; internal static Sprite Placeholder { get { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_placeholder != (Object)null || _attempted) { return _placeholder; } _attempted = true; try { Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); ((Object)val).name = "BalrondExtraSkills_PlaceholderTexture"; val.SetPixel(0, 0, new Color(0f, 0f, 0f, 0f)); val.Apply(false, true); _placeholder = CreateSpriteCompat(val); if ((Object)(object)_placeholder != (Object)null) { ((Object)_placeholder).name = "BalrondExtraSkills_PlaceholderIcon"; } } catch (Exception ex) { if (BesRuntime.Log != null) { BesRuntime.Log.LogWarning((object)("[BES] Could not create placeholder skill icon: " + ex.Message)); } } return _placeholder; } } private static Sprite CreateSpriteCompat(Texture2D texture) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)texture == (Object)null) { return null; } MethodInfo[] methods = typeof(Sprite).GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (!string.Equals(methodInfo.Name, "Create", StringComparison.Ordinal)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length < 3 || parameters[0].ParameterType != typeof(Texture2D) || parameters[1].ParameterType != typeof(Rect) || parameters[2].ParameterType != typeof(Vector2)) { continue; } object[] array = new object[parameters.Length]; array[0] = texture; array[1] = (object)new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height); array[2] = (object)new Vector2(0.5f, 0.5f); bool flag = true; for (int j = 3; j < parameters.Length; j++) { ParameterInfo parameterInfo = parameters[j]; if (parameterInfo.HasDefaultValue) { array[j] = parameterInfo.DefaultValue; continue; } if (parameterInfo.ParameterType == typeof(float)) { array[j] = 100f; continue; } if (parameterInfo.ParameterType == typeof(uint)) { array[j] = 0u; continue; } if (parameterInfo.ParameterType == typeof(int)) { array[j] = 0; continue; } if (parameterInfo.ParameterType == typeof(bool)) { array[j] = false; continue; } if (parameterInfo.ParameterType.IsEnum) { array[j] = Activator.CreateInstance(parameterInfo.ParameterType); continue; } if (parameterInfo.ParameterType.IsValueType) { array[j] = Activator.CreateInstance(parameterInfo.ParameterType); continue; } flag = false; break; } if (flag) { try { object? obj = methodInfo.Invoke(null, array); return (Sprite)((obj is Sprite) ? obj : null); } catch { } } } return null; } } internal static class BalrondSkillLevelupMessagePatch { [HarmonyPatch(typeof(Player), "Message", new Type[] { typeof(MessageType), typeof(string), typeof(int), typeof(Sprite), typeof(bool) })] private static class Player_Message_SkillupTokenFix { [HarmonyPrefix] private static void Prefix(ref string msg) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(msg) || !msg.StartsWith("$msg_skillup")) { return; } int num = msg.IndexOf("$skill_"); if (num < 0) { return; } int i = num + 7; int num2 = i; for (; i < msg.Length; i++) { char c = msg[i]; if (c < '0' || c > '9') { break; } } if (i == num2 || !int.TryParse(msg.Substring(num2, i - num2), out var result)) { return; } SkillType key = (SkillType)result; if (BalrondSkillSystem.Registered.TryGetValue(key, out var value) && value != null) { string text = value.LocalizedName; if (string.IsNullOrEmpty(text)) { text = value.SkillNameEnglish; } msg = msg.Substring(0, num) + text + msg.Substring(i); } } } } public static class BalrondSkillSystem { [HarmonyPatch(typeof(SkillsDialog), "Setup")] private static class SkillsDialog_Setup_CustomNames_Patch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(SkillsDialog __instance) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null || __instance.m_elements == null) { return; } Player localPlayer = Player.m_localPlayer; Skills val = (((Object)(object)localPlayer != (Object)null) ? ((Character)localPlayer).GetSkills() : null); List<Skill> list = (((Object)(object)val != (Object)null) ? val.GetSkillList() : null); if (list == null) { return; } int num = Mathf.Min(list.Count, __instance.m_elements.Count); for (int i = 0; i < num; i++) { Skill val2 = list[i]; GameObject val3 = __instance.m_elements[i]; if (val2 == null || val2.m_info == null || (Object)(object)val3 == (Object)null || !val3.activeInHierarchy) { continue; } SkillType skill = val2.m_info.m_skill; if (!Registered.TryGetValue(skill, out var value) || value == null) { continue; } Transform val4 = Utils.FindChild(val3.transform, "name", (IterativeSearchType)0); TMP_Text val5 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<TMP_Text>() : null); if ((Object)(object)val5 != (Object)null) { val5.text = value.LocalizedName; } Transform val6 = Utils.FindChild(val3.transform, "icon", (IterativeSearchType)0); if ((Object)(object)val6 != (Object)null) { Image component = ((Component)val6).GetComponent<Image>(); if ((Object)(object)component != (Object)null) { component.sprite = value.Icon; } } } } catch (Exception ex) { if (BesRuntime.Settings != null && BesRuntime.Settings.LogCompatibility.Value && BesRuntime.Log != null) { BesRuntime.Log.LogWarning((object)("[BES localization] Failed to refresh custom skill labels: " + ex.Message)); } } } } [HarmonyPatch(typeof(Skills), "IsSkillValid")] private static class Skills_IsSkillValid_Patch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(SkillType type, ref bool __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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) if (TryGetLegacyTarget(type, out var _)) { __result = true; return false; } if (!IsCustomSkill(type)) { return true; } if (CollisionDisabled.Contains(type)) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Skills), "GetSkillDef")] private static class Skills_GetSkillDef_Patch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(Skills __instance, SkillType type, ref SkillDef __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) if (TryGetLegacyTarget(type, out var currentType) && Registered.TryGetValue(currentType, out var value) && value != null) { if ((Object)(object)__instance != (Object)null && __instance.m_skills != null) { for (int i = 0; i < __instance.m_skills.Count; i++) { SkillDef val = __instance.m_skills[i]; if (val != null && val.m_skill == type) { return true; } } } __result = new SkillDef { m_skill = type, m_icon = value.Icon, m_description = value.DescToken, m_increseStep = 1f }; return false; } if (!Registered.TryGetValue(type, out var value2) || value2 == null) { return true; } if (CollisionDisabled.Contains(type)) { return true; } if (!IsSkillEnabled(type)) { if ((Object)(object)__instance != (Object)null && __instance.m_skills != null) { for (int j = 0; j < __instance.m_skills.Count; j++) { SkillDef val2 = __instance.m_skills[j]; if (val2 != null && val2.m_skill == type && !IsOurDefinition(val2, value2)) { return true; } } } __result = CreateDefinition(value2); return false; } return true; } [HarmonyPostfix] private static void Postfix(Skills __instance, SkillType type, ref SkillDef __result) { //IL_0011: 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_0041: Unknown result type (might be due to invalid IL or missing references) if (__result == null && Registered.TryGetValue(type, out var value) && value != null && !CollisionDisabled.Contains(type)) { __result = CreateDefinition(value); if (IsSkillEnabled(type)) { EnsureDefsInSkillsList(__instance); } } } } [HarmonyPatch(typeof(Skills), "GetSkillList")] private static class Skills_GetSkillList_FilterDisabledCustom_Patch { [HarmonyPostfix] private static void Postfix(ref List<Skill> __result) { //IL_0051: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (__result == null || __result.Count == 0) { return; } for (int num = __result.Count - 1; num >= 0; num--) { Skill val = __result[num]; if (val != null && val.m_info != null) { SkillType skill = val.m_info.m_skill; if (Registered.TryGetValue(skill, out var value) && value != null && IsOurDefinition(val.m_info, value) && !IsSkillEnabled(skill)) { __result.RemoveAt(num); } } } } } [HarmonyPatch(typeof(Skills), "Awake")] private static class Skills_Awake_Patch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "M2Valheim.SkillsReworked" })] private static void Prefix(Skills __instance) { try { EnsureDefsInSkillsList(__instance); } catch { } } [HarmonyPostfix] [HarmonyAfter(new string[] { "M2Valheim.SkillsReworked" })] private static void Postfix(Skills __instance) { try { EnsureDefsInSkillsList(__instance); } catch { } } } [HarmonyPatch(typeof(Skills), "Save", new Type[] { typeof(ZPackage) })] private static class Skills_Save_CustomSkillStorage_Patch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(Skills __instance) { try { if (!((Object)(object)__instance == (Object)null)) { EnsureDefsInSkillsList(__instance); } } catch (Exception ex) { if (BesRuntime.Log != null) { BesRuntime.Log.LogError((object)("[BES persistence] Failed to reconcile custom skills before Skills.Save: " + ex)); } } } } [HarmonyPatch(typeof(Skills), "Load", new Type[] { typeof(ZPackage) })] private static class Skills_Load_CustomSkillStorage_Patch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(Skills __instance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null) { return; } EnsureDefsInSkillsList(__instance); MigrateLegacySkillData(__instance); foreach (KeyValuePair<SkillType, BaseSkill> item in Registered) { EnsureSkillSeeded(__instance, item.Key); } InvalidateLoadedSkillCaches(); } catch (Exception ex) { if (BesRuntime.Log != null) { BesRuntime.Log.LogError((object)("[BES persistence] Failed to reconcile custom skills after Skills.Load: " + ex)); } } } } [HarmonyPatch(typeof(Player), "Awake")] private static class Player_Awake_CustomSkillDefinitionsOnly_Patch { [HarmonyPostfix] private static void Postfix(Player __instance) { try { if ((Object)(object)__instance != (Object)null) { EnsureDefsInSkillsList(((Character)__instance).GetSkills()); } } catch { } } } [HarmonyPatch(typeof(Player), "Load")] [HarmonyAfter(new string[] { "M2Valheim.SkillsReworked" })] private static class Player_Load_SeedCustomSkills_Patch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(Player __instance) { EnsureAllSeeded(__instance); BesSkillPersistence.RestoreAfterPlayerLoad(__instance); InvalidateLoadedSkillCaches(); if (SkillRuntime.IsLocal(__instance)) { BesSkillPersistence.LogState("LOAD", __instance); } } } [HarmonyPatch(typeof(Skills), "CheatRaiseSkill")] private static class Skills_CheatRaiseSkill_Patch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "M2Valheim.SkillsReworked" })] private static bool Prefix(Skills __instance, ref string name, float value, bool showMessage) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) try { if (string.IsNullOrEmpty(name)) { return true; } if (!TryResolveCustomAlias(name, out var type)) { return true; } if (!Registered.TryGetValue(type, out var value2) || value2 == null) { return true; } if (CollisionDisabled.Contains(type)) { return true; } if (!IsSkillEnabled(type)) { Console instance = Console.instance; if (instance != null) { instance.Print(BesLocalization.Format("$tag_bes_skill_disabled", value2.LocalizedName)); } return false; } Player player = __instance.m_player; EnsureDefsInSkillsList(__instance, forceRefresh: true); EnsureSkillSeeded(__instance, type); if (SkillsReworkedCompat.IsActive && IsPlainEnduranceAlias(name, type)) { return true; } if (SkillsReworkedCompat.IsActive && (Object)(object)player != (Object)null) { SkillsReworkedCompat.RefreshSkillMapping(player); } if (SkillsReworkedCompat.OwnsProgression(type)) { name = NumericSkillName(type); return true; } if (__instance.m_skillData == null || !__instance.m_skillData.TryGetValue(type, out var value3) || value3 == null) { return false; } value3.m_level = Mathf.Clamp(value3.m_level + value, NegativeSkillsCompat.IsActive ? (-100f) : 0f, 100f); value3.m_accumulator = 0f; BesSkillPersistence.CaptureSkill(player, type); InvalidateLoadedSkillCaches(); if (showMessage && (Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)1, BesLocalization.Format("$tag_bes_skill_increased", value2.LocalizedName, (int)value3.m_level), 0, value2.Icon, false); } Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(BesLocalization.Format("$tag_bes_skill_value", value2.LocalizedName, (int)value3.m_level)); } return false; } catch { return true; } } } [HarmonyPatch(typeof(Skills), "CheatResetSkill")] private static class Skills_CheatResetSkill_Patch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "M2Valheim.SkillsReworked" })] private static bool Prefix(Skills __instance, ref string name) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) try { if (string.IsNullOrEmpty(name)) { return true; } if (!TryResolveCustomAlias(name, out var type)) { return true; } if (!Registered.TryGetValue(type, out var value) || value == null) { return true; } if (CollisionDisabled.Contains(type)) { return true; } if (!IsSkillEnabled(type)) { Console instance = Console.instance; if (instance != null) { instance.Print(BesLocalization.Format("$tag_bes_skill_disabled", value.LocalizedName)); } return false; } Player player = __instance.m_player; EnsureDefsInSkillsList(__instance, forceRefresh: true); EnsureSkillSeeded(__instance, type); if (SkillsReworkedCompat.IsActive && IsPlainEnduranceAlias(name, type)) { return true; } if (SkillsReworkedCompat.IsActive && (Object)(object)player != (Object)null) { SkillsReworkedCompat.RefreshSkillMapping(player); } if (SkillsReworkedCompat.OwnsProgression(type)) { name = NumericSkillName(type); return true; } __instance.ResetSkill(type); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(BesLocalization.Format("$tag_bes_skill_reset", value.LocalizedName)); } return false; } catch { return true; } } } public static readonly Dictionary<SkillType, BaseSkill> Registered = new Dictionary<SkillType, BaseSkill>(); private static readonly Dictionary<string, SkillType> ByAlias = new Dictionary<string, SkillType>(); private static readonly HashSet<SkillType> CollisionDisabled = new HashSet<SkillType>(); private static readonly Dictionary<SkillType, SkillType> LegacySkillIds = new Dictionary<SkillType, SkillType> { { (SkillType)17876, (SkillType)15001 }, { (SkillType)32776, (SkillType)15002 }, { (SkillType)39487, (SkillType)15003 }, { (SkillType)39004, (SkillType)15005 }, { (SkillType)35846, (SkillType)15006 } }; internal static Skill GetSkillCompat(Skills skills, SkillType type) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return ((Object)(object)skills == (Object)null) ? null : skills.GetSkill(type); } internal static SkillDef GetSkillDefCompat(Skills skills, SkillType type) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return ((Object)(object)skills == (Object)null) ? null : skills.GetSkillDef(type); } public static void RegisterSkill(BaseSkill skill) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_005a: 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) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected I4, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected I4, but got Unknown //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected I4, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected I4, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) if (skill == null) { throw new ArgumentNullException("skill"); } string text = SanitizeKey(skill.InternalKey); if (string.IsNullOrEmpty(text)) { text = SanitizeKey(skill.SkillNameEnglish); } if ((int)skill.SkillType == 0) { skill.SkillType = GetFixedSkillType(skill); } if (Registered.TryGetValue(skill.SkillType, out var value)) { throw new InvalidOperationException($"[BalrondExtraSkills] Skill ID collision: {(int)skill.SkillType} is already used by '{value.InternalKey}', cannot register '{skill.InternalKey}'."); } Registered.Add(skill.SkillType, skill); AddAlias(text, skill.SkillType); AddAlias(skill.SkillNameEnglish, skill.SkillType); AddAlias("BES" + skill.SkillNameEnglish, skill.SkillType); AddAlias("BES" + text, skill.SkillType); AddAlias(skill.NameToken, skill.SkillType); AddAlias("skill_" + (int)skill.SkillType, skill.SkillType); AddAlias(((int)skill.SkillType).ToString(), skill.SkillType); Debug.Log((object)$"[BalrondExtraSkills] Registered skill: {skill.SkillNameEnglish} (internal: {text}, type {(int)skill.SkillType})"); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { EnsureDefsInSkillsList(((Character)localPlayer).GetSkills()); EnsureSkillSeeded(((Character)localPlayer).GetSkills(), skill.SkillType); } } public static bool IsCustomSkill(SkillType type) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Registered.ContainsKey(type); } private static bool TryGetLegacyTarget(SkillType legacyType, out SkillType currentType) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return LegacySkillIds.TryGetValue(legacyType, out currentType); } internal static bool IsCollisionDisabled(SkillType type) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return CollisionDisabled.Contains(type); } internal static bool TryGetCustomSkill(SkillType type, out BaseSkill skill) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Registered.TryGetValue(type, out skill); } internal static bool IsSkillEnabled(SkillType type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!Registered.TryGetValue(type, out var value) || value == null) { return true; } if (CollisionDisabled.Contains(type)) { return false; } return BesRuntime.Settings?.IsSkillEnabled(value.FixedSkillId) ?? true; } internal static float GetSkillGainMultiplier(SkillType type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!Registered.TryGetValue(type, out var value) || value == null) { return 1f; } ExtraSkillsConfig settings = BesRuntime.Settings; if (settings == null) { return 1f; } return Mathf.Max(0f, settings.GetSkillGainMultiplier(value.FixedSkillId)); } internal static float GetSkillEffectMultiplier(SkillType type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!Registered.TryGetValue(type, out var value) || value == null) { return 1f; } ExtraSkillsConfig settings = BesRuntime.Settings; if (settings == null) { return 1f; } return Mathf.Max(0f, settings.GetSkillEffectMultiplier(value.FixedSkillId)); } public static void RaiseSkill(Player player, SkillType type, float amount) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && !(amount <= 0f) && (!IsCustomSkill(type) || IsSkillEnabled(type))) { SkillXpRouter.Raise(player, type, amount, "BES custom skill"); } } public static void NotifyAssetsReady() { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { EnsureDefsInSkillsList(((Character)localPlayer).GetSkills(), forceRefresh: true); DualMasteryCompat.EnsureSkillVisible(((Character)localPlayer).GetSkills()); SkillsReworkedCompat.RefreshSkillMapping(localPlayer); } foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { EnsureDefsInSkillsList(((Character)allPlayer).GetSkills(), forceRefresh: true); } } } catch { } } internal static void NotifySkillEnablementChanged(SkillType type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected I4, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected I4, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!Registered.ContainsKey(type)) { return; } bool flag = IsSkillEnabled(type); ResetRuntimeState(type); try { List<Player> allPlayers = Player.GetAllPlayers(); for (int i = 0; i < allPlayers.Count; i++) { Player val = allPlayers[i]; if (!((Object)(object)val == (Object)null)) { Skills skills = ((Character)val).GetSkills(); if (!((Object)(object)skills == (Object)null)) { EnsureDefsInSkillsList(skills, forceRefresh: true); EnsureSkillSeeded(skills, type); } } } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { SkillsReworkedCompat.RefreshSkillMapping(localPlayer); } TryRefreshOpenSkillsDialogs(); } catch (Exception ex) { if (BesRuntime.Log != null) { BesRuntime.Log.LogWarning((object)("[BES skills] Failed to reconcile Enabled state for skill " + (int)type + ": " + ex.Message)); } } if (BesRuntime.Log != null) { BesRuntime.Log.LogInfo((object)("[BES skills] " + ((Registered[type] != null) ? Registered[type].SkillNameEnglish : ((int)type).ToString()) + (flag ? " enabled and exposed to the game." : " disabled and removed from game-facing skill definitions."))); } } private static void TryRefreshOpenSkillsDialogs() { try { MethodInfo methodInfo = AccessTools.Method(typeof(SkillsDialog), "Setup", (Type[])null, (Type[])null); if (methodInfo == null) { return; } ParameterInfo[] parameters = methodInfo.GetParameters(); SkillsDialog[] array = Resources.FindObjectsOfTypeAll<SkillsDialog>(); foreach (SkillsDialog val in array) { if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } if (parameters.Length == 0) { methodInfo.Invoke(val, null); } else if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(typeof(Player))) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { methodInfo.Invoke(val, new object[1] { localPlayer }); } } } } catch (Exception ex) { if (BesRuntime.Settings != null && BesRuntime.Settings.LogCompatibility.Value && BesRuntime.Log != null) { BesRuntime.Log.LogWarning((object)("[BES skills] Could not refresh an open Skills dialog after config change: " + ex.Message)); } } } private static void ResetRuntimeState(SkillType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Expected I4, but got Unknown switch ((int)type) { case 15001: VitalitySkill.ResetRuntimeState(); break; case 15002: ArcanaSkill.ResetRuntimeState(); break; case 15003: EnduranceSkill.ResetRuntimeState(); break; case 15004: ExplorationSkill.ResetRuntimeState(); break; case 15005: FortitudeSkill.ResetRuntimeState(); break; case 15006: HaulingSkill.ResetRuntimeState(); break; case 15007: SailingSkill.ResetRuntimeState(); break; case 15008: TamingSkill.ResetRuntimeState(); break; } } private static SkillType GetFixedSkillType(BaseSkill skill) { //IL_003e: 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) int fixedSkillId = skill.FixedSkillId; if (fixedSkillId < 10000 || fixedSkillId > 39999) { Debug.LogWarning((object)$"[BalrondExtraSkills] Skill '{skill.InternalKey}' uses ID outside recommended range 10000-39999: {fixedSkillId}"); } return (SkillType)fixedSkillId; } private static void AddAlias(string raw, SkillType type) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) string text = SanitizeKey(raw); if (string.IsNullOrEmpty(text)) { return; } if (ByAlias.TryGetValue(text, out var value)) { if (value != type) { Debug.LogWarning((object)("[BalrondExtraSkills] Alias collision for '" + raw + "' -> '" + text + "'")); } } else { ByAlias.Add(text, type); } } private static string SanitizeKey(string s) { if (string.IsNullOrEmpty(s)) { return ""; } s = s.Trim().ToLowerInvariant(); s = s.Replace("$", ""); s = s.Replace(" ", ""); s = s.Replace("-", ""); s = s.Replace("_", ""); return s; } internal static bool TryResolveSkillIdentifier(string raw, out SkillType type) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected I4, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected I4, but got Unknown type = (SkillType)0; if (string.IsNullOrWhiteSpace(raw)) { return false; } string key = SanitizeKey(raw); if (ByAlias.TryGetValue(key, out var value)) { type = (SkillType)(int)value; return true; } if (int.TryParse(raw.Trim(), out var result)) { type = (SkillType)result; return true; } try { if (Enum.TryParse<SkillType>(raw.Trim(), ignoreCase: true, out SkillType result2)) { type = (SkillType)(int)result2; return true; } } catch { } return false; } private static bool TryResolveCustomAlias(string raw, out SkillType type) { type = (SkillType)0; if (string.IsNullOrWhiteSpace(raw)) { return false; } return ByAlias.TryGetValue(SanitizeKey(raw), out type) && Registered.ContainsKey(type); } private static bool IsPlainEnduranceAlias(string raw, SkillType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)type == 15003 && SanitizeKey(raw) == SanitizeKey("Endurance"); } private static string NumericSkillName(SkillType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Expected I4, but got Unknown return ((int)type).ToString(CultureInfo.InvariantCulture); } private static bool IsOurDefinition(SkillDef def, BaseSkill skill) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) return def != null && skill != null && def.m_skill == skill.SkillType && string.Equals(def.m_description, skill.DescToken, StringComparison.Ordinal); } private static void EnsureDefsInSkillsList(Skills skills, bool forceRefresh = false) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected I4, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skills == (Object)null) { return; } List<SkillDef> skills2 = skills.m_skills; if (skills2 == null) { return; } foreach (KeyValuePair<SkillType, BaseSkill> item in Registered) { SkillType key = item.Key; BaseSkill value = item.Value; bool flag = IsSkillEnabled(key); SkillDef val = null; SkillDef val2 = null; for (int num = skills2.Count - 1; num >= 0; num--) { SkillDef val3 = skills2[num]; if (val3 != null && val3.m_skill == key) { if (IsOurDefinition(val3, value)) { if (!flag) { skills2.RemoveAt(num); } else { val = val3; } } else { val2 = val3; } } } if (val2 != null) { if (CollisionDisabled.Add(key)) { Debug.LogError((object)("[BalrondExtraSkills] CRITICAL skill ID collision: " + (int)key + " is already represented by another SkillDef. BES module '" + value.InternalKey + "' is disabled; the numeric ID will not be remapped.")); } } else if (!CollisionDisabled.Contains(key) && flag) { if (val == null) { val = CreateDefinition(value); skills2.Add(val); } else if (forceRefresh) { val.m_icon = value.Icon; val.m_description = value.DescToken; } if (val != null && skills.m_skillData != null && skills.m_skillData.TryGetValue(key, out var value2) && value2 != null) { value2.m_info = val; } } } } private static SkillDef CreateDefinition(BaseSkill skill) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown if (skill == null) { return null; } return new SkillDef { m_skill = skill.SkillType, m_icon = skill.Icon, m_description = skill.DescToken, m_increseStep = 1f }; } private static void MigrateLegacySkillData(Skills skills) { //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Expected I4, but got Unknown //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected I4, but got Unknown //IL_0041: 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) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected I4, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected I4, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skills == (Object)null || skills.m_skillData == null) { return; } foreach (KeyValuePair<SkillType, SkillType> legacySkillId in LegacySkillIds) { if (!skills.m_skillData.TryGetValue(legacySkillId.Key, out var value) || value == null || !Registered.TryGetValue(legacySkillId.Value, out var value2) || value2 == null || (value.m_info != null && !string.Equals(value.m_info.m_description, value2.DescToken, StringComparison.Ordinal))) { continue; } Skill value3 = null; skills.m_skillData.TryGetValue(legacySkillId.Value, out value3); if (value3 == null) { try { value3 = skills.GetSkill(legacySkillId.Value); } catch { value3 = null; } } if (value3 != null) { bool flag = Mathf.Approximately(value3.m_level, 0f) && Mathf.Approximately(value3.m_accumulator, 0f); bool flag2 = !Mathf.Approximately(value.m_level, 0f) || !Mathf.Approximately(value.m_accumulator, 0f); if (flag && flag2) { value3.m_level = value.m_level; value3.m_accumulator = value.m_accumulator; if (BesRuntime.Log != null) { BesRuntime.Log.LogInfo((object)("[BES persistence] Migrated legacy skill " + (int)legacySkillId.Key + " -> " + (int)legacySkillId.Value + " level=" + value.m_level.ToString(CultureInfo.InvariantCulture) + ".")); } } } if (value3 != null) { skills.m_skillData.Remove(legacySkillId.Key); } else if (BesRuntime.Log != null) { BesRuntime.Log.LogWarning((object)("[BES persistence] Deferred legacy skill migration " + (int)legacySkillId.Key + " -> " + (int)legacySkillId.Value + ": target skill is unavailable.")); } } } private static void EnsureSkillSeeded(Skills skills, SkillType type) { //IL_001c: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)skills == (Object)null) && skills.m_skillData != null && IsCustomSkill(type) && !CollisionDisabled.Contains(type) && !skills.m_skillData.ContainsKey(type)) { skills.GetSkill(type); } } private static void EnsureAllSeeded(Player player) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null) { return; } EnsureDefsInSkillsList(skills); foreach (KeyValuePair<SkillType, BaseSkill> item in Registered) { EnsureSkillSeeded(skills, item.Key); } if (SkillRuntime.IsLocal(player)) { DualMasteryCompat.EnsureSkillVisible(skills); SkillsReworkedCompat.RefreshSkillMapping(player); } } private static void InvalidateLoadedSkillCaches() { SkillRuntime.InvalidateAllLevelCache(); TotalLevelService.Invalidate(); ResourceCapacityBonus.Invalidate(); } } public class BalrondTranslator { public static readonly Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); public static Dictionary<string, string> getLanguage(string language) { if (string.IsNullOrEmpty(language)) { return null; } translations.TryGetValue(language, out var value); return value; } public static Dictionary<string, string> GetMergedLanguage(string language) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); Dictionary<string, string> language2 = getLanguage("English"); if (language2 != null) { foreach (KeyValuePair<string, string> item in language2) { dictionary[item.Key] = item.Value; } } if (!string.IsNullOrEmpty(language) && !string.Equals(language, "English", StringComparison.OrdinalIgnoreCase)) { Dictionary<string, string> language3 = getLanguage(language); if (language3 != null) { foreach (KeyValuePair<string, string> item2 in language3) { dictionary[item2.Key] = item2.Value; } } } return (dictionary.Count > 0) ? dictionary : null; } } internal static class BesLocalization { private static readonly Dictionary<string, string> CoreEnglishFallback = new Dictionary<string, string>(StringComparer.Ordinal) { { "skill_15001", "Vitality" }, { "skill_15002", "Arcana" }, { "skill_15003", "Endurance" }, { "skill_15004", "Exploration" }, { "skill_15005", "Fortitude" }, { "skill_15006", "Hauling" }, { "skill_15007", "Sailing" }, { "skill_15008", "Taming" }, { "tag_skill_vitalityskill_bal", "Vitality" }, { "tag_skill_vitalityskill_bal_description", "Raises maximum health and health regeneration." }, { "tag_skill_arcanaskill_bal", "Arcana" }, { "tag_skill_arcanaskill_bal_description", "Raises maximum Eitr and Eitr regeneration." }, { "tag_skill_enduranceskill_bal", "Endurance" }, { "tag_skill_enduranceskill_bal_description", "Raises maximum stamina and stamina regeneration." }, { "tag_skill_explorationskill_bal", "Exploration" }, { "tag_skill_explorationskill_bal_description", "Expands map discovery radius." }, { "tag_skill_fortitudeskill_bal", "Fortitude" }, { "tag_skill_fortitudeskill_bal_description", "Increases armor." }, { "tag_skill_haulingskill_bal", "Hauling" }, { "tag_skill_haulingskill_bal_description", "Increases carry weight." }, { "tag_skill_sailingskill_bal", "Sailing" }, { "tag_skill_sailingskill_bal_description", "Improves ship handling and reduces collision damage." }, { "tag_skill_tamingskill_bal", "Taming" }, { "tag_skill_tamingskill_bal_description", "Speeds basic taming. Progressing taming and successful breeding train the skill." } }; internal static string Text(string token) { if (string.IsNullOrEmpty(token)) { return string.Empty; } string text = ((token[0] == '$') ? token : ("$" + token)); string text2 = text.Substring(1); try { if (Localization.instance != null) { string text3 = Localization.instance.Localize(text); if (!IsRawLocalizationResult(text3, text, text2)) { return text3; } } } catch { } string text4 = English(text2); if (!string.IsNullOrEmpty(text4)) { return text4; } return HumanizeKey(text2); } internal static string Format(string token, params object[] args) { string text = Text(token); try { return string.Format(CultureInfo.CurrentCulture, text, args ?? Array.Empty<object>()); } catch { return text; } } internal static string English(string tokenOrKey, string fallback = "") { if (string.IsNullOrEmpty(tokenOrKey)) { return fallback ?? string.Empty; } string key = ((tokenOrKey[0] == '$') ? tokenOrKey.Substring(1) : tokenOrKey); Dictionary<string, string> language = BalrondTranslator.getLanguage("English"); if (language != null && language.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value)) { return value; } if (CoreEnglishFallback.TryGetValue(key, out var value2) && !string.IsNullOrEmpty(value2)) { return value2; } return fallback ?? string.Empty; } private static bool IsRawLocalizationResult(string localized, string normalized, string key) { if (string.IsNullOrEmpty(localized)) { return true; } if (string.Equals(localized, normalized, StringComparison.Ordinal)) { return true; } if (string.Equals(localized, key, StringComparison.Ordinal)) { return true; } if (string.Equals(localized, "[" + key + "]", StringComparison.Ordinal)) { return true; } if (string.Equals(localized, "[" + normalized + "]", StringComparison.Ordinal)) { return true; } return false; } private static string HumanizeKey(string key) { if (string.IsNullOrEmpty(key)) { return string.Empty; } string text = key; if (text.StartsWith("tag_skill_", StringComparison.Ordinal)) { text = text.Substring("tag_skill_".Length); } else if (text.StartsWith("tag_bes_", StringComparison.Ordinal)) { text = text.Substring("tag_bes_".Length); } else if (text.StartsWith("skill_", StringComparison.Ordinal)) { text = text.Substring("skill_".Length); } if (text.EndsWith("_description", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "_description".Length); } if (text.EndsWith("_bal", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - 4); } text = text.Replace('_', ' ').Trim(); if (text.Length == 0) { return key; } return char.ToUpperInvariant(text[0]) + text.Substring(1); } } internal static class BesSkillPersistence { [HarmonyPatch(typeof(Player), "Save", new Type[] { typeof(ZPackage) })] private static class Player_Save_BesSkillMirror_Patch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(Player __instance) { CaptureAll(__instance); if (SkillRuntime.IsLocal(__instance)) { LogState("SAVE", __instance); } } } [HarmonyPatch(typeof(Skills), "LowerAllSkills", new Type[] { typeof(float) })] private static class Skills_LowerAllSkills_BesSkillMirror_Patch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(Skills __instance) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance)) { CaptureAll(localPlayer); } } } [HarmonyPatch(typeof(Skills), "ResetSkill", new Type[] { typeof(SkillType) })] private static class Skills_ResetSkill_BesSkillMirror_Patch { [HarmonyPostfix] private static void Postfix(Skills __instance, SkillType skillType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (BalrondSkillSystem.IsCustomSkill(skillType)) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance)) { CaptureSkill(localPlayer, skillType); } } } } private const string StatePrefix = "BES_SKILL_STATE_V1_"; private static readonly FieldInfo PlayerCustomDataField = AccessTools.Field(typeof(Player), "m_customData"); internal static void CaptureAll(Player player) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null || skills.m_skillData == null) { return; } IDictionary customData = GetCustomData(player); if (customData == null) { return; } foreach (KeyValuePair<SkillType, BaseSkill> item in BalrondSkillSystem.Registered) { SkillType key = item.Key; if (!BalrondSkillSystem.IsCollisionDisabled(key) && !SkillsReworkedCompat.OwnsProgression(key) && skills.m_skillData.TryGetValue(key, out var value) && value != null) { WriteState(customData, key, value.m_level, value.m_accumulator); } } } internal static void CaptureSkill(Player player, SkillType type) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || !BalrondSkillSystem.IsCustomSkill(type) || BalrondSkillSystem.IsCollisionDisabled(type) || SkillsReworkedCompat.OwnsProgression(type)) { return; } Skills skills = ((Character)player).GetSkills(); if (!((Object)(object)skills == (Object)null) && skills.m_skillData != null && skills.m_skillData.TryGetValue(type, out var value) && value != null) { IDictionary customData = GetCustomData(player); if (customData != null) { WriteState(customData, type, value.m_level, value.m_accumulator); } } } internal static void RestoreAfterPlayerLoad(Player player) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected I4, but got Unknown if ((Object)(object)player == (Object)null) { return; } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null || skills.m_skillData == null) { return; } IDictionary customData = GetCustomData(player); if (customData == null) { return; } foreach (KeyValuePair<SkillType, BaseSkill> item in BalrondSkillSystem.Registered) { SkillType key = item.Key; if (BalrondSkillSystem.IsCollisionDisabled(key) || SkillsReworkedCompat.OwnsProgression(key) || !TryReadState(customData, key, out var level, out var accumulator)) { continue; } if (!skills.m_skillData.TryGetValue(key, out var value) || value == null) { try { value = skills.GetSkill(key); } catch { value = null; } } if (value == null) { continue; } bool flag = !Mathf.Approximately(value.m_level, 0f) || !Mathf.Approximately(value.m_accumulator, 0f); bool flag2 = !Mathf.Approximately(level, 0f) || !Mathf.Approximately(accumulator, 0f); if (!flag && flag2) { float num = (NegativeSkillsCompat.IsActive ? (-100f) : 0f); value.m_level = Mathf.Clamp(level, num, 100f); value.m_accumulator = Mathf.Max(0f, accumulator); if (BesRuntime.Log != null) { BesRuntime.Log.LogWarning((object)("[BES persistence] Recovered skill " + (int)key + " from player custom-data mirror at level " + value.m_level.ToString("0.###", CultureInfo.InvariantCulture) + ".")); } } } } internal static void LogState(string phase, Player player) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected I4, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) ExtraSkillsConfig settings = BesRuntime.Settings; if (settings == null || !settings.LogCompatibility.Value || BesRuntime.Log == null || (Object)(object)player == (Object)null) { return; } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null || skills.m_skillData == null) { return; } StringBuilder stringBuilder = new StringBuilder(192); stringBuilder.Append("[BES persistence ").Append(phase).Append("] "); bool flag = true; foreach (KeyValuePair<SkillType, BaseSkill> item in BalrondSkillSystem.Registered) { SkillType key = item.Key; if (!flag) { stringBuilder.Append(" | "); } flag = false; stringBuilder.Append((int)key).Append('='); if (skills.m_skillData.TryGetValue(key, out var value) && value != null) { stringBuilder.Append(value.m_level.ToString("0.###", CultureInfo.InvariantCulture)); stringBuilder.Append('/'); stringBuilder.Append(value.m_accumulator.ToString("0.###", CultureInfo.InvariantCulture)); } else { stringBuilder.Append("missing"); } if (SkillsReworkedCompat.OwnsProgression(key)) { stringBuilder.Append("(SR)"); } } BesRuntime.Log.LogInfo((object)stringBuilder.ToString()); } private static IDictionary GetCustomData(Player player) { try { return (PlayerCustomDataField != null) ? (PlayerCustomDataField.GetValue(player) as IDictionary) : null; } catch { return null; } } private static string Key(SkillType type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected I4, but got Unknown return "BES_SKILL_STATE_V1_" + ((int)type).ToString(CultureInfo.InvariantCulture); } private static void WriteState(IDictionary data, SkillType type, float level, float accumulator) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (data != null && !float.IsNaN(level) && !float.IsInfinity(level)) { if (float.IsNaN(accumulator) || float.IsInfinity(accumulator)) { accumulator = 0f; } data[Key(type)] = level.ToString("R", CultureInfo.InvariantCulture) + "|" + accumulator.ToString("R", CultureInfo.InvariantCulture); } } private static bool TryReadState(IDictionary data, SkillType type, out float level, out float accumulator) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) level = 0f; accumulator = 0f; if (data == null) { return false; } object obj = data[Key(type)]; if (obj == null) { return false; } string text = obj.ToString(); if (string.IsNullOrEmpty(text)) { return false; } int num = text.IndexOf('|'); if (num <= 0 || num >= text.Length - 1) { return false; } if (!float.TryParse(text.Substring(0, num), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return false; } if (!float.TryParse(text.Substring(num + 1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return false; } if (float.IsNaN(result) || float.IsInfinity(result)) { return false; } if (float.IsNaN(result2) || float.IsInfinity(result2)) { result2 = 0f; } level = result; accumulator = result2; return true; } } internal static class BesSkillSaveGuard { private sealed class SaveState { internal readonly List<SkillType> EmptyKeys = new List<SkillType>(); internal readonly List<TemporaryInfo> TemporaryInfos = new List<TemporaryInfo>(); internal bool Restored; } private struct TemporaryInfo { internal Skill Skill; internal SkillDef Injected; internal SkillDef Original; } [HarmonyPatch(typeof(Skills), "Save", new Type[] { typeof(ZPackage) })] private static class Skills_Save_ValidateEntries_Patch { [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "M2Valheim.SkillsReworked" })] private static void Prefix(Skills __instance, out SaveState __state) { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected I4, but got Unknown //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Expected O, but got Unknown //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Expected I4, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected I4, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected I4, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected I4, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected I4, but got Unknown //IL_0295: Unknown result type (might be due to invalid IL or missing references) __state = new SaveState(); if ((Object)(object)__instance == (Object)null || __instance.m_skillData == null) { return; } try { List<KeyValuePair<SkillType, Skill>> list = new List<KeyValuePair<SkillType, Skill>>(__instance.m_skillData); foreach (KeyValuePair<SkillType, Skill> item in list) { SkillType key = item.Key; Skill value = item.Value; if (value == null) { __state.EmptyKeys.Add(key); Warn("Null skill entry " + (int)key + " excluded from this save (no level or XP to serialize)."); continue; } SkillDef info = value.m_info; if (info != null) { if (info.m_skill == key) { continue; } if (!BalrondSkillSystem.IsCustomSkill(key) || BalrondSkillSystem.IsCollisionDisabled(key)) { Warn("Skill dictionary key " + (int)key + " has definition ID " + (int)info.m_skill + "; foreign mapping left unchanged."); continue; } } SkillDef val = null; try { val = __instance.GetSkillDef(key); } catch (Exception ex) { Warn("GetSkillDef(" + (int)key + ") failed: " + ex.Message); } if (val != null && val.m_skill == key) { value.m_info = val; Warn("Restored missing SkillDef for skill " + (int)key + "."); continue; } SkillDef val2 = new SkillDef { m_skill = key, m_description = "", m_increseStep = 1f }; __state.TemporaryInfos.Add(new TemporaryInfo { Skill = value, Original = info, Injected = val2 }); value.m_info = val2; Warn("Skill " + (int)key + " has no registered definition; using a temporary save-only SkillDef to preserve its XP."); } for (int i = 0; i < __state.EmptyKeys.Count; i++) { SkillType key2 = __state.EmptyKeys[i]; if (__instance.m_skillData.TryGetValue(key2, out var value2) && value2 == null) { __instance.m_skillData.Remove(key2); } } } catch (Exception ex2) { Restore(__instance, __state); if (BesRuntime.Log != null) { BesRuntime.Log.LogError((object)("[BES save guard] Pre-save validation failed: " + ex2)); } } } [HarmonyPostfix] private static void Postfix(Skills __instance, SaveState __state) { Restore(__instance, __state); } [HarmonyFinalizer] private static Exception Finalizer(Skills __instance, SaveState __state, Exception __exception) { Restore(__instance, __state); if (__exception != null && BesRuntime.Log != null) { BesRuntime.Log.LogError((object)("[BES save guard] Skills.Save still failed after entry validation. Check other Harmony prefixes/transpilers and preceding skill-ID warnings. Patch owners: " + GetSavePatchOwners() + ". " + __exception)); } return __exception; } } private static void Restore(Skills skills, SaveState state) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if (state == null || state.Restored) { return; } state.Restored = true; for (int i = 0; i < state.TemporaryInfos.Count; i++) { TemporaryInfo temporaryInfo = state.TemporaryInfos[i]; if (temporaryInfo.Skill != null && temporaryInfo.Skill.m_info == temporaryInfo.Injected) { temporaryInfo.Skill.m_info = temporaryInfo.Original; } } if ((Object)(object)skills == (Object)null || skills.m_skillData == null) { return; } for (int j = 0; j < state.EmptyKeys.Count; j++) { SkillType key = state.EmptyKeys[j]; if (!skills.m_skillData.ContainsKey(key)) { skills.m_skillData[key] = null; } } } private static string GetSavePatchOwners() { try { MethodInfo methodInfo = AccessTools.Method(typeof(Skills), "Save", new Type[1] { typeof(ZPackage) }, (Type[])null); Patches val = ((methodInfo != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo) : null); return (val != null && val.Owners != null) ? string.Join(", ", val.Owners) : "none"; } catch { return "unavailable"; } } private static void Warn(string message) { if (BesRuntime.Log != null) { BesRuntime.Log.LogWarning((object)("[BES save guard] " + message)); } } } internal static class BesBootstrap { internal static void Start(Launch plugin, ManualLogSource log) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown if ((Object)(object)plugin == (Object)null) { throw new ArgumentNullException("plugin"); } if (log == null) { throw new ArgumentNullException("log"); } if (!BesRuntime.Started) { BesRuntime.Instance = plugin; BesRuntime.Log = log; log.LogInfo((object)"[BES bootstrap 1/8] Initializing ServerSync and configuration."); ConfigSync configSync = new ConfigSync("balrond.astafaraios.BalrondExtraSkills") { DisplayName = "BalrondExtraSkills", CurrentVersion = "0.4.5", MinimumRequiredVersion = "0.4.5" }; ExtraSkillsConfig extraSkillsConfig = new ExtraSkillsConfig((BaseUnityPlugin)(object)plugin, configSync); configSync.AddLockingConfigEntry<bool>(extraSkillsConfig.LockConfiguration); BesRuntime.ConfigSyncInstance = configSync; BesRuntime.Settings = extraSkillsConfig; log.LogInfo((object)("[BES config] Bound configuration entries: Sailing=" + (extraSkillsConfig.SailingEnabled != null) + ", Taming=" + (extraSkillsConfig.TamingEnabled != null) + ", TotalHUD=" + (extraSkillsConfig.TotalHudEnabled != null) + ".")); log.LogInfo((object)"[BES bootstrap 2/8] Initializing Harmony."); Harmony harmony = new Harmony("balrond.astafaraios.BalrondExtraSkills"); BesRuntime.HarmonyInstance = harmony; log.LogInfo((object)"[BES bootstrap 3/8] Loading translation data."); RunStage(log, "translation loading", delegate { BesRuntime.JsonLoader = new JsonLoader(); BesRuntime.JsonLoader.loadJson(); }); log.LogInfo((object)"[BES bootstrap 4/8] Applying Harmony patches for the current Valheim API."); RunStage(log, "Harmony compatibility registration", delegate { HarmonyCompat.PatchAssembly(harmony, typeof(Launch).Assembly, log); }); RunStage(log, "Harmony diagnostics", delegate { PatchDiagnostics.Report(log); }); RunStage(log, "localization refresh", TranslationPatches.RefreshCurrentLanguage); log.LogInfo((object)"[BES bootstrap 5/8] Loading embedded assets."); RunStage(log, "embedded asset loading", delegate { BesRuntime.ModResourceLoader = new ModResourceLoader(); BesRuntime.ModResourceLoader.loadAssets(); }); log.LogInfo((object)"[BES bootstrap 6/8] Registering custom skills."); RegisterSkillsSafe(log); log.LogInfo((object)"[BES bootstrap 7/8] Refreshing skill assets and definitions."); RunStage(log, "skill definition refresh", BalrondSkillSystem.NotifyAssetsReady); log.LogInfo((object)"[BES bootstrap 8/8] Warming compatibility bridges and HUD."); RunStage(log, "SkillsReworked compatibility warmup", SkillsReworkedCompat.Warmup); RunStage(log, "OdinHorse compatibility warmup", OdinHorseCompat.Warmup); RunStage(log, "MonsterMayhem Taming compatibility warmup", MonsterMayhemTamingCompat.Warmup); RunStage(log, "Total Level HUD initialization", TotalLevelHud.Ensure); RunStage(log, "compatibility report", ReportCompatibility); BesRuntime.Started = true; log.LogInfo((object)"BalrondExtraSkills 0.4.5 loaded with ServerSync."); } } internal static void Stop() { SneakSpeedBonus.ResetRuntimeState(); VitalitySkill.ResetRuntimeState(); ArcanaSkill.ResetRuntimeState(); EnduranceSkill.ResetRuntimeState(); ExplorationSkill.ResetRuntimeState(); FortitudeSkill.ResetRuntimeState(); HaulingSkill.ResetRuntimeState(); SailingSkill.ResetRuntimeState(); TamingSkill.ResetRuntimeState(); ResourceRegenerationBonus.ResetRuntimeState(); SkillRuntime.InvalidateAllLevelCache(); TotalLevelService.Invalidate(); ResourceCapacityBonus.Invalidate(); try { Harmony harmonyInstance = BesRuntime.HarmonyInstance; if (harmonyInstance != null) { harmonyInstance.UnpatchSelf(); } } catch (Exception ex) { if (BesRuntime.Log != null) { BesRuntime.Log.LogError((object)("BalrondExtraSkills: Failed during Harmony shutdown. " + ex)); } } finally { BesRuntime.Started = false; BesRuntime.Settings = null; BesRuntime.ConfigSyncInstance = null; BesRuntime.HarmonyInstance = null; BesRuntime.ModResourceLoader = null; BesRuntime.JsonLoader = null; BesRuntime.Log = null; BesRuntime.Instance = null; } } private static void RunStage(ManualLogSource log, string name, Action action) { if (action == null) { return; } try { action(); } catch (Exception ex) { log.LogError((object)("[BES bootstrap] " + name + " failed. Remaining independent systems will continue. " + ex)); } } private static void RegisterSkillsSafe(ManualLogSource log) { TryRegisterSkill(log, () => VitalitySkill.Instance, "VitalitySkill"); TryRegisterSkill(log, () => ArcanaSkill.Instance, "ArcanaSkill"); TryRegisterSkill(log, () => FortitudeSkill.Instance, "FortitudeSkill"); TryRegisterSkill(log, () => EnduranceSkill.Instance, "EnduranceSkill"); TryRegisterSkill(log, () => HaulingSkill.Instance, "HaulingSkill"); TryRegisterSkill(log, () => ExplorationSkill.Instance, "ExplorationSkill"); TryRegisterSkill(log, () => SailingSkill.Instance, "SailingSkill"); TryRegisterSkill(log, () => TamingSkill.Instance, "TamingSkill"); } private static void TryRegisterSkill(ManualLogSource log, Func<BaseSkill> getter, string skillName) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 try { BaseSkill baseSkill = getter?.Invoke(); if (baseSkill == null) { log.LogWarning((object)("BalrondExtraSkills: Skill instance for " + skillName + " is null.")); } else if ((int)baseSkill.SkillType == 0) { log.LogWarning((object)("BalrondExtraSkills: Skill " + skillName + " has SkillType.None after initialization. Check FixedSkillId / registration.")); } } catch (Exception ex) { log.LogError((object)("BalrondExtraSkills: Failed to initialize skill " + skillName + ". " + ex)); } } private static void ReportCompatibility() { ExtraSkillsConfig settings = BesRuntime.Settings; ManualLogSource log = BesRuntime.Log; if (settings != null && log != null && settings.LogCompatibility.Value) { log.LogInfo((object)("[BES compatibility] BAO=" + ModPresenceCompat.IsBaoActive + ", MonsterMayhem=" + ModPresenceCompat.IsMonsterMayhemActive + " (Taming=" + MonsterMayhemTamingCompat.Status + "), SkillsReworked=" + SkillsReworkedCompat.IsActive + " (" + SkillsReworkedCompat.Version + "), DualMastery=" + ModPresenceCompat.IsDualMasteryActive + ", BetterArchery=" + ModPresenceCompat.IsBetterArcheryActive + ", OdinHorse=" + OdinHorseCompat.IsActive + " (" + OdinHorseCompat.Version + ", " + OdinHorseCompat.BindingStatus + "), Windstride=" + ModPresenceCompat.IsWindstrideBowAnimationsActive + ", NegativeSkills=" + NegativeSkillsCompat.IsActive + ", RuneforgingSkillId=" + 16050 + ", SRBindings={" + SkillsReworkedCompat.BindingStatus + "}")); } } } internal static class BesRuntime { internal static Launch Instance; internal static ManualLogSource Log; internal static Harmony HarmonyInstance; internal static ConfigSync ConfigSyncInstance; internal static ExtraSkillsConfig Settings; internal static ModResourceLoader ModResourceLoader; internal static JsonLoader JsonLoader; internal static bool Started; } internal sealed class ConfigurationManagerAttributes { public int? Order = null; public bool? Browsable = null; public string Category = null; public string DispName = null; public bool? IsAdvanced = null; public bool? ReadOnly = null; public bool? HideDefaultButton = null; public bool? ShowRangeAsPercent = null; public object DefaultValue = null; } internal static class PlayerActivitySampler { [HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })] private static class Player_UpdateStats_Patch { [HarmonyPostfix] private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { SneakSpeedBonus.OnPlayerStatsUpdate(__instance); HaulingSkill.OnPlayerStatsUpdate(__instance); SailingSkill.OnPlayerStatsUpdate(__instance); } } } } internal static class ResourceCapacityBonus { [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static class Player_GetTotalFoodValue_Patch { [HarmonyPostfix] private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { GetBonuses(__instance, out var hp2, out var stamina2, out var eitr2); hp = Mathf.Max(1f, hp + hp2); stamina = Mathf.Max(1f, stamina + stamina2); eitr = Mathf.Max(0f, eitr + eitr2); } } private const float CacheSeconds = 0.15f; private static Player s_player; private static float s_expiresAt; private static float s_hpBonus; private static float s_staminaBonus; private static float s_eitrBonus; private static void GetBonuses(Player player, out float hp, out float stamina, out float eitr) { if ((Object)(object)player == (Object)null) { hp = (stamina = (eitr = 0f)); return; } bool flag = (Object)(object)player == (Object)(object)Player.m_localPlayer; if (flag && (Object)(object)s_player == (Object)(object)player && Time.unscaledTime < s_expiresAt) { hp = s_hpBonus; stamina = s_staminaBonus; eitr = s_eitrBonus; return; } hp = VitalitySkill.GetBonusHp(player); stamina = EnduranceSkill.GetBonusStamina(player); eitr = ArcanaSkill.GetBonusEitr(player); if (flag) { s_player = player; s_hpBonus = hp; s_staminaBonus = stamina; s_eitrBonus = eitr; s_expiresAt = Time.unscaledTime + 0.15f; } } internal static void Invalidate() { s_player = null; s_expiresAt = 0f; } } internal static class SkillFloorSystem { [HarmonyPatch(typeof(Skills), "RaiseSkill")] private static class Skills_RaiseSkill_Milestone_Patch { [HarmonyPostfix] private static void Postfix(Skills __instance, SkillType skillType) { //IL_0025: 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_0044: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance) && !SkillsReworkedCompat.OwnsProgression(skillType)) { Skill skill = __instance.GetSkill(skillType); if (skill != null) { RefreshMilestone(localPlayer, skillType, skill.m_level); } } } } [HarmonyPatch(typeof(Player), "Load")] private static class PlayerLoadMilestonesPatch { [HarmonyPostfix] private static void Postfix(Player __instance) { if (SkillRuntime.IsLocal(__instance)) { RefreshAllMilestones(__instance); } } } [HarmonyPatch(typeof(Skills), "LowerAllSkills", new Type[] { typeof(float) })] private static class Skills_LowerAllSkills_Floors_Patch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(Skills __instance) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) ExtraSkillsConfig settings = BesRuntime.Settings; if (settings == null || !settings.SkillFloorsEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance || __instance.m_skillData == null) { return; } foreach (KeyValuePair<SkillType, Skill> skillDatum in __instance.m_skillData) { SkillType key = skillDatum.Key; Skill value = skillDatum.Value; if (value != null && !SkillsReworkedCompat.OwnsProgression(key)) { RefreshMilestone(localPlayer, key, value.m_level); int num = GetUnlockedFloor(localPlayer, key); if (settings.MasteredSkillProtection.Value && num >= 75) { num = 100; } if (value.m_level < (float)num) { value.m_level = num; } } } } } private const string Prefix = "BES_FLOOR_"; private static readonly FieldInfo PlayerCustomDataField = AccessTools.Field(typeof(Player), "m_customData"); internal static int GetUnlockedFloor(Player player, SkillType type) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected I4, but got Unknown if ((Object)(object)player == (Object)null) { return -100; } IDictionary customData = GetCustomData(player); if (customData == null) { return -100; } object obj = customData["BES_FLOOR_" + ((int)type).ToString(CultureInfo.InvariantCulture)]; int result; return (obj != null && int.TryParse(obj.ToString(), out result)) ? result : (-100); } internal static void RefreshMilestone(Player player, SkillType type, float level) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected I4, but got Unknown ExtraSkillsConfig settings = BesRuntime.Settings; if (settings == null || !settings.SkillFloorsEnabled.Value || (Object)(object)player == (Object)null) { return; } int num = -100; if (level >= 100f) { num = 75; } else if (level >= 75f) { num = 50; } else if (level >= 50f) { num = 25; } else { if (!(level >= 25f)) { return; } num = 0; } int unlockedFloor = GetUnlockedFloor(player, type); if (num > unlockedFloor) { IDictionary customData = GetCustomData(player); if (customData != null) { customData["BES_FLOOR_" + ((int)type).ToString(CultureInfo.InvariantCulture)] = num.ToString(CultureInfo.InvariantCulture); } } } internal static void RefreshAllMilestones(Player player) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) ExtraSkillsConfig settings = BesRuntime.Settings; if (settings == null || !settings.SkillFloorsEnabled.Value || (Object)(object)player == (Object)null) { return; } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null || skills.m_skillData == null) { return; } foreach (KeyValuePair<SkillType, Skill> skillDatum in skills.m_skillData) { if (skillDatum.Value != null && !SkillsReworkedCompat.OwnsProgression(skillDatum.Key)) { RefreshMilestone(player, skillDatum.Key, skillDatum.Value.m_level); } } } private static IDictionary GetCustomData(Player player) { try { return (PlayerCustomDataField != null) ? (PlayerCustomDataField.GetValue(player) as IDictionary) : null; } catch { return null; } } } internal static class SkillRuntime { private struct LocalLevelCacheEntry { internal Player Player; internal float ExpiresAt; internal float Level; } private const float LocalLevelCacheSeconds = 0.15f; private static readonly Dictionary<SkillType, LocalLevelCacheEntry> LocalLevelCache = new Dictionary<SkillType, LocalLevelCacheEntry>(); internal static float GetLevel(Player player, SkillType type, bool signed = true) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0021: 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_0052: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (int)type == 0) { return 0f; } if (BalrondSkillSystem.IsCustomSkill(type) && !BalrondSkillSystem.IsSkillEnabled(type)) { return 0f; } bool flag = IsLocal(player); if (flag && TryGetCachedLevel(player, type, out var level)) { return signed ? Mathf.Clamp(level, -100f, 100f) : Mathf.Clamp(level, 0f, 100f); } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null) { return 0f; } if (!SkillsReworkedCompat.IsManaged(type) || !SkillsReworkedCompat.TryGetEffectiveSkillLevel(player, type, out level)) { try { level = skills.GetSkillLevel(type); } catch { return 0f; } } level = SafeFinite(level); if (flag) { LocalLevelCache[type] = new LocalLevelCacheEntry { Player = player, ExpiresAt = Time.unscaledTime + 0.15f, Level = level }; } if (!signed) { return Mathf.Clamp(level, 0f, 100f); } return Mathf.Clamp(level, -100f, 100f); } private static bool TryGetCachedLevel(Player player, SkillType type, out float level) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) level = 0f; if (!LocalLevelCache.TryGetValue(type, out var value)) { return false; } if ((Object)(object)value.Player != (Object)(object)player || Time.unscaledTime >= value.ExpiresAt) { LocalLevelCache.Remove(type); return false; } level = value.Level; return true; } internal static void InvalidateLevelCache(SkillType type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) LocalLevelCache.Remove(type); } internal static void InvalidateAllLevelCache() { LocalLevelCache.Clear(); } internal static float SignedFactor(Player player, SkillType type) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return Mathf.Clamp(GetLevel(player, type) / 100f, -1f, 1f); } internal static float SignedFactor(float level) { return Mathf.Clamp(level / 100f, -1f, 1f); } internal static float PositiveFactor(Player player, SkillType type) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return Mathf.Clamp01(GetLevel(player, type, signed: false) / 100f); } internal static bool IsLocal(Player player) { return (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer; } internal static float SafeFinite(float value, float fallback = 0f) { return (float.IsNaN(value) || float.IsInfinity(value)) ? fallback : value; } } internal static class SkillXpRouter { [HarmonyPatch(typeof(Skills), "RaiseSkill")] private static class Skills_RaiseSkill_GlobalMultiplier_Patch { [HarmonyPrefix] private static bool Prefix(SkillType skillType, ref float factor) { //IL_0018: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (factor <= 0f) { return true; } if (BalrondSkillSystem.IsCustomSkill(skillType)) { if (BalrondSkillSystem.IsCollisionDisabled(skillType)) { return true; } if (!BalrondSkillSystem.IsSkillEnabled(skillType)) { return false; } return true; } if (s_internalRaise) { return true; } ExtraSkillsConfig settings = BesRuntime.Settings; if (settings == null) { return true; } if (SkillsReworkedCompat.OwnsProgression(skillType)) { return true; } factor *= Mathf.Max(0f, settings.GlobalXpMultiplier.Value) * Mathf.Max(0f, settings.GetXpMultiplier(skillType)); return true; } [HarmonyPostfix] private static void Postfix(SkillType skillType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) SkillRuntime.InvalidateLevelCache(skillType); TotalLevelService.Invalidate(); ResourceCapacityBonus.Invalidate(); } } [ThreadStatic] private static bool s_internalRaise; internal unsafe static void Raise(Player player, SkillType type, float amount, string source = null) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0023: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) if (!SkillRuntime.IsLocal(player) || amount <= 0f || (int)type == 0 || (BalrondSkillSystem.IsCustomSkill(type) && !BalrondSkillSystem.IsSkillEnabled(type))) { return; } ExtraSkillsConfig settings = BesRuntime.Settings; float num = ((settings != null) ? Mathf.Max(0f, settings.GlobalXpMultiplier.Value) : 1f); float num2 = ((settings != null) ? Mathf.Max(0f, settings.GetXpMultiplier(type)) : 1f); amount *= num * num2; if (amount <= 0f || float.IsNaN(amount) || float.IsInfinity(amount)) { return; } Skills skills = ((Character)player).GetSkills(); if (!((Object)(object)skills == (Object)null)) { s_internalRaise = true; try { skills.RaiseSkill(type, amount); } finally { s_internalRaise = false; } if (settings != null && settings.LogSkillXpEvents.Value && BesRuntime.Log != null) { bool flag = SkillsReworkedCompat.IsManaged(type); BesRuntime.Log.LogInfo((object)((flag ? "[BES XP->SR RaiseSkill] " : "[BES XP] ") + ((object)(*(SkillType*)(&type))/*cast due to .constrained prefix*/).ToString() + " +" + amount.ToString("0.###") + " source=" + (source ?? "unknown"))); } } } } internal enum TotalLevelProviderMode { Auto, NativeSkills, SkillsReworked } internal struct TotalLevelSnapshot { internal float ContinuousLevel; internal int WholeLevel; internal float Progress01; internal int SkillCount; internal bool SkillsReworkedPrimary; internal float SecondarySkillAverage; } internal static class TotalLevelService { private const float SnapshotCacheSeconds = 0.5f; private static readonly HashSet<SkillType> Seen = new HashSet<SkillType>(); private static Player s_cachedPlayer; private static float s_cacheExpiresAt; private static TotalLevelSnapshot s_cachedSnapshot; internal static void Invalidate() { s_cachedPlayer = null; s_cacheExpiresAt = 0f; } internal static TotalLevelSnapshot Get(Player player) { if ((Object)(object)player != (Object)null && (Object)(object)s_cachedPlayer == (Object)(object)player && Time.unscaledTime < s_cacheExpiresAt) { return s_cachedSnapshot; } TotalLevelSnapshot native = GetNative(player); if ((Object)(object)player == (Object)null) { return native; } TotalLevelProviderMode totalLevelProviderMode = ((BesRuntime.Settings != null) ? BesRuntime.Settings.TotalLevelProvider.Value : TotalLevelProviderMode.Auto); if ((totalLevelProviderMode == TotalLevelProviderMode.SkillsReworked || (totalLevelProviderMode == TotalLevelProviderMode.Auto && SkillsReworkedCompat.IsActive)) && SkillsReworkedCompat.TryGetCharacterProgress(player, out var level, out var progress)) { TotalLevelSnapshot totalLevelSnapshot = new TotalLevelSnapshot { ContinuousLevel = level + Mathf.Clamp01(progress), WholeLevel = Mathf.FloorToInt(level), Progress01 = Mathf.Clamp01(progress), SkillCount = native.SkillCount, SkillsReworkedPrimary = true, SecondarySkillAverage = native.ContinuousLevel }; Cache(player, totalLevelSnapshot); return totalLevelSnapshot; } Cache(player, native); return native; } internal static TotalLevelSnapshot GetNative(Player player) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) TotalLevelSnapshot result = default(TotalLevelSnapshot); if ((Object)(object)player == (Object)null) { return result; } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null || skills.m_skills == null) { return result; } Seen.Clear(); double num = 0.0; int num2 = 0; for (int i = 0; i < skills.m_skills.Count; i++) { SkillDef val = skills.m_skills[i]; if (val == null) { continue; } SkillType skill = val.m_skill; if (!IsEligible(skill) || !Seen.Add(skill)) { continue; } Skill skill2; try { skill2 = skills.GetSkill(skill); } catch { continue; } if (skill2 == null) { continue; } float num3 = 0f; float num4; if (SkillsReworkedCompat.IsActive && SkillsReworkedCompat.IsManaged(skill) && SkillsReworkedCompat.TryGetEffectiveSkillLevel(player, skill, out var level)) { num4 = Mathf.Clamp(level, 0f, 100f); num3 = 0f; } else { num4 = Mathf.Clamp(skill2.m_level, -100f, 100f); try { num3 = Mathf.Clamp01(skill2.GetLevelPercentage()); } catch { num3 = 0f; } } float num5 = num4 + num3; if (num4 >= 100f) { num5 = 100f; } num += (double)num5; num2++; } float num6 = ((num2 > 0) ? ((float)(num / (double)num2)) : 0f); int num7 = Mathf.FloorToInt(num6); float num8 = num6 - (float)num7; if (num8 < 0f) { num8 += 1f; } result.ContinuousLevel = num6; result.WholeLevel = num7; result.Progress01 = Mathf.Clamp01(num8); result.SkillCount = num2; result.SkillsReworkedPrimary = false; result.SecondarySkillAverage = num6; return result; } private static void Cache(Player player, TotalLevelSnapshot snapshot) { s_cachedPlayer = player; s_cachedSnapshot = snapshot; s_cacheExpiresAt = Time.unscaledTime + 0.5f; } private static bool IsEligible(SkillType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_004d: Unknown result type (might be due to invalid IL or missing references) if ((int)type == 0 || (int)type == 999) { return false; } if (SkillsReworkedCompat.IsVirtualSkill(type)) { return false; } if (BalrondSkillSystem.IsCustomSkill(type) && !BalrondSkillSystem.IsSkillEnabled(type)) { return false; } ExtraSkillsConfig settings = BesRuntime.Settings; return settings == null || !settings.IsExcludedFromTotalLevel(type); } } internal static class VanillaSkillTypes { internal static readonly SkillType Fists = Resolve("Fists", "Unarmed"); private static SkillType Resolve(params string[] names) { //IL_0046: 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) //IL_0024: 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) for (int i = 0; i < names.Length; i++) { try { object obj = Enum.Parse(typeof(SkillType), names[i], ignoreCase: true); if (obj != null) { return (SkillType)obj; } } catch { } } return (SkillType)0; } } public sealed class ModResourceLoader { public AssetBundle assetBundle; public readonly List<GameObject> itemPrefabs = new List<GameObject>(); public readonly List<GameObject> otherPrefabs = new List<GameObject>(); public static List<Sprite> skillIcons = new List<Sprite>(); public void loadAssets() { assetBundle = GetAssetBundleFromResources("balrondextraskills"); if ((Object)(object)assetBundle == (Object)null) { Debug.LogWarning((object)(Launch.projectName + " AssetBundle not found (embedded resource endswith 'BalrondExtraSkills').")); return; } string basePath = "Assets/Custom/BalrondExtraSkills/"; LoadSkillIcons(); loadItems(basePath); loadOther(basePath); } public void AddPrefabsToZnetScene(ZNetScene zNetScene) { if (!((Object)(object)zNetScene == (Object)null)) { validateAddedPrefabs(itemPrefabs, zNetScene); validateAddedPrefabs(otherPrefabs, zNetScene); } } public void AddItemsToObjectDB(ObjectDB db) { if ((Object)(object)db == (Object)null || db.m_items == null) { return; } for (int i = 0; i < itemPrefabs.Count; i++) { GameObject go = itemPrefabs[i]; if (!((Object)(object)go == (Object)null) && !((Object)(object)db.m_items.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == ((Object)go).name) != (Object)null)) { db.m_items.Add(go); } } } private void loadItems(string basePath) { string mainPath = basePath + "Items/"; string[] nameList = new string[0]; addNewPrefabToCollection(nameList, mainPath, itemPrefabs, "item", requireZNetView: false); } private void loadOther(string basePath) { string mainPath = basePath + "Other/"; string[] nameList = new string[0]; addNewPrefabToCollection(nameList, mainPath, otherPrefabs,