using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text.RegularExpressions; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DetailedLevels.Features; using DetailedLevels.Tools; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("DetailedLevels")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DetailedLevels")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("f302fe77-1481-495a-84b9-5ba829a4cf2b")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace DetailedLevels { public enum SkillsSortOrder { None, AlphabeticalAscending, AlphabeticalDescending, LevelAscending, LevelDescending } public enum SkillValuesFormat { Decimals, Percentage } public enum KillStatsGroupingFormat { ByInitialLetter, AllTogether } public enum SkillBuffValuePosition { Above, Below } internal class ConfigurationFile { private static ConfigEntry _serverConfigLocked = null; public static ConfigEntry debug; public static ConfigEntry hotKey; public static ConfigEntry numberOfDecimals; public static ConfigEntry skillBuffValuePosition; public static ConfigEntry skillUpMessageAfterMultipleLevel; public static ConfigEntry skillUpBigMessageAfterMultipleLevel; public static ConfigEntry colorSkillBackground; public static ConfigEntry saveSkillBuffs; public static ConfigEntry saveSkillsOrder; public static ConfigEntry saveSkillsOrderValue; public static ConfigEntry skillValuesFormat; public static ConfigEntry killStatsGroupingFormat; public static ConfigEntry deathPenaltyText; public static ConfigEntry reloadAfterDyingText; public static ConfigEntry skillValuePositionText; public static ConfigEntry numberOfDecimalsText; public static ConfigEntry skillValuesFormatText; public static ConfigEntry skillUpMessageText; public static ConfigEntry skillUpBigMessageText; public static ConfigEntry skillUpValueText; public static ConfigEntry skillsOrderText; public static ConfigEntry statsText; public static ConfigEntry statsDeathTypesText; public static ConfigEntry statsProgressionText; public static ConfigEntry statsTravellingText; public static ConfigEntry statsOthersText; private static ConfigFile configFile; private static readonly string ConfigFileName = "Turbero.DetailedLevels.cfg"; private static readonly string ConfigFileFullPath; private static readonly ConfigSync ConfigSync; internal static void LoadConfig(BaseUnityPlugin plugin) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) configFile = plugin.Config; _serverConfigLocked = config("1 - General", "Lock Configuration", value: true, "If on, the configuration is locked and can be changed by server admins only."); ConfigSync.AddLockingConfigEntry(_serverConfigLocked); debug = config("1 - General", "DebugMode", value: false, "Enabling/Disabling the debugging in the console (default = false)", synchronizedSetting: false); hotKey = config("1 - General", "HotKey", (KeyCode)285, "Hot Key to show the skills tab without opening the inventory first (default = F4)", synchronizedSetting: false); numberOfDecimals = config("2 - Levels Data", "NumberOfDecimals", 2, "Number of decimals to show in your levels information (default = 2, min = 0, max = 15)", synchronizedSetting: false); skillBuffValuePosition = config("2 - Levels Data", "Skill Buff Value Position", SkillBuffValuePosition.Below, "Choose the position of the skill value on the buff icon (default = BelowBuffIcon)", synchronizedSetting: false); skillUpMessageAfterMultipleLevel = config("2 - Levels Data", "SkillUpMessageAfterMultipleLevel", 5, "Shows skill up message after the new level is multiple of the indicated level (0 = disabled, default = 5)", synchronizedSetting: false); skillUpBigMessageAfterMultipleLevel = config("2 - Levels Data", "SkillUpBigMessageAfterMultipleLevel", 10, "Shows skill up big message after the new level is multiple of the indicated level (0 = disabled, default = 20)", synchronizedSetting: false); colorSkillBackground = config("3 - Config", "ColorSkillBackground", Color.cyan, "Choose the color background for selected skills in the skills dialog: red, green, blue, white, black, yellow, cyan, magenta, gray or grey (default = cyan)", synchronizedSetting: false); saveSkillBuffs = config("3 - Config", "SaveSkillBuffs", value: false, "Enable/disable the option to reload tracked skills after dying (default = false)", synchronizedSetting: false); saveSkillsOrder = config("3 - Config", "Save Skills Order", value: false, "Enable/disable the option to save the order selected in the skills dialog (default = false)", synchronizedSetting: false); saveSkillsOrderValue = config("3 - Config", "Skills Order Value", SkillsSortOrder.None, "Skills Order to use when skills dialog is opened and the save option is enabled (default = None)", synchronizedSetting: false); skillValuesFormat = config("3 - Config", "Skill Values Format", SkillValuesFormat.Decimals, "Show the skill number values with decimals or percentage (default = Decimals)", synchronizedSetting: false); killStatsGroupingFormat = config("3 - Config", "Kill Stats Grouping Format", KillStatsGroupingFormat.ByInitialLetter, "Show kill stats grouped by initial letter or all together (default = InitialLetter)", synchronizedSetting: false); deathPenaltyText = config("4 - Language", "DeathPenaltyText", "Death Penalty", "Translation for text"); reloadAfterDyingText = config("4 - Language", "ReloadAfterDyingText", "Reload after dying", "Translation for text"); skillValuePositionText = config("4 - Language", "SkillValuePositionText", "Skill value position", "Translation for text"); numberOfDecimalsText = config("4 - Language", "NumberOfDecimalsText", "Number of decimals", "Translation for text"); skillValuesFormatText = config("4 - Language", "Skill Values Format Text", "Skill Values Format", "Translation for text"); skillUpMessageText = config("4 - Language", "SkillUpMessageText", "Skill up message", "Translation for text"); skillUpBigMessageText = config("4 - Language", "SkillUpBigMessageText", "Skill up big message", "Translation for text"); skillUpValueText = config("4 - Language", "SkillUpValueText", "Each {0} levels", "Translation for text"); skillsOrderText = config("4 - Language", "SkillsOrderText", "Save Skills Order", "Translation for text"); statsText = config("4 - Language", "StatsText", "Stats", "Translation for text"); statsDeathTypesText = config("4 - Language", "Stats Death Types", "Death Types", "Translation for text (restart game after change)"); statsProgressionText = config("4 - Language", "StatsProgressionText", "Progression", "Translation for text (restart game after change)"); statsTravellingText = config("4 - Language", "StatsTravellingText", "Travelling", "Translation for text (restart game after change)"); statsOthersText = config("4 - Language", "StatsOthersText", "Others", "Translation for text (restart game after change)"); SetupWatcher(); } private static void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReadConfigValues; fileSystemWatcher.Created += ReadConfigValues; fileSystemWatcher.Renamed += ReadConfigValues; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private static void ReadConfigValues(object sender, FileSystemEventArgs e) { if (!File.Exists(ConfigFileFullPath)) { return; } try { Logger.Log("Attempting to reload configuration..."); configFile.Reload(); SettingsChanged(null, null); } catch (Exception arg) { Logger.LogError($"There was an issue loading {ConfigFileName}, {arg}"); } } private static void SettingsChanged(object sender, EventArgs e) { PlayerSkillupOptionsPatch.updateOptionsTexts(); PlayerSkillupOptionsPatch.reloadTexts(); SkillTypeCraftStationDescriptionsPatch.updated = false; if (!((Object)(object)Player.m_localPlayer != (Object)null)) { return; } PlayerColorBuffs.refreshAllBlueColors(Player.m_localPlayer); foreach (KeyValuePair skillStatusEffect in PlayerUtils.skillStatusEffects) { if (((Character)Player.m_localPlayer).GetSEMan().GetStatusEffect(skillStatusEffect.Value) is SE_SkillBuff sE_SkillBuff) { sE_SkillBuff.Refresh(); } } } private static ConfigEntry config(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty()), synchronizedSetting); } private static ConfigEntry config(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry val2 = configFile.Bind(group, name, value, val); SyncedConfigEntry syncedConfigEntry = ConfigSync.AddConfigEntry(val2); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val2; } static ConfigurationFile() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConfigSync = new ConfigSync("Turbero.DetailedLevels") { DisplayName = "Detailed Levels", CurrentVersion = "2.0.1", MinimumRequiredVersion = "2.0.1" }; } } public class ControllerUtils { public static void BindGamePad(Transform buttonGo, KeyCode gamepadKeyCode, InventoryGui inventoryGui = null) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) UIGamePad val = null; if (((Component)buttonGo).TryGetComponent(ref val)) { string text = KeyCodeToString(gamepadKeyCode); if (ZInput.instance != null) { ((TMP_Text)val.m_hint.GetComponentInChildren(true)).text = ZInput.instance.GetBoundKeyString(text, true); } else { ZInput.Initialize(); TextMeshProUGUI componentInChildren = val.m_hint.GetComponentInChildren(true); ZInput instance = ZInput.instance; ((TMP_Text)componentInChildren).text = ((instance != null) ? instance.GetBoundKeyString(text, true) : null); } val.m_zinputKey = text; val.m_keyCode = gamepadKeyCode; UIGroupHandler value = default(UIGroupHandler); if ((Object)(object)inventoryGui != (Object)null && ((Component)inventoryGui.m_crafting).TryGetComponent(ref value)) { SetPrivateValue(val, "m_group", value); } } } private static void SetPrivateValue(object obj, string name, object value, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic) { obj.GetType().GetField(name, bindingAttr)?.SetValue(obj, value); } public static string KeyCodeToString(KeyCode keyCode) { //IL_0001: 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) //IL_0009: Expected I4, but got Unknown int num = keyCode - 330; if (1 == 0) { } string result = num switch { 1 => "JoyButtonB", 2 => "JoyButtonX", 3 => "JoyButtonY", 4 => "JoyLBumper", 5 => "JoyRBumper", 6 => "JoyBack", 7 => "JoyStart", 8 => "JoyLStick", 9 => "JoyRStick", 10 => "JoyDPadLeft", 11 => "JoyDPadRight", 12 => "JoyDPadUp", 13 => "JoyDPadDown", 14 => "JoyLTrigger", 15 => "JoyRTrigger", 16 => "JoyButtonA", 17 => "JoyButtonB", 18 => "JoyButtonX", 19 => "JoyButtonY", _ => "JoyButtonA", }; if (1 == 0) { } return result; } } public class ReflectionUtils { public static object GetPrivateValue(object obj, string name, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic) { return obj.GetType().GetField(name, bindingAttr)?.GetValue(obj); } public static void SetPrivateValue(object obj, string name, object value, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic) { obj.GetType().GetField(name, bindingAttr)?.SetValue(obj, value); } public static object GetPrivateMethod(object obj, string name, object[] parameters = null, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic) { return obj.GetType().GetMethod(name, bindingAttr)?.Invoke(obj, parameters); } public static void RunPrivateMethod(object obj, string name, object[] parameters = null, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic) { obj.GetType().GetMethod(name, bindingAttr)?.Invoke(obj, parameters); } } [BepInPlugin("Turbero.DetailedLevels", "Detailed Levels", "2.0.1")] public class DetailedLevels : BaseUnityPlugin { public const string GUID = "Turbero.DetailedLevels"; public const string NAME = "Detailed Levels"; public const string VERSION = "2.0.1"; private readonly Harmony harmony = new Harmony("Turbero.DetailedLevels"); private void Awake() { ConfigurationFile.LoadConfig((BaseUnityPlugin)(object)this); harmony.PatchAll(); } private void onDestroy() { harmony.UnpatchSelf(); } private void Update() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)InventoryGui.instance)) { return; } if (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)9) || ((Character)Player.m_localPlayer).IsDead()) { hideCustomPanelAndSkillsDialog(); } if (Input.GetKeyDown(ConfigurationFile.hotKey.Value) && Time.timeScale > 0f) { if (((Component)InventoryGui.instance.m_skillsDialog).gameObject.activeSelf) { hideCustomPanelAndSkillsDialog(); InventoryGui.instance.Hide(); } else { InventoryGui.instance.Show((Container)null, 1); WaitForSecondsAsync(0.15f); } } } private static void hideCustomPanelAndSkillsDialog() { if (!((Object)(object)InventoryGui.instance.m_skillsDialog == (Object)null)) { ((Component)InventoryGui.instance.m_skillsDialog).gameObject.SetActive(false); if (!((Object)(object)((Component)InventoryGui.instance.m_skillsDialog).transform.Find("SkillsFrame/CustomSkillOptionsPanel") == (Object)null)) { ((Component)((Component)InventoryGui.instance.m_skillsDialog).transform.Find("SkillsFrame/CustomSkillOptionsPanel")).gameObject.SetActive(false); ((Component)((Component)InventoryGui.instance.m_skillsDialog).transform.Find("TabStatsButton")).gameObject.SetActive(false); ((Component)((Component)InventoryGui.instance.m_skillsDialog).transform.Find("TabKillStatsButton")).gameObject.SetActive(false); } } } private static async Task WaitForSecondsAsync(float seconds) { await Task.Delay((int)(Math.Max(0f, seconds) * 1000f)); InventoryGui.instance.m_skillsDialog.Setup(Player.m_localPlayer); ((Component)InventoryGui.instance.m_skillsDialog).gameObject.SetActive(true); } } [HarmonyPatch] public class NoWarnings { [HarmonyPatch(typeof(Debug), "LogWarning", new Type[] { typeof(object), typeof(Object) })] [HarmonyPrefix] private static bool LogWarning(object message, Object context) { if (message.ToString().Contains("The LiberationSans SDF Font Asset was not found") || message.ToString().Contains("The character used for Ellipsis is not available in font asset") || message.ToString().Contains("lacks a proper counterpart in the GamepadButton enum")) { return false; } return true; } } [HarmonyPatch(typeof(Localization), "SetLanguage")] public class Localization_SetLanguage_Patch { private static void Postfix(string language) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) Logger.Log("Language changed to: " + language); foreach (SkillType key in PlayerUtils.skillStatusEffects.Keys) { int valueSafe = GeneralExtensions.GetValueSafe(PlayerUtils.skillStatusEffects, key); Player_RaiseSkill_Patch.updateSkillTypeBuff(Player.m_localPlayer, key, valueSafe, forceUpdate: true); } } } public static class Logger { public static ManualLogSource logger = Logger.CreateLogSource("Detailed Levels"); internal static void Log(object s) { if (ConfigurationFile.debug.Value) { logger.LogInfo((object)s?.ToString()); } } internal static void LogInfo(object s) { logger.LogInfo((object)s?.ToString()); } internal static void LogWarning(object s) { string text = "Detailed Levels 2.0.1: " + ((s != null) ? s.ToString() : "null"); Debug.LogWarning((object)text); } internal static void LogError(object s) { string text = "Detailed Levels 2.0.1: " + ((s != null) ? s.ToString() : "null"); Debug.LogError((object)text); } } } namespace DetailedLevels.Tools { public class CustomSkillOptionsPanel { private GameObject panel; private TextMeshProUGUI titleText; private TMP_Text buttonText; public CustomSkillOptionsPanel(Transform copyForCloseButton) { Init(copyForCloseButton); } private void Init(Transform copyForCloseButton) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_007a: 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_013a: 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_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Expected O, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Expected O, but got Unknown Transform transform = ((Component)((Component)InventoryGui.instance.m_skillsDialog).transform.Find("SkillsFrame")).transform; panel = new GameObject("CustomSkillOptionsPanel", new Type[1] { typeof(RectTransform) }); panel.SetActive(false); panel.transform.SetParent(transform, false); RectTransform component = panel.GetComponent(); component.sizeDelta = new Vector2(512f, 512f); component.anchoredPosition = new Vector2(0f, 0f); Image component2 = ((Component)transform.Find("bkg")).GetComponent(); Image val = Object.Instantiate(component2, panel.transform); ((Object)val).name = "bkg_customskills"; GameObject gameObject = ((Component)transform.Find("topic")).gameObject; GameObject val2 = Object.Instantiate(gameObject, panel.transform); ((Object)val2).name = "Title"; titleText = val2.GetComponent(); ((TMP_Text)titleText).text = Localization.instance.Localize("$button_ps_start"); RectTransform component3 = val2.GetComponent(); component3.anchoredPosition = new Vector2(0f, -30f); Transform val3 = ((Component)InventoryGui.instance.m_skillsDialog).transform.Find("SkillsFrame/Closebutton"); GameObject val4 = Object.Instantiate(((Component)val3).gameObject, copyForCloseButton); ((Object)val4).name = "DLOptionsCloseButton"; val4.transform.SetParent(panel.transform, false); ControllerUtils.BindGamePad(val4.transform, (KeyCode)332, InventoryGui.instance); RectTransform component4 = val4.GetComponent(); component4.anchoredPosition = new Vector2(0f, 40f); buttonText = val4.GetComponentInChildren(); Button component5 = val4.GetComponent