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 SkillLimitExtender v1.2.0
plugins/skill_Limit_Extender.dll
Decompiled 6 months 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: