Decompiled source of SkillLimitExtender v1.2.0
plugins/skill_Limit_Extender.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using YamlDotNet.Core; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("skill_Limit_Extender")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+cea2b9e20772a06bbb13306900b8227aabb27c88")] [assembly: AssemblyProduct("skill_Limit_Extender")] [assembly: AssemblyTitle("skill_Limit_Extender")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SkillLimitExtender { [HarmonyPatch(typeof(Skills), "CheatRaiseSkill")] [HarmonyPatch(new Type[] { typeof(string), typeof(float), typeof(bool) })] internal static class SLE_CheatRaiseSkill_Transpiler { [HarmonyTranspiler] [HarmonyPriority(-9000)] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(SkillConfigManager), "GetCap", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(SkillConfigManager), "GetCapByName", (Type[])null, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(Skill), "m_info"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(SkillDef), "m_skill"); if (methodInfo == null || fieldInfo == null || fieldInfo2 == null) { return list; } for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (!(val.opcode == OpCodes.Ldc_R4) || !(val.operand is float num) || !(Math.Abs(num - 100f) < 0.0001f)) { continue; } bool flag = false; for (int j = Math.Max(0, i - 5); j < Math.Min(list.Count, i + 5); j++) { if (list[j].opcode == OpCodes.Call) { object operand = list[j].operand; if (operand != null && (operand.ToString()?.Contains("Clamp")).GetValueOrDefault()) { flag = true; break; } } } if (!flag || !(methodInfo2 != null)) { continue; } List<CodeInstruction> list2 = new List<CodeInstruction> { new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)methodInfo2), new CodeInstruction(OpCodes.Conv_R4, (object)null) }; list[i] = list2[0]; list.InsertRange(i + 1, list2.GetRange(1, list2.Count - 1)); ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogDebug((object)"[SLE] CheatRaiseSkill: Replaced 100f with GetCapByName(name)"); } } break; } return list; } } [HarmonyPatch(typeof(SkillsDialog), "Setup")] internal static class SLE_Hook_SkillsDialog_LevelBars { [HarmonyPrefix] private static bool Prefix(SkillsDialog __instance, ref Player player) { //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Invalid comparison between Unknown and I4 //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Invalid comparison between Unknown and I4 //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Expected I4, but got Unknown //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Expected I4, but got Unknown try { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { Player obj = player; logger.LogInfo((object)("[SLE] SkillsDialog.Setup - Player: " + (((obj != null) ? obj.GetPlayerName() : null) ?? "null"))); } if ((Object)(object)__instance == (Object)null) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogError((object)"[SLE] SkillsDialog instance is null - cannot proceed"); } return false; } if ((Object)(object)player == (Object)null) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogWarning((object)"[SLE] SkillsDialog.Setup called with null player - attempting to get local player"); } Player safeLocalPlayer = SLE_SkillHelpers.GetSafeLocalPlayer(); if (!((Object)(object)safeLocalPlayer != (Object)null)) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogError((object)"[SLE] Cannot get local player - skipping SkillsDialog.Setup"); } return false; } ManualLogSource logger5 = SkillLimitExtenderPlugin.Logger; if (logger5 != null) { logger5.LogInfo((object)"[SLE] Successfully recovered local player for SkillsDialog.Setup"); } player = safeLocalPlayer; } Skills skills = ((Character)player).GetSkills(); if ((Object)(object)skills == (Object)null) { ManualLogSource logger6 = SkillLimitExtenderPlugin.Logger; if (logger6 != null) { logger6.LogWarning((object)"[SLE] Player skills are null - skipping SkillsDialog.Setup"); } return false; } try { int cap = SkillConfigManager.GetCap((SkillType)1); ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger7 = SkillLimitExtenderPlugin.Logger; if (logger7 != null) { logger7.LogDebug((object)$"[SLE] SkillConfigManager test - Swords cap: {cap}"); } } } catch (Exception ex) { ManualLogSource logger8 = SkillLimitExtenderPlugin.Logger; if (logger8 != null) { logger8.LogError((object)("[SLE] SkillConfigManager is in invalid state: " + ex.Message)); } return false; } try { Dictionary<SkillType, Skill> value = Traverse.Create((object)skills).Field("m_skillData").GetValue<Dictionary<SkillType, Skill>>(); if (value != null) { int num = 0; int num2 = 0; foreach (KeyValuePair<SkillType, Skill> item in value) { SkillType key = item.Key; Skill value2 = item.Value; if ((int)key <= 999) { continue; } num++; if (value2 == null) { ManualLogSource logger9 = SkillLimitExtenderPlugin.Logger; if (logger9 != null) { logger9.LogWarning((object)$"[SLE] MOD skill {key} ({(int)key}) is null in m_skillData"); } continue; } SkillDef value3 = Traverse.Create((object)value2).Field("m_info").GetValue<SkillDef>(); if (value3 != null) { continue; } num2++; if ((int)key == 1337) { ManualLogSource logger10 = SkillLimitExtenderPlugin.Logger; if (logger10 != null) { logger10.LogWarning((object)$"[SLE] MOD skill 1337 has null m_info (level={value2.m_level})"); } continue; } ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger11 = SkillLimitExtenderPlugin.Logger; if (logger11 != null) { logger11.LogDebug((object)$"[SLE] MOD skill {key} ({(int)key}) has null m_info (level={value2.m_level})"); } } } ManualLogSource logger12 = SkillLimitExtenderPlugin.Logger; if (logger12 != null) { logger12.LogInfo((object)$"[SLE] Found {num} MOD skills ({num2} with null m_info)"); } } } catch (Exception ex2) { ManualLogSource logger13 = SkillLimitExtenderPlugin.Logger; if (logger13 != null) { logger13.LogWarning((object)("[SLE] Could not check MOD skills: " + ex2.Message)); } } ConfigEntry<bool> enableGrowthCurveDebug3 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug3 != null && enableGrowthCurveDebug3.Value) { ManualLogSource logger14 = SkillLimitExtenderPlugin.Logger; if (logger14 != null) { logger14.LogDebug((object)("[SLE] SkillsDialog.Setup proceeding with player: " + player.GetPlayerName())); } } return true; } catch (Exception arg) { ManualLogSource logger15 = SkillLimitExtenderPlugin.Logger; if (logger15 != null) { logger15.LogError((object)$"[SLE] SkillsDialog.Setup Prefix failed: {arg}"); } return false; } } [HarmonyTranspiler] [HarmonyPriority(-9000)] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Expected O, but got Unknown //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Expected O, but got Unknown try { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(SkillConfigManager), "GetUiDenominator", (Type[])null, (Type[])null); if (methodInfo == null) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogWarning((object)"[SLE] SkillsDialog: GetUiDenominator method missing; keeping original code"); } return list; } try { float uiDenominator = SkillConfigManager.GetUiDenominator(); if (uiDenominator <= 0f) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)$"[SLE] SkillsDialog: GetUiDenominator returned invalid value {uiDenominator}; keeping original code"); } return list; } } catch (Exception ex) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogError((object)("[SLE] SkillsDialog: GetUiDenominator test failed: " + ex.Message + "; keeping original code")); } return list; } int num = 0; for (int i = 0; i < list.Count - 1; i++) { CodeInstruction val = list[i]; CodeInstruction val2 = list[i + 1]; if (!(val.opcode == OpCodes.Ldc_R4) || !(val.operand is float num2) || !(Math.Abs(num2 - 100f) < 0.0001f) || !(val2.opcode == OpCodes.Div)) { continue; } bool flag = false; for (int j = i + 1; j < Math.Min(list.Count, i + 12); j++) { if (list[j].opcode == OpCodes.Callvirt) { object operand = list[j].operand; if (operand != null && (operand.ToString()?.Contains("SetValue")).GetValueOrDefault()) { flag = true; break; } } } if (flag) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo); list.Insert(i + 1, new CodeInstruction(OpCodes.Conv_R4, (object)null)); i++; num++; } } ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogInfo((object)$"[SLE] SkillsDialog: Replaced {num} instances of 100f with global UI denominator"); } return list; } catch (Exception arg) { ManualLogSource logger5 = SkillLimitExtenderPlugin.Logger; if (logger5 != null) { logger5.LogError((object)$"[SLE] SkillsDialog Transpiler failed: {arg}"); } return instructions; } } } [HarmonyPatch(typeof(Skills), "GetSkillFactor")] internal static class SLE_Hook_Skills_GetSkillFactor { [HarmonyPrefix] private static bool Prefix(Skills __instance, SkillType skillType, ref float __result) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) try { float num = __instance.GetSkillSafe(skillType)?.m_level ?? 0f; int num2 = Math.Max(1, SkillConfigManager.GetBonusCap(skillType)); float num3 = (float)num2 / 100f; float num6; if (SkillConfigManager.IsRelative(skillType)) { int cap = SkillConfigManager.GetCap(skillType); float num4 = ((cap > 0) ? ((float)cap) : 100f); float num5 = ((num4 > 0f) ? (num / num4) : 0f); num6 = num5 * num3; } else { float factorDenominator = SkillConfigManager.GetFactorDenominator(skillType); num6 = num / factorDenominator; } if (num6 < 0f) { num6 = 0f; } if (num6 > num3) { num6 = num3; } __result = num6; return false; } catch { return true; } } } [HarmonyPatch(typeof(Skills), "Save")] internal static class SLE_Hook_Skills_Save_Cleanup { [HarmonyPrefix] private static bool Prefix(Skills __instance, ZPackage pkg) { //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: 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_01c7: Expected I4, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected I4, but got Unknown //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Expected I4, but got Unknown //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Invalid comparison between Unknown and I4 //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) try { if (!(AccessTools.Field(typeof(Skills), "m_skillData")?.GetValue(__instance) is IDictionary<SkillType, Skill> dictionary)) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogError((object)"[SLE] Skills.Save: m_skillData is null!"); } pkg.Write(2); pkg.Write(0); return false; } List<KeyValuePair<SkillType, Skill>> list = new List<KeyValuePair<SkillType, Skill>>(); int num = 0; foreach (KeyValuePair<SkillType, Skill> item in dictionary) { SkillType key = item.Key; Skill value = item.Value; if (value == null) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)$"[SLE] Skills.Save: Skipping null skill {key}"); } num++; continue; } try { SkillDef value2 = Traverse.Create((object)value).Field("m_info").GetValue<SkillDef>(); if (value2 == null) { int num2 = (int)key; string skillKey = ((object)(SkillType)(ref key)).ToString(); if (num2 > 999 || IsSkillDefinedInYaml(skillKey)) { ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogDebug((object)$"[SLE] Skills.Save: Including custom skill {key} (ID: {num2}) with null m_info"); } } list.Add(item); } else if ((int)key > 0) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogWarning((object)$"[SLE] Skills.Save: Skipping vanilla skill {key} with null m_info"); } num++; } continue; } SkillType value3 = Traverse.Create((object)value2).Field("m_skill").GetValue<SkillType>(); int num3 = (int)key; if (num3 > 999) { if (!Enum.IsDefined(typeof(SkillType), value3)) { ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger5 = SkillLimitExtenderPlugin.Logger; if (logger5 != null) { logger5.LogDebug((object)$"[SLE] Skills.Save: Including MOD skill {key} (ID: {num3}) with undefined m_info.m_skill value {value3}"); } } } else { ConfigEntry<bool> enableGrowthCurveDebug3 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug3 != null && enableGrowthCurveDebug3.Value) { ManualLogSource logger6 = SkillLimitExtenderPlugin.Logger; if (logger6 != null) { logger6.LogDebug((object)$"[SLE] Skills.Save: Including MOD skill {key} (ID: {num3})"); } } } list.Add(item); } else if (!Enum.IsDefined(typeof(SkillType), value3)) { ManualLogSource logger7 = SkillLimitExtenderPlugin.Logger; if (logger7 != null) { logger7.LogWarning((object)$"[SLE] Skills.Save: Skipping vanilla skill '{key}' (ID: {num3}) with invalid m_info.m_skill value {value3}"); } num++; } else if (num3 <= 999 && value3 != key) { ManualLogSource logger8 = SkillLimitExtenderPlugin.Logger; if (logger8 != null) { logger8.LogWarning((object)$"[SLE] Skills.Save: Skipping skill '{key}' (ID: {num3}) with mismatched m_info.m_skill value {value3}"); } num++; } else { list.Add(item); } } catch (Exception ex) { ManualLogSource logger9 = SkillLimitExtenderPlugin.Logger; if (logger9 != null) { logger9.LogWarning((object)$"[SLE] Skills.Save: Skipping skill {key} due to error: {ex.Message}"); } num++; } } pkg.Write(2); pkg.Write(list.Count); foreach (KeyValuePair<SkillType, Skill> item2 in list) { try { Skill value4 = item2.Value; SkillType key2 = item2.Key; SkillDef value5 = Traverse.Create((object)value4).Field("m_info").GetValue<SkillDef>(); SkillType val = ((value5 == null) ? key2 : Traverse.Create((object)value5).Field("m_skill").GetValue<SkillType>()); pkg.Write((int)val); pkg.Write(value4.m_level); pkg.Write(value4.m_accumulator); } catch (Exception ex2) { ManualLogSource logger10 = SkillLimitExtenderPlugin.Logger; if (logger10 != null) { logger10.LogError((object)$"[SLE] Skills.Save: Failed to write skill {item2.Key}: {ex2.Message}"); } } } if (num > 0) { ManualLogSource logger11 = SkillLimitExtenderPlugin.Logger; if (logger11 != null) { logger11.LogWarning((object)$"[SLE] Skills.Save: Saved {list.Count} valid skills, skipped {num} invalid skills"); } } else { ConfigEntry<bool> enableGrowthCurveDebug4 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug4 != null && enableGrowthCurveDebug4.Value) { ManualLogSource logger12 = SkillLimitExtenderPlugin.Logger; if (logger12 != null) { logger12.LogDebug((object)$"[SLE] Skills.Save: Successfully saved {list.Count} skills"); } } } return false; } catch (Exception arg) { ManualLogSource logger13 = SkillLimitExtenderPlugin.Logger; if (logger13 != null) { logger13.LogError((object)$"[SLE] Skills.Save replacement failed: {arg}"); } return true; } } private static bool IsSkillDefinedInYaml(string skillKey) { try { if (typeof(SkillConfigManager).GetField("_entriesByName", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) is Dictionary<string, YamlExporter.SkillYamlEntry> dictionary) { return dictionary.ContainsKey(skillKey); } return false; } catch { return false; } } } internal static class SLE_SkillsExtensions { private static readonly MethodInfo _miGetSkill = AccessTools.Method(typeof(Skills), "GetSkill", new Type[1] { typeof(SkillType) }, (Type[])null); private static readonly FieldInfo _fiSkillData = AccessTools.Field(typeof(Skills), "m_skillData"); internal static Skill? GetSkillSafe(this Skills skills, SkillType st) { //IL_0032: 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_0044: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skills == (Object)null) { return null; } if (_miGetSkill != null) { try { return (Skill)_miGetSkill.Invoke(skills, new object[1] { st }); } catch { } } if (_fiSkillData != null) { try { if (_fiSkillData.GetValue(skills) is IDictionary<SkillType, Skill> dictionary && dictionary.TryGetValue(st, out var value)) { return value; } } catch { } } return null; } } internal static class SLE_SkillHelpers { internal static Player? GetSafeLocalPlayer() { try { if ((Object)(object)Player.m_localPlayer != (Object)null) { return Player.m_localPlayer; } Game instance = Game.instance; if (instance != null) { PlayerProfile playerProfile = instance.GetPlayerProfile(); if (((playerProfile != null) ? new long?(playerProfile.GetPlayerID()) : null) == 0) { goto IL_00d9; } } List<Player> allPlayers = Player.GetAllPlayers(); if (allPlayers != null && allPlayers.Count > 0) { foreach (Player item in allPlayers) { if ((Object)(object)item != (Object)null && ((Character)item).IsOwner()) { return item; } } } goto IL_00d9; IL_00d9: return null; } catch { return null; } } } [HarmonyPatch(typeof(Skill), "Raise")] internal static class SLE_Skill_Raise_Transpiler { public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); FieldInfo fieldInfo = AccessTools.Field(typeof(Skill), "m_info"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(SkillDef), "m_skill"); MethodInfo methodInfo = AccessTools.Method(typeof(SkillConfigManager), "GetCap", (Type[])null, (Type[])null); if (fieldInfo == null || fieldInfo2 == null || methodInfo == null) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogError((object)"[SLE] Transpiler failed: Cannot find required fields/methods"); } return list; } bool flag = false; int num = 0; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Ldc_R4 && val.operand is float num2 && Math.Abs(num2 - 100f) < 0.0001f) { List<CodeInstruction> list2 = new List<CodeInstruction>(); list2.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SLE_Skill_Raise_Transpiler), "GetSkillTypeFromInstance", (Type[])null, (Type[])null))); list2.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo)); list2.Add(new CodeInstruction(OpCodes.Conv_R4, (object)null)); List<CodeInstruction> list3 = list2; list[i] = list3[0]; list.InsertRange(i + 1, list3.GetRange(1, list3.Count - 1)); i += list3.Count - 1; num++; ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[SLE] Skill.Raise: Replaced 100f #{num} with GetCap(GetSkillTypeFromInstance()) at position {i}"); } flag = true; } } if (!flag) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogWarning((object)"[SLE] Transpiler: No 100f constant found to replace in Skills.Skill.Raise"); } } return list; } internal static SkillType GetSkillTypeFromInstance(Skill skillInstance) { //IL_0034: 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) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) try { SkillDef value = Traverse.Create((object)skillInstance).Field("m_info").GetValue<SkillDef>(); if (value != null) { SkillType value2 = Traverse.Create((object)value).Field("m_skill").GetValue<SkillType>(); if (int.TryParse(((object)(SkillType)(ref value2)).ToString(), out var result) && result == 1337) { ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[SLE DEBUG Transpiler] Skill 1337 found via m_info path, returning: {value2}"); } } } return value2; } Player safeLocalPlayer = SLE_SkillHelpers.GetSafeLocalPlayer(); Skills val = ((safeLocalPlayer != null) ? ((Character)safeLocalPlayer).GetSkills() : null); if ((Object)(object)val != (Object)null) { Dictionary<SkillType, Skill> value3 = Traverse.Create((object)val).Field("m_skillData").GetValue<Dictionary<SkillType, Skill>>(); if (value3 != null) { foreach (KeyValuePair<SkillType, Skill> item in value3) { if (item.Value != skillInstance) { continue; } SkillType key = item.Key; if (int.TryParse(((object)(SkillType)(ref key)).ToString(), out var result2) && result2 == 1337) { ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[SLE DEBUG Transpiler] Skill 1337 found via skillData search, returning: {item.Key}"); } } } return item.Key; } } } ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogWarning((object)"[SLE DEBUG Transpiler] Could not find skill type for instance, returning None"); } return (SkillType)0; } catch (Exception ex) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogError((object)("[SLE DEBUG Transpiler] Exception in GetSkillTypeFromInstance: " + ex.Message)); } return (SkillType)0; } } } [HarmonyPatch(typeof(Skill), "Raise")] internal static class SLE_Skill_Raise_Debug { [HarmonyPatch(typeof(Skill), "GetLevelPercentage")] internal static class SLE_Skill_GetLevelPercentage_Patch { [HarmonyPrefix] private static bool Prefix(Skill __instance, ref float __result) { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011f: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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) try { SkillDef value = Traverse.Create((object)__instance).Field("m_info").GetValue<SkillDef>(); SkillType val2; if (value == null) { Player safeLocalPlayer = SLE_SkillHelpers.GetSafeLocalPlayer(); Skills val = ((safeLocalPlayer != null) ? ((Character)safeLocalPlayer).GetSkills() : null); if ((Object)(object)val != (Object)null) { Dictionary<SkillType, Skill> value2 = Traverse.Create((object)val).Field("m_skillData").GetValue<Dictionary<SkillType, Skill>>(); if (value2 != null) { foreach (KeyValuePair<SkillType, Skill> item in value2) { if (item.Value != __instance) { continue; } val2 = item.Key; ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogDebug((object)$"[SLE] Found MOD skill type {val2} for skill with null m_info"); } } goto IL_011e; } } } return true; } val2 = Traverse.Create((object)value).Field("m_skill").GetValue<SkillType>(); goto IL_011e; IL_011e: int cap = SkillConfigManager.GetCap(val2); if (__instance.m_level >= (float)cap) { __result = 0f; return false; } float num = CalculateNextLevelRequirement(__instance, val2); __result = Mathf.Clamp01(__instance.m_accumulator / num); return false; } catch (Exception ex) { if (SkillLimitExtenderPlugin.EnableGrowthCurveDebug.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogError((object)("[SLE Growth Curve] Error in GetLevelPercentage patch: " + ex.Message)); } } return true; } } private static float CalculateNextLevelRequirement(Skill skill, SkillType skillType) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_00a5: 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_004d: Unknown result type (might be due to invalid IL or missing references) try { bool flag = SkillConfigManager.UseCustomGrowthCurve(skillType); float level = skill.m_level; float num; if (!flag) { num = Mathf.Pow(Mathf.Floor(level + 1f), 1.5f) * 0.5f + 0.5f; if (SkillLimitExtenderPlugin.EnableGrowthCurveDebug.Value) { string skillDisplayName = SkillConfigManager.GetSkillDisplayName(skillType); ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)($"[SLE Growth Curve] Skill: {skillDisplayName}, Level: {level:F1}, " + $"Mode: Vanilla, Result: {num:F2}")); } } } else { float growthExponent = SkillConfigManager.GetGrowthExponent(skillType); float growthMultiplier = SkillConfigManager.GetGrowthMultiplier(skillType); float growthConstant = SkillConfigManager.GetGrowthConstant(skillType); num = growthMultiplier * Mathf.Pow(level + growthConstant, growthExponent); if (SkillLimitExtenderPlugin.EnableGrowthCurveDebug.Value) { string skillDisplayName2 = SkillConfigManager.GetSkillDisplayName(skillType); float num2 = Mathf.Pow(Mathf.Floor(level + 1f), 1.5f) * 0.5f + 0.5f; ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)($"[SLE Growth Curve] Skill: {skillDisplayName2}, Level: {level:F1}, " + $"Mode: Custom, Params: exp={growthExponent:F2}, mult={growthMultiplier:F2}, const={growthConstant:F2}, " + $"Vanilla: {num2:F2}, Custom: {num:F2}")); } } } return num; } catch (Exception ex) { if (SkillLimitExtenderPlugin.EnableGrowthCurveDebug.Value) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogError((object)("[SLE Growth Curve] Error in CalculateNextLevelRequirement: " + ex.Message)); } } float level2 = skill.m_level; return Mathf.Pow(Mathf.Floor(level2 + 1f), 1.5f) * 0.5f + 0.5f; } } } [HarmonyPrefix] private static void Prefix(Skill __instance, float factor, out float __state) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) __state = __instance.m_level; SkillType skillTypeFromInstance = SLE_Skill_Raise_Transpiler.GetSkillTypeFromInstance(__instance); if (!int.TryParse(((object)(SkillType)(ref skillTypeFromInstance)).ToString(), out var result) || result != 1337) { return; } ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[SLE DEBUG Raise] BEFORE - Skill 1337: Level={__instance.m_level:F2}, Accumulator={__instance.m_accumulator:F2}, Factor={factor:F4}"); } } } [HarmonyPostfix] private static void Postfix(Skill __instance, float factor, float __state) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) SkillType skillTypeFromInstance = SLE_Skill_Raise_Transpiler.GetSkillTypeFromInstance(__instance); if (!int.TryParse(((object)(SkillType)(ref skillTypeFromInstance)).ToString(), out var result) || result != 1337) { return; } float num = __instance.m_level - __state; ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[SLE DEBUG Raise] AFTER - Skill 1337: Level={__instance.m_level:F2} (change: {num:F2}), Accumulator={__instance.m_accumulator:F2}"); } } if (num > 0f) { ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[SLE DEBUG Raise] *** LEVEL UP DETECTED *** Skill 1337 leveled up by {num:F2}!"); } } } if (__instance.m_level >= 100f) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogInfo((object)$"[SLE] Skill 1337 reached level {__instance.m_level:F2} (cap: 250)"); } } } } internal static class SLE_TerminalCommands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; public static ConsoleEvent <>9__0_1; internal void <Register>b__0_0(ConsoleEventArgs args) { ZNet instance = ZNet.instance; if (instance != null && instance.IsServer()) { SkillConfigManager.ReloadFromYaml(); SkillConfigManager.SendConfigToClientsIfChanged(); args.Context.AddString("SLE: reloaded YAML; broadcasted only if changed."); } else { SkillConfigManager.ReloadFromYaml(); args.Context.AddString("SLE: reloaded local YAML."); } } internal void <Register>b__0_1(ConsoleEventArgs args) { args.Context.AddString("SLE YAML path: " + YamlExporter.GetYamlPath()); } } public static void Register() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_006c: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown try { object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { ZNet instance = ZNet.instance; if (instance != null && instance.IsServer()) { SkillConfigManager.ReloadFromYaml(); SkillConfigManager.SendConfigToClientsIfChanged(); args.Context.AddString("SLE: reloaded YAML; broadcasted only if changed."); } else { SkillConfigManager.ReloadFromYaml(); args.Context.AddString("SLE: reloaded local YAML."); } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("sle_yaml_reload", "Reload SLE YAML", (ConsoleEvent)obj, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__0_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { args.Context.AddString("SLE YAML path: " + YamlExporter.GetYamlPath()); }; <>c.<>9__0_1 = val2; obj2 = (object)val2; } new ConsoleCommand("sle_yaml_path", "Show current SLE YAML path", (ConsoleEvent)obj2, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } catch (Exception arg) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogError((object)$"[SLE] Failed to register console command: {arg}"); } } } } internal static class SLE_VersionHandshake { internal static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>(); internal static void RPC_SLE_Version(ZRpc rpc, ZPackage pkg) { try { string text = pkg.ReadString(); ZNet instance = ZNet.instance; bool flag = instance != null && instance.IsServer(); ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)("[SLE] Version check: remote=" + text + ", local=1.2.0")); } if (text != "1.2.0") { if (flag) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)"[SLE] Incompatible client version; disconnecting"); } rpc.Invoke("Error", new object[1] { 3 }); } else { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogWarning((object)"[SLE] Server version differs; features may be limited"); } } } else if (flag) { ValidatedPeers.Add(rpc); } else { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogInfo((object)"[SLE] Server and client versions match"); } } } catch (EndOfStreamException ex) { ManualLogSource logger5 = SkillLimitExtenderPlugin.Logger; if (logger5 != null) { logger5.LogError((object)("[SLE] Version handshake failed - incompatible data format: " + ex.Message)); } rpc.Invoke("Error", new object[1] { 3 }); } catch (Exception arg) { ManualLogSource logger6 = SkillLimitExtenderPlugin.Logger; if (logger6 != null) { logger6.LogError((object)$"[SLE] Version handshake error: {arg}"); } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] internal static class SLE_VersionHandshake_OnNewConnection { [HarmonyPrefix] private static void Prefix(ZNetPeer peer, ZNet __instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown peer.m_rpc.Register<ZPackage>("SLE_Version", (Action<ZRpc, ZPackage>)SLE_VersionHandshake.RPC_SLE_Version); ZPackage val = new ZPackage(); val.Write("1.2.0"); peer.m_rpc.Invoke("SLE_Version", new object[1] { val }); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] internal static class SLE_VersionHandshake_VerifyClient { [HarmonyPrefix] private static bool Prefix(ZRpc rpc, ZPackage pkg, ZNet __instance) { if (__instance.IsServer() && !SLE_VersionHandshake.ValidatedPeers.Contains(rpc)) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogWarning((object)"[SLE] Peer never sent version; disconnecting"); } rpc.Invoke("Error", new object[1] { 3 }); return false; } return true; } } [HarmonyPatch(typeof(ZNet), "Disconnect")] internal static class SLE_VersionHandshake_RemovePeerOnDisconnect { [HarmonyPrefix] private static void Prefix(ZNetPeer peer, ZNet __instance) { if (__instance.IsServer()) { ZRpc val = peer?.m_rpc; if (val != null) { SLE_VersionHandshake.ValidatedPeers.Remove(val); } } } } internal static class SkillConfigManager { internal static ConfigEntry<bool> ServerConfigLocked = null; internal static ConfigEntry<bool> EnableYamlOverride = null; private static Dictionary<string, YamlExporter.SkillYamlEntry> _entriesByName = new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); private static bool _initialized; private static bool _isServerConfig; private static string _lastYamlHash = string.Empty; private static HashSet<int> _warnedSkillIds = new HashSet<int>(); private static readonly Dictionary<int, string> _skillKeyCache = new Dictionary<int, string>(); private static DateTime _lastSkillKeyCacheUpdate = DateTime.MinValue; private static readonly TimeSpan SkillKeyCacheExpiry = TimeSpan.FromMinutes(5.0); internal const int DefaultCapFallback = 250; internal const int DefaultBonusCapFallback = 100; internal static void Initialize(ConfigFile config) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown if (!_initialized) { ServerConfigLocked = config.Bind<bool>("Server", "LockConfiguration", false, new ConfigDescription("If true, server forces its configuration to all clients. (Admin Only)", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Category = "Server", Order = -1000, IsAdminOnly = true } })); EnableYamlOverride = config.Bind<bool>("General", "EnableYamlOverride", true, new ConfigDescription("Allow YAML file to override individual skill caps/bonus/relative", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Category = "Skill Level", Order = -85 } })); ReloadFromYaml(); _initialized = true; ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)"[SLE] Configuration loaded"); } } } internal static void OnYamlReceivedStatic(long sender, string yamlContent, int protocolVersion) { OnYamlReceived(sender, yamlContent, protocolVersion); } internal static void ReloadFromYaml() { if (_isServerConfig || (EnableYamlOverride != null && !EnableYamlOverride.Value)) { if (!_isServerConfig) { return; } ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)"[SLE] Using server configuration (YAML disabled locally)"); } } return; } try { Dictionary<string, YamlExporter.SkillYamlEntry> dictionary = YamlExporter.LoadYamlEntries(); if (dictionary != null) { _entriesByName = dictionary; _skillKeyCache.Clear(); ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[SLE] YAML reloaded successfully ({_entriesByName.Count} entries)"); } } return; } ConfigEntry<bool> enableGrowthCurveDebug3 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug3 != null && enableGrowthCurveDebug3.Value) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogWarning((object)"[SLE] YAML reload returned null, keeping existing configuration"); } } _entriesByName = _entriesByName ?? new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); } catch (Exception ex) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogError((object)("[SLE] YAML reload failed: " + ex.Message)); } _entriesByName = _entriesByName ?? new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); } } private static string GetSkillKeyForLookup(SkillType st) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) string text = ((object)(SkillType)(ref st)).ToString(); string text2; if (int.TryParse(text, out var result) && result > 999) { if (DateTime.Now - _lastSkillKeyCacheUpdate > SkillKeyCacheExpiry) { _skillKeyCache.Clear(); _lastSkillKeyCacheUpdate = DateTime.Now; } if (_skillKeyCache.TryGetValue(result, out string value)) { return value; } text2 = text; if (_entriesByName != null) { if (_entriesByName.ContainsKey(text)) { ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[SLE] Using numeric key '" + text + "' for MOD skill")); } } _skillKeyCache[result] = text; return text; } string actualModSkillName = GetActualModSkillName(st); if (!string.IsNullOrEmpty(actualModSkillName) && !string.Equals(actualModSkillName, text, StringComparison.Ordinal)) { if (_entriesByName.ContainsKey(actualModSkillName)) { ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogDebug((object)$"[SLE] Mapping MOD skill ID {result} to actual name '{actualModSkillName}'"); } } text2 = actualModSkillName; _skillKeyCache[result] = text2; return text2; } string[] array = GenerateSkillNameVariations(actualModSkillName); string[] array2 = array; foreach (string text3 in array2) { if (!_entriesByName.ContainsKey(text3)) { continue; } ConfigEntry<bool> enableGrowthCurveDebug3 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug3 != null && enableGrowthCurveDebug3.Value) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogDebug((object)$"[SLE] Mapping MOD skill ID {result} to variation '{text3}' (from '{actualModSkillName}')"); } } text2 = text3; _skillKeyCache[result] = text2; return text2; } } string[] array3 = GenerateCommonModSkillNames(result); string[] array4 = array3; foreach (string text4 in array4) { if (!_entriesByName.ContainsKey(text4)) { continue; } ConfigEntry<bool> enableGrowthCurveDebug4 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug4 != null && enableGrowthCurveDebug4.Value) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogDebug((object)$"[SLE] Mapping MOD skill ID {result} to common name '{text4}'"); } } text2 = text4; _skillKeyCache[result] = text2; return text2; } if (!_warnedSkillIds.Contains(result)) { ConfigEntry<bool> enableGrowthCurveDebug5 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug5 != null && enableGrowthCurveDebug5.Value) { _warnedSkillIds.Add(result); string text5 = string.Join(", ", _entriesByName.Keys.Take(10)); string text6 = ((!string.IsNullOrEmpty(actualModSkillName) && !actualModSkillName.StartsWith("$")) ? actualModSkillName : text); ManualLogSource logger5 = SkillLimitExtenderPlugin.Logger; if (logger5 != null) { logger5.LogWarning((object)string.Format("[SLE] MOD skill ID {0} (name: '{1}') not found in YAML. Available keys: {2}... Please add '{3}' to your YAML file.", result, actualModSkillName ?? "Unknown", text5, text6)); } goto IL_0392; } } if (!_warnedSkillIds.Contains(result)) { _warnedSkillIds.Add(result); } } goto IL_0392; } return text; IL_0392: _skillKeyCache[result] = text2; return text2; } private static string[] GenerateSkillNameVariations(string skillName) { if (string.IsNullOrEmpty(skillName)) { return new string[0]; } List<string> list = new List<string>(); list.Add(skillName); if (skillName.StartsWith("$")) { string text = skillName.Substring(1); list.Add(text); if (text.StartsWith("skilldesc_")) { list.Add(text.Substring(10)); } if (text.EndsWith("Skill")) { list.Add(text.Substring(0, text.Length - 5)); } } string item = CleanSkillNameForYaml(skillName); if (!list.Contains(item)) { list.Add(item); } return list.ToArray(); } private static string[] GenerateCommonModSkillNames(int skillId) { List<string> list = new List<string>(); list.Add(skillId.ToString()); switch (skillId) { case 1337: list.AddRange(new string[3] { "Cartography", "CartographySkill", "Cartographer" }); break; case 410134081: list.AddRange(new string[3] { "Agility", "AgilitySkill", "Agile" }); break; } return list.ToArray(); } private static string? TryGetLocalizedName(string descriptionKey) { if (string.IsNullOrEmpty(descriptionKey) || !descriptionKey.StartsWith("$")) { return null; } try { Type type = AccessTools.TypeByName("Localization"); if (type != null) { object obj = null; try { obj = Traverse.Create(type).Property("instance", (object[])null).GetValue<object>(); if (obj == null) { obj = Traverse.Create(type).Field("instance").GetValue<object>(); } } catch { } MethodInfo methodInfo = AccessTools.Method(type, "Localize", new Type[1] { typeof(string) }, (Type[])null); if (obj != null && methodInfo != null) { string text = methodInfo.Invoke(obj, new object[1] { descriptionKey }) as string; if (!string.IsNullOrEmpty(text) && text != descriptionKey) { return text; } } } } catch { } return null; } internal static string GetActualModSkillName(SkillType skillType) { //IL_0202: 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_008b: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 try { Player safeLocalPlayer = SLE_SkillHelpers.GetSafeLocalPlayer(); Skills val = ((safeLocalPlayer != null) ? ((Character)safeLocalPlayer).GetSkills() : null); if ((Object)(object)val != (Object)null) { Dictionary<SkillType, Skill> value = Traverse.Create((object)val).Field("m_skillData").GetValue<Dictionary<SkillType, Skill>>(); if (value != null && value.TryGetValue(skillType, out var value2)) { SkillDef value3 = Traverse.Create((object)value2).Field("m_info").GetValue<SkillDef>(); if (value3 != null) { SkillType value4 = Traverse.Create((object)value3).Field("m_skill").GetValue<SkillType>(); if ((int)value4 > 0) { string text = ((object)(SkillType)(ref value4)).ToString(); if (!int.TryParse(text, out var _)) { return text; } } try { string value5 = Traverse.Create((object)value3).Field("m_name").GetValue<string>(); if (!string.IsNullOrEmpty(value5) && !value5.StartsWith("$")) { return value5; } } catch { } try { string value6 = Traverse.Create((object)value3).Field("m_name").GetValue<string>(); if (!string.IsNullOrEmpty(value6) && value6.StartsWith("$")) { string text2 = TryGetLocalizedName(value6); if (text2 != null) { return text2; } } } catch { } string value7 = Traverse.Create((object)value3).Field("m_description").GetValue<string>(); if (!string.IsNullOrEmpty(value7) && value7.StartsWith("$")) { string text3 = TryGetLocalizedName(value7); if (text3 != null && !text3.Contains(" ")) { return text3; } } } } } return ((object)(SkillType)(ref skillType)).ToString(); } catch (Exception ex) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogWarning((object)$"[SLE] Failed to get actual skill name for {skillType}: {ex.Message}"); } return ((object)(SkillType)(ref skillType)).ToString(); } } private static string CleanSkillNameForYaml(string skillName) { if (string.IsNullOrEmpty(skillName)) { return skillName; } string text = Regex.Replace(skillName, "[^\\w]", ""); if (text.Length > 0 && char.IsDigit(text[0])) { text = "_" + text; } return string.IsNullOrEmpty(text) ? skillName : text; } internal static int GetCap(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string skillKeyForLookup = GetSkillKeyForLookup(st); int result; bool flag = int.TryParse(((object)(SkillType)(ref st)).ToString(), out result) && result == 1337; if (flag) { Dictionary<string, YamlExporter.SkillYamlEntry> entriesByName = _entriesByName; YamlExporter.SkillYamlEntry value; YamlExporter.SkillYamlEntry skillYamlEntry = ((entriesByName != null && entriesByName.TryGetValue(skillKeyForLookup, out value)) ? value : null); ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[SLE] Skill 1337 - Key: '{skillKeyForLookup}', Cap: {skillYamlEntry?.Cap ?? 250}"); } } } if (!_isServerConfig) { ConfigEntry<bool> enableYamlOverride = EnableYamlOverride; if (enableYamlOverride != null && enableYamlOverride.Value && _entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value2) && value2 != null && value2.Cap > 0) { if (flag) { ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[SLE] Skill 1337 using client cap: {value2.Cap}"); } } } return value2.Cap; } } if (_isServerConfig && _entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value3) && value3 != null && value3.Cap > 0) { if (flag) { ConfigEntry<bool> enableGrowthCurveDebug3 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug3 != null && enableGrowthCurveDebug3.Value) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogInfo((object)$"[SLE] Skill 1337 using server cap: {value3.Cap}"); } } } return value3.Cap; } if (flag) { ConfigEntry<bool> enableGrowthCurveDebug4 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug4 != null && enableGrowthCurveDebug4.Value) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogInfo((object)$"[SLE] Skill 1337 using fallback cap: {250}"); } } } return 250; } [Obsolete("Use GetCap with proper skill type instead")] internal static int GetCartographySkillCap() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) try { SkillType st = (SkillType)1337; return GetCap(st); } catch (Exception ex) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[SLE] Error getting CartographySkill cap via generic method: " + ex.Message)); } return 250; } } internal static int GetBonusCap(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string skillKeyForLookup = GetSkillKeyForLookup(st); if (!_isServerConfig) { ConfigEntry<bool> enableYamlOverride = EnableYamlOverride; if (enableYamlOverride != null && enableYamlOverride.Value && _entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value) && value != null && value.BonusCap > 0) { return value.BonusCap; } } if (_isServerConfig && _entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value2) && value2 != null && value2.BonusCap > 0) { return value2.BonusCap; } return 100; } internal static bool IsRelative(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string skillKeyForLookup = GetSkillKeyForLookup(st); if (_entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value) && value != null) { return value.Relative; } return true; } internal static float GetGrowthExponent(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string skillKeyForLookup = GetSkillKeyForLookup(st); if (_entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value) && value != null) { return value.GrowthExponent; } return 1.5f; } internal static float GetGrowthMultiplier(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string skillKeyForLookup = GetSkillKeyForLookup(st); if (_entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value) && value != null) { return value.GrowthMultiplier; } return 0.5f; } internal static float GetGrowthConstant(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string skillKeyForLookup = GetSkillKeyForLookup(st); if (_entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value) && value != null) { return value.GrowthConstant; } return 0.5f; } internal static bool UseCustomGrowthCurve(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string skillKeyForLookup = GetSkillKeyForLookup(st); if (_entriesByName != null && _entriesByName.TryGetValue(skillKeyForLookup, out YamlExporter.SkillYamlEntry value) && value != null) { return value.UseCustomGrowthCurve; } return false; } internal static float GetFactorDenominator(SkillType st) { return 100f; } internal static float GetUiDenominator() { try { int num = Math.Max(1, 250); if (num <= 0 || float.IsNaN(num) || float.IsInfinity(num)) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogWarning((object)"[SLE] GetUiDenominator: Invalid result, using fallback 100f"); } return 100f; } return num; } catch (Exception ex) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogError((object)("[SLE] GetUiDenominator failed: " + ex.Message + ", using fallback 100f")); } return 100f; } } internal static float GetUiDenominatorForSkill(SkillType st) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Math.Max(1, GetCap(st)); } internal static float GetUiDenominatorForSkillSafe(object? skillMaybe) { //IL_0046: 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) //IL_004d: 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) try { Skill val = (Skill)((skillMaybe is Skill) ? skillMaybe : null); if (val != null) { SkillDef value = Traverse.Create((object)val).Field("m_info").GetValue<SkillDef>(); if (value != null) { SkillType value2 = Traverse.Create((object)value).Field("m_skill").GetValue<SkillType>(); float uiDenominatorForSkill = GetUiDenominatorForSkill(value2); ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogDebug((object)$"[SLE] UI denominator for {value2}: {uiDenominatorForSkill} (level={val.m_level})"); } } return uiDenominatorForSkill; } } } catch (Exception ex) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)("[SLE] GetUiDenominatorForSkillSafe failed: " + ex.Message)); } } float uiDenominator = GetUiDenominator(); ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogDebug((object)$"[SLE] UI denominator fallback: {uiDenominator}"); } } return uiDenominator; } internal static void SendConfigToClients() { ZNet instance = ZNet.instance; if (instance == null || !instance.IsServer() || !(ServerConfigLocked?.Value ?? false)) { return; } try { string yamlPath = YamlExporter.GetYamlPath(); string text = (File.Exists(yamlPath) ? File.ReadAllText(yamlPath) : string.Empty); int num = 2; ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "SLE_YamlSync", new object[2] { text, num }); _lastYamlHash = ComputeHash(text ?? string.Empty); ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[SLE] Server YAML sent to clients (length={text?.Length ?? 0}, proto={num})"); } } } catch (Exception arg) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogError((object)$"[SLE] Failed to send YAML to clients: {arg}"); } } } internal static void SendConfigToClientsIfChanged() { ZNet instance = ZNet.instance; if (instance == null || !instance.IsServer() || !(ServerConfigLocked?.Value ?? false)) { return; } try { string yamlPath = YamlExporter.GetYamlPath(); string text = (File.Exists(yamlPath) ? File.ReadAllText(yamlPath) : string.Empty); string text2 = ComputeHash(text ?? string.Empty); if (string.Equals(_lastYamlHash, text2, StringComparison.Ordinal)) { ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogDebug((object)"[SLE] YAML unchanged; broadcast skipped."); } } return; } int num = 2; ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "SLE_YamlSync", new object[2] { text, num }); _lastYamlHash = text2; ConfigEntry<bool> enableGrowthCurveDebug2 = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug2 != null && enableGrowthCurveDebug2.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"[SLE] Server YAML broadcasted to everybody (length={text?.Length ?? 0}, proto={num})"); } } } catch (Exception arg) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogError((object)$"[SLE] Failed to broadcast YAML: {arg}"); } } } private static void OnYamlReceived(long sender, string yamlContent, int protocolVersion) { //IL_00af: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown ZNet instance = ZNet.instance; if (instance != null && instance.IsServer()) { return; } try { _isServerConfig = true; if (!VersionInfo.IsCompatible(protocolVersion)) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogWarning((object)$"[SLE] Protocol version mismatch: remote={protocolVersion}, local={2}"); } return; } if (!string.IsNullOrEmpty(yamlContent)) { IDeserializer val = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).IgnoreUnmatchedProperties().Build(); try { Dictionary<string, YamlExporter.SkillYamlEntry> dictionary = val.Deserialize<Dictionary<string, YamlExporter.SkillYamlEntry>>(yamlContent); _entriesByName = dictionary ?? new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); } catch (YamlException val2) { YamlException val3 = val2; ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)("[SLE] YAML parsing failed, trying legacy format: " + ((Exception)(object)val3).Message)); } Dictionary<string, int> dictionary2 = val.Deserialize<Dictionary<string, int>>(yamlContent) ?? new Dictionary<string, int>(); Dictionary<string, YamlExporter.SkillYamlEntry> dictionary3 = new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); foreach (KeyValuePair<string, int> item in dictionary2) { dictionary3[item.Key] = new YamlExporter.SkillYamlEntry { Cap = item.Value, BonusCap = 100, Relative = true, UseCustomGrowthCurve = false, GrowthExponent = 1.5f, GrowthMultiplier = 0.5f, GrowthConstant = 0.5f }; } _entriesByName = dictionary3; } catch (Exception arg) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogError((object)$"[SLE] Failed to parse server YAML: {arg}"); } _entriesByName = new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); } } else { _entriesByName = new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); } _skillKeyCache.Clear(); ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogInfo((object)$"[SLE] Received server YAML (entries={_entriesByName.Count})"); } } } catch (Exception arg2) { ManualLogSource logger5 = SkillLimitExtenderPlugin.Logger; if (logger5 != null) { logger5.LogError((object)$"[SLE] Failed to apply server YAML: {arg2}"); } _entriesByName = new Dictionary<string, YamlExporter.SkillYamlEntry>(StringComparer.Ordinal); } } internal static void OnPlayerConnected() { SendConfigToClients(); } internal static int GetCapByName(string name) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(name)) { return 250; } if (Enum.TryParse<SkillType>(name, ignoreCase: true, out SkillType result) && (int)result != 0 && (int)result != 999) { return GetCap(result); } return 250; } internal static int GetSkillLimit(SkillType st) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return GetCap(st); } private static string ComputeHash(string text) { try { using SHA256 sHA = SHA256.Create(); byte[] bytes = Encoding.UTF8.GetBytes(text ?? string.Empty); byte[] array = sHA.ComputeHash(bytes); return BitConverter.ToString(array).Replace("-", ""); } catch { return string.Empty; } } internal static string GetSkillDisplayName(SkillType st) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) try { if ((int)st > 999) { Player safeLocalPlayer = SLE_SkillHelpers.GetSafeLocalPlayer(); Skills val = ((safeLocalPlayer != null) ? ((Character)safeLocalPlayer).GetSkills() : null); if ((Object)(object)val != (Object)null) { Dictionary<SkillType, Skill> value = Traverse.Create((object)val).Field("m_skillData").GetValue<Dictionary<SkillType, Skill>>(); if (value != null && value.TryGetValue(st, out var value2)) { SkillDef value3 = Traverse.Create((object)value2).Field("m_info").GetValue<SkillDef>(); if (value3 != null) { string value4 = Traverse.Create((object)value3).Field("m_description").GetValue<string>(); string text = TryGetLocalizedName(value4); if (text != null) { return text; } if (!string.IsNullOrEmpty(value4) && !value4.StartsWith("$")) { return value4; } } } } return ((object)(SkillType)(ref st)).ToString(); } return ((object)(SkillType)(ref st)).ToString(); } catch { return ((object)(SkillType)(ref st)).ToString(); } } } [BepInPlugin("SkillLimitExtender", "SkillLimitExtender", "1.2.0")] public class SkillLimitExtenderPlugin : BaseUnityPlugin { internal const string PluginGuid = "SkillLimitExtender"; internal const string PluginName = "SkillLimitExtender"; internal const string PluginVersion = "1.2.0"; private readonly Harmony _harmony = new Harmony("SkillLimitExtender"); internal static ManualLogSource Logger { get; private set; } internal static ConfigEntry<bool> EnableGrowthCurveDebug { get; private set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; EnableGrowthCurveDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Enable Growth Curve Debug", false, "Enable debug logging for skill growth curve calculations"); try { Logger.LogInfo((object)("[SLE] " + VersionInfo.VersionString)); SkillConfigManager.Initialize(((BaseUnityPlugin)this).Config); YamlExporter.EnsureYamlExists(); _harmony.PatchAll(typeof(SkillLimitExtenderPlugin).Assembly); SLE_Hook_ModSkills.Initialize(_harmony); SLE_TerminalCommands.Register(); Logger.LogInfo((object)"[SLE] Plugin loaded successfully (v1.2.0)"); } catch (Exception arg) { Logger.LogError((object)$"[SLE] Awake failed: {arg}"); } } private void Start() { if (!((Object)(object)ZNet.instance != (Object)null)) { return; } try { ZRoutedRpc.instance.Register<string, int>("SLE_YamlSync", (Action<long, string, int>)SkillConfigManager.OnYamlReceivedStatic); ManualLogSource logger = Logger; if (logger != null) { logger.LogInfo((object)"[SLE] RPC registered successfully"); } } catch (Exception arg) { ManualLogSource logger2 = Logger; if (logger2 != null) { logger2.LogError((object)$"[SLE] RPC registration failed: {arg}"); } } } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception arg) { Logger.LogError((object)$"[SLE] UnpatchSelf failed: {arg}"); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class SLE_Hook_PlayerSpawned { [HarmonyPostfix] private static void Postfix(Player __instance) { ZNet instance = ZNet.instance; if (instance != null && instance.IsServer() && (Object)(object)__instance != (Object)null) { SkillConfigManager.SendConfigToClientsIfChanged(); } } } internal static class SLE_Hook_ModSkills { private static Harmony? _harmony; private static readonly List<string> _patchedAssemblies = new List<string>(); private static readonly HashSet<string> _checkedAssemblies = new HashSet<string>(); private static readonly HashSet<string> _modSkillAssemblies = new HashSet<string>(); private static readonly Dictionary<string, bool> _assemblySkillCheckCache = new Dictionary<string, bool>(); private static readonly Dictionary<string, List<MethodInfo>> _assemblyMethodCache = new Dictionary<string, List<MethodInfo>>(); private static readonly Dictionary<string, SkillType> _typeNameCache = new Dictionary<string, SkillType>(); private static readonly Dictionary<SkillType, int> _skillCapCache = new Dictionary<SkillType, int>(); private static DateTime _lastCacheUpdate = DateTime.MinValue; private static readonly TimeSpan CacheExpiry = TimeSpan.FromSeconds(30.0); internal static void Initialize(Harmony harmony) { _harmony = harmony; ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)"[SLE] ModSkills: Starting universal MOD skill patch system..."); } try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); int num = 0; Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { string name = assembly.GetName().Name; if (_checkedAssemblies.Contains(name)) { if (_modSkillAssemblies.Contains(name)) { int num2 = PatchModSkillAssembly(assembly); if (num2 > 0) { num += num2; _patchedAssemblies.Add(name); } } continue; } _checkedAssemblies.Add(name); if (IsModSkillAssembly(assembly)) { _modSkillAssemblies.Add(name); int num3 = PatchModSkillAssembly(assembly); if (num3 > 0) { num += num3; _patchedAssemblies.Add(name); } } } catch (Exception ex) { ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogDebug((object)("[SLE] ModSkills: Skipping assembly " + assembly.GetName().Name + ": " + ex.Message)); } } } } ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogInfo((object)$"[SLE] ModSkills loaded: {num} methods patched across {_patchedAssemblies.Count} MOD assemblies"); } if (_patchedAssemblies.Count > 0) { ManualLogSource logger4 = SkillLimitExtenderPlugin.Logger; if (logger4 != null) { logger4.LogInfo((object)("[SLE] Additional skills found: " + string.Join(", ", _patchedAssemblies))); } } } catch (Exception arg) { ManualLogSource logger5 = SkillLimitExtenderPlugin.Logger; if (logger5 != null) { logger5.LogError((object)$"[SLE] ModSkills: Initialization failed: {arg}"); } } } private static bool IsModSkillAssembly(Assembly assembly) { try { string name = assembly.GetName().Name; if (_assemblySkillCheckCache.TryGetValue(name, out var value)) { return value; } if (name.StartsWith("Assembly-CSharp") || name.StartsWith("UnityEngine") || name.StartsWith("System") || name.StartsWith("mscorlib") || name.StartsWith("BepInEx") || name.StartsWith("0Harmony") || name.StartsWith("Jotunn") || name.StartsWith("Microsoft") || name.StartsWith("netstandard") || name == "SkillLimitExtender") { _assemblySkillCheckCache[name] = false; return false; } Type[] types = assembly.GetTypes(); bool flag = false; Type[] array = types; foreach (Type type in array) { if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length == 0) { continue; } MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { string name2 = methodInfo.Name; if (name2.Contains("Skill") || name2.Contains("Raise") || name2.Contains("Cheat")) { flag = true; break; } } if (flag) { break; } } _assemblySkillCheckCache[name] = flag; return flag; } catch { return false; } } private static int PatchModSkillAssembly(Assembly assembly) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown int num = 0; try { string name = assembly.GetName().Name; if (!_assemblyMethodCache.TryGetValue(name, out List<MethodInfo> value)) { value = new List<MethodInfo>(); Type[] types = assembly.GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { if (IsSkillLimitMethod(methodInfo)) { value.Add(methodInfo); } } } _assemblyMethodCache[name] = value; } foreach (MethodInfo item in value) { try { HarmonyMethod val = new HarmonyMethod(typeof(SLE_Hook_ModSkills), "UniversalSkillLimitTranspiler", (Type[])null); Harmony? harmony = _harmony; if (harmony != null) { harmony.Patch((MethodBase)item, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); } ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)("[SLE] ModSkills: Patched " + name + "." + item.DeclaringType?.Name + "." + item.Name)); } } num++; } catch (Exception ex) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogWarning((object)("[SLE] ModSkills: Failed to patch " + item.DeclaringType?.Name + "." + item.Name + ": " + ex.Message)); } } } } catch (Exception arg) { ManualLogSource logger3 = SkillLimitExtenderPlugin.Logger; if (logger3 != null) { logger3.LogError((object)$"[SLE] ModSkills: Error processing assembly {assembly.GetName().Name}: {arg}"); } } return num; } private static bool IsSkillLimitMethod(MethodInfo method) { try { if (!method.Name.Contains("Skill") && !method.Name.Contains("Raise") && !method.Name.Contains("Cheat") && !method.Name.Contains("Level")) { return false; } List<CodeInstruction> currentInstructions = PatchProcessor.GetCurrentInstructions((MethodBase)method, int.MaxValue, (ILGenerator)null); if (currentInstructions.Any((CodeInstruction instr) => instr.opcode == OpCodes.Ldc_R4 && instr.operand is float num && Math.Abs(num - 100f) < 0.001f)) { return currentInstructions.Any(delegate(CodeInstruction instr) { int result; if (instr.opcode == OpCodes.Call) { object operand = instr.operand; result = ((operand != null && (operand.ToString()?.Contains("Clamp")).GetValueOrDefault()) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }); } return false; } catch { return false; } } [HarmonyTranspiler] private static IEnumerable<CodeInstruction> UniversalSkillLimitTranspiler(IEnumerable<CodeInstruction> instructions, MethodBase original) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); try { for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (!(val.opcode == OpCodes.Ldc_R4) || !(val.operand is float num) || !(Math.Abs(num - 100f) < 0.001f)) { continue; } bool flag = false; for (int j = Math.Max(0, i - 5); j < Math.Min(list.Count, i + 5); j++) { if (list[j].opcode == OpCodes.Call) { object operand = list[j].operand; if (operand != null && (operand.ToString()?.Contains("Clamp")).GetValueOrDefault()) { flag = true; break; } } } if (!flag) { continue; } List<CodeInstruction> list2 = new List<CodeInstruction>(); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SLE_Hook_ModSkills), "GetUniversalSkillCap", (Type[])null, (Type[])null))); list2.Add(new CodeInstruction(OpCodes.Conv_R4, (object)null)); List<CodeInstruction> list3 = list2; list[i] = list3[0]; list.InsertRange(i + 1, list3.GetRange(1, list3.Count - 1)); ConfigEntry<bool> enableGrowthCurveDebug = SkillLimitExtenderPlugin.EnableGrowthCurveDebug; if (enableGrowthCurveDebug != null && enableGrowthCurveDebug.Value) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)("[SLE] ModSkills: Replaced 100f in " + original.DeclaringType?.Name + "." + original.Name)); } } break; } } catch (Exception arg) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogError((object)$"[SLE] ModSkills: Transpiler error in {original.DeclaringType?.Name}.{original.Name}: {arg}"); } } return list; } private static int GetUniversalSkillCap() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Invalid comparison between Unknown and I4 //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0230: 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_00a0: 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_00c8: 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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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_01db: Unknown result type (might be due to invalid IL or missing references) try { if (DateTime.Now - _lastCacheUpdate > CacheExpiry) { _skillCapCache.Clear(); _lastCacheUpdate = DateTime.Now; } SkillType val = (SkillType)0; MethodBase currentMethod = MethodBase.GetCurrentMethod(); MethodBase methodBase = new StackFrame(1)?.GetMethod(); if (methodBase?.DeclaringType != null) { string text = methodBase.DeclaringType.FullName ?? methodBase.DeclaringType.Name; if (_typeNameCache.TryGetValue(text, out var value)) { val = value; } else if (text.Contains("CartographySkill")) { val = (SkillType)1337; _typeNameCache[text] = val; } else if (text.Contains("AgilitySkill") || text.Contains("Agility")) { val = (SkillType)410134081; _typeNameCache[text] = val; } else { StackTrace stackTrace = new StackTrace(); int num = Math.Min(5, stackTrace.FrameCount); for (int i = 2; i < num; i++) { Type type = (stackTrace.GetFrame(i)?.GetMethod())?.DeclaringType; if (type != null) { string text2 = type.FullName ?? type.Name; if (text2.Contains("CartographySkill")) { val = (SkillType)1337; _typeNameCache[text2] = val; break; } if (text2.Contains("AgilitySkill") || text2.Contains("Agility")) { val = (SkillType)410134081; _typeNameCache[text2] = val; break; } } } } } if ((int)val > 0) { if (_skillCapCache.TryGetValue(val, out var value2)) { return value2; } int cap = SkillConfigManager.GetCap(val); _skillCapCache[val] = cap; return cap; } return 250; } catch { return 250; } } } internal static class VersionInfo { public const string Version = "1.2.0"; public const string Prerelease = ""; public const string Build = "20251001"; public const bool IsDevelopmentVersion = false; public const string FullVersion = "1.2.0"; public const string FullVersionWithBuild = "1.2.0.0"; public const int ProtocolVersion = 2; public const int ConfigSchemaVersion = 2; public static string DisplayVersion => string.IsNullOrEmpty("") ? "1.2.0" : "1.2.0-"; public static string VersionString => string.Format("v{0} (build {1}, proto={2}, cfg={3})", DisplayVersion, "20251001", 2, 2); public static bool IsCompatible(int remoteProtocolVersion) { return remoteProtocolVersion == 2; } } internal sealed class ConfigurationManagerAttributes { public bool? ShowRangeAsPercent { get; set; } public bool? IsAdvanced { get; set; } public int? Order { get; set; } public string? Category { get; set; } public bool? Browsable { get; set; } public object? DefaultValue { get; set; } public string? ReadOnly { get; set; } public bool? HideDefaultButton { get; set; } public bool? HideSettingName { get; set; } public bool? IsAdminOnly { get; set; } } internal static class YamlExporter { internal sealed class SkillYamlEntry { public int Cap { get; set; } = 250; public int BonusCap { get; set; } = 100; public bool Relative { get; set; } = true; public bool UseCustomGrowthCurve { get; set; } = false; public float GrowthExponent { get; set; } = 1.5f; public float GrowthMultiplier { get; set; } = 0.5f; public float GrowthConstant { get; set; } = 0.5f; } private static readonly string ConfigDir = Path.Combine(Paths.ConfigPath, "SkillLimitExtender"); private static string YamlPath = Path.Combine(ConfigDir, "SLE_Skill_List.yaml"); internal static string GetYamlPath() { return YamlPath; } internal static void EnsureYamlExists() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0057: Invalid comparison between Unknown and I4 Directory.CreateDirectory(ConfigDir); if (File.Exists(YamlPath)) { return; } Dictionary<string, SkillYamlEntry> dictionary = new Dictionary<string, SkillYamlEntry>(); try { foreach (SkillType value in Enum.GetValues(typeof(SkillType))) { SkillType val = value; if ((int)val != 0 && (int)val != 999) { dictionary[((object)(SkillType)(ref val)).ToString()] = new SkillYamlEntry { Cap = 250, BonusCap = 100, Relative = true, UseCustomGrowthCurve = false, GrowthExponent = 1.5f, GrowthMultiplier = 0.5f, GrowthConstant = 0.5f }; } } } catch { } SaveYamlEntries(dictionary); ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogInfo((object)$"[SLE] Created YAML: {YamlPath} (seed={dictionary.Count} vanilla skills, fields: cap/bonusCap/relative)"); } } internal static Dictionary<string, SkillYamlEntry> LoadYamlEntries() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown try { if (!File.Exists(YamlPath)) { return new Dictionary<string, SkillYamlEntry>(); } string text = File.ReadAllText(YamlPath, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); IDeserializer val = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).IgnoreUnmatchedProperties().Build(); try { Dictionary<string, SkillYamlEntry> dictionary = val.Deserialize<Dictionary<string, SkillYamlEntry>>(text); if (dictionary != null) { return dictionary; } } catch { } Dictionary<string, int> dictionary2 = val.Deserialize<Dictionary<string, int>>(text) ?? new Dictionary<string, int>(); Dictionary<string, SkillYamlEntry> dictionary3 = new Dictionary<string, SkillYamlEntry>(StringComparer.Ordinal); foreach (KeyValuePair<string, int> item in dictionary2) { dictionary3[item.Key] = new SkillYamlEntry { Cap = item.Value, BonusCap = 100, Relative = true, UseCustomGrowthCurve = false, GrowthExponent = 1.5f, GrowthMultiplier = 0.5f, GrowthConstant = 0.5f }; } return dictionary3; } catch (Exception arg) { ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogError((object)$"[SLE] LoadYaml error: {arg}"); } return new Dictionary<string, SkillYamlEntry>(); } } internal static void SaveYamlEntries(Dictionary<string, SkillYamlEntry> map) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown try { Directory.CreateDirectory(ConfigDir); ISerializer val = ((BuilderSkeleton<SerializerBuilder>)new SerializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); string contents = val.Serialize((object)map.OrderBy<KeyValuePair<string, SkillYamlEntry>, string>((KeyValuePair<string, SkillYamlEntry> kv) => kv.Key, StringComparer.Ordinal).ToDictionary((KeyValuePair<string, SkillYamlEntry> kv) => kv.Key, (KeyValuePair<string, SkillYamlEntry> kv) => kv.Value)); if (!TryWriteAllText(YamlPath, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), out Exception error)) { string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SkillLimitExtender"); string text2 = Path.Combine(text, "SLE_Skill_List.yaml"); Directory.CreateDirectory(text); File.WriteAllText(text2, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); YamlPath = text2; ManualLogSource logger = SkillLimitExtenderPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[SLE] SaveYaml primary failed: " + error?.GetType().Name + " " + error?.Message + "; switched to fallback: " + text2)); } } } catch (Exception arg) { ManualLogSource logger2 = SkillLimitExtenderPlugin.Logger; if (logger2 != null) { logger2.LogError((object)$"[SLE] SaveYaml error: