using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SkillsSorter")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SkillsSorter")] [assembly: AssemblyTitle("SkillsSorter")] [assembly: AssemblyVersion("1.0.0.0")] namespace Kladbm.SkillsSorter; public enum SortMode { Disabled, ByName, ByLevel } public enum LiveUpdateMode { Disabled, Enabled, EnabledExceptRunSkill } [BepInPlugin("Kladbm.SkillsSorter", "SkillsSorter", "1.0.1")] public class SkillsSorterPlugin : BaseUnityPlugin { private const string ModName = "SkillsSorter"; private const string ModVersion = "1.0.1"; private const string Author = "Kladbm"; private const string ModGUID = "Kladbm.SkillsSorter"; private readonly Harmony _harmony = new Harmony("Kladbm.SkillsSorter"); internal static ManualLogSource Log; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"SkillsSorter initializing..."); SkillsConfig.Load((BaseUnityPlugin)(object)this); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)"All patches applied successfully."); } internal static void LogDebug(string message) { if (SkillsConfig.EnableLogging.Value) { Log.LogInfo((object)message); } } } internal static class SkillsConfig { internal static ConfigEntry SortMode; internal static ConfigEntry DescendingLevel; internal static ConfigEntry LiveUpdate; internal static ConfigEntry EnableLogging; internal static void Load(BaseUnityPlugin plugin) { ConfigFile config = plugin.Config; SortMode = config.Bind("Sorting", "SortMode", Kladbm.SkillsSorter.SortMode.ByLevel, "Disabled — original order.\nByName — alphabetical.\nByLevel — highest level first, ties broken by name."); DescendingLevel = config.Bind("Sorting", "DescendingLevel", true, "true — highest level at the top, false — lowest level at the top."); LiveUpdate = config.Bind("LiveUpdate", "LiveUpdateMode", LiveUpdateMode.EnabledExceptRunSkill, "Disabled — updates only on menu open.\nEnabled — updates on skill level up or gear change.\nEnabledExceptRunSkill — same, but ignores the Run skill to avoid constant redraws."); EnableLogging = config.Bind("_Debug", "Enable Logging", false, "Generate additional debug information in the logs for this mod.\nThis will cause a performance hit and should only be used for debugging."); config.SettingChanged += delegate { SkillsMenuHelper.TryRefreshMenu(Player.m_localPlayer); }; } } internal static class SkillComparer { internal static string GetTranslatedName(this Skill skill) { return Localization.instance.Localize("$skill_" + ((object)(SkillType)(ref skill.m_info.m_skill)).ToString().ToLower()); } internal static int CompareLevel(this Skill a, Skill b) { int num = Mathf.FloorToInt(a.m_level).CompareTo(Mathf.FloorToInt(b.m_level)); if (num != 0) { return num; } return a.m_accumulator.CompareTo(b.m_accumulator); } internal static int CompareByConfig(this Skill a, Skill b) { switch (SkillsConfig.SortMode.Value) { case SortMode.ByLevel: { int num = a.CompareLevel(b); if (num != 0) { if (!SkillsConfig.DescendingLevel.Value) { return num; } return -num; } return a.GetTranslatedName().CompareTo(b.GetTranslatedName()); } case SortMode.ByName: return a.GetTranslatedName().CompareTo(b.GetTranslatedName()); default: return 0; } } } internal static class SkillsMenuHelper { private static bool _safeToRefresh; internal static void SetSafe() { _safeToRefresh = true; } internal static void SetUnsafe() { _safeToRefresh = false; } internal static void TryRefreshMenu(Player player) { if (_safeToRefresh && SkillsConfig.LiveUpdate.Value != 0 && !((Object)(object)InventoryGui.instance == (Object)null)) { SkillsDialog skillsDialog = InventoryGui.instance.m_skillsDialog; if (!((Object)(object)skillsDialog == (Object)null) && ((Component)skillsDialog).gameObject.activeSelf && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { skillsDialog.Setup(player); } } } } [HarmonyPatch(typeof(Skills), "GetSkillList")] public static class Patch_Skills_GetSkillList { [HarmonyPostfix] [HarmonyPriority(100)] private static void Postfix(ref List __result) { if (SkillsConfig.SortMode.Value != 0) { __result.Sort((Skill a, Skill b) => a.CompareByConfig(b)); } } } [HarmonyPatch(typeof(SkillsDialog), "Setup")] public static class Patch_SkillsDialog_Setup { [HarmonyPostfix] private static void Postfix() { SkillsMenuHelper.SetSafe(); } } [HarmonyPatch(typeof(Game), "Logout")] public static class Patch_Game_Logout { [HarmonyPrefix] private static void Prefix() { SkillsMenuHelper.SetUnsafe(); } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] public static class Patch_Skills_RaiseSkill { [HarmonyPostfix] [HarmonyPriority(100)] private static void Postfix(SkillType skillType) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 if (!((Object)(object)Player.m_localPlayer == (Object)null) && (SkillsConfig.LiveUpdate.Value != LiveUpdateMode.EnabledExceptRunSkill || (int)skillType != 102)) { SkillsSorterPlugin.LogDebug($"[SkillsSorter] RaiseSkill triggered: {skillType}"); SkillsMenuHelper.TryRefreshMenu(Player.m_localPlayer); } } } [HarmonyPatch(typeof(Humanoid), "EquipItem")] public static class Patch_Humanoid_EquipItem { [HarmonyPostfix] [HarmonyPriority(300)] private static void Postfix(Humanoid __instance, bool __result) { if (__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { SkillsSorterPlugin.LogDebug("[SkillsSorter] EquipItem triggered."); SkillsMenuHelper.TryRefreshMenu(Player.m_localPlayer); } } } [HarmonyPatch(typeof(Humanoid), "UnequipItem")] public static class Patch_Humanoid_UnequipItem { [HarmonyPostfix] private static void Postfix(Humanoid __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { SkillsSorterPlugin.LogDebug("[SkillsSorter] UnequipItem triggered."); SkillsMenuHelper.TryRefreshMenu(Player.m_localPlayer); } } }