Decompiled source of ConfigForge v1.0.1
ConfigForge.dll
Decompiled 10 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using AskaConfigForge.Core; using AskaShared.Game; using AskaShared.UI; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Fusion; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using Microsoft.CodeAnalysis; using SSSGame; using SSSGame.UI; using SandSailorStudio.Game; using SandSailorStudio.Localization; using SandSailorStudio.UI; using SandSailorStudio.WorldGen; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.UI; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("ConfigForge")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1")] [assembly: AssemblyInformationalVersion("1.0.1+48a86bd2e0d0ea8a6bc56ef1163f7c4fe4e9bf61")] [assembly: AssemblyProduct("Config Forge")] [assembly: AssemblyTitle("ConfigForge")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte flag) { NullableFlags = new byte[1] { flag }; } public NullableAttribute(byte[] flags) { NullableFlags = flags; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte flag) { Flag = flag; } } } namespace AskaConfigForge { [HarmonyPatch(typeof(TMP_InputField), "OnCancel")] internal static class CancelGuard { private static bool Prefix(TMP_InputField __instance, BaseEventData eventData) { if (!TextEntry.IsEditing(__instance)) { return true; } if (eventData != null) { ((AbstractEventData)eventData).Use(); } return false; } } [HarmonyPatch] internal static class ConfigForgeLeaveHold { [HarmonyPrefix] [HarmonyPatch(typeof(TabGroup), "TabSelect")] private static bool TabSelecting(TabGroup __instance, TabButton button) { return ConfigForgeTab.AllowTabSelect(__instance, button); } [HarmonyPrefix] [HarmonyPatch(typeof(MenuManager), "CloseMenu")] private static bool MenuClosing(Menu menu) { return ConfigForgeTab.AllowMenuClose(menu); } } [HarmonyPatch] internal static class ConfigForgeTab { internal const string ButtonName = "ConfigForge_ModSettingsTab"; private const string PageName = "ConfigForge_ModSettingsPage"; private static bool _failed; private static bool _templateLogged; private static bool _toggleFailed; private static bool _contentFailed; private static TabPage _page; private static TabGroupControls _strip; private static TabButton _tab; private static ModSettingsContent _content; private static GameObject _frameSelected; private static GameObject[] _hiddenWhileShown; private static bool[] _turnedOff; private const float LeaveApprovalSeconds = 3f; private static float _leaveApprovedUntil = float.NegativeInfinity; internal static bool IsShowing { get { if (_content != null) { return _content.IsActive; } return false; } } private static bool LeaveApproved => Time.unscaledTime < _leaveApprovedUntil; [HarmonyPostfix] [HarmonyPatch(typeof(SettingsMenu), "Start")] private static void SettingsMenuStarted(SettingsMenu __instance) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown _content = null; _leaveApprovedUntil = float.NegativeInfinity; _strip = null; _tab = null; if (_failed || _toggleFailed) { return; } GameObject page = null; GameObject button = null; try { Add(__instance, ref page, ref button); } catch (Exception ex) { _failed = true; _page = null; _strip = null; _tab = null; _frameSelected = null; _hiddenWhileShown = null; if ((Object)(object)button != (Object)null) { Object.DestroyImmediate((Object)(object)button); } if ((Object)(object)page != (Object)null) { Object.DestroyImmediate((Object)(object)page); } ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(91, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab could not be built; the settings page shows only the game's own tabs: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex); } log.LogError(val); } } internal static void Tick() { _content?.Tick(); } internal static bool AllowTabSelect(TabGroup group, TabButton target) { if (LeaveApproved || (Object)(object)_strip == (Object)null || (Object)(object)_tab == (Object)null || ((Il2CppObjectBase)group).Pointer != ((Il2CppObjectBase)_strip).Pointer) { return true; } if ((Object)(object)target != (Object)null && ((Il2CppObjectBase)target).Pointer == ((Il2CppObjectBase)_tab).Pointer) { return true; } if (!HoldsStagedChanges()) { return true; } Hold("tab switch", delegate { ((TabGroup)_strip).TabSelect(target); }); return false; } internal static bool AllowMenuClose(Menu menu) { if (LeaveApproved || (Object)(object)menu == (Object)null || (Object)(object)((Il2CppObjectBase)menu).TryCast<SettingsMenu>() == (Object)null || !HoldsStagedChanges()) { return true; } Hold("menu close", delegate { MenuManager.Instance.CloseMenu(menu); }); return false; } private static bool HoldsStagedChanges() { if (_content != null && (Object)(object)_page != (Object)null && ((Component)_page).gameObject.activeInHierarchy) { return _content.LeaveWouldAsk; } return false; } private static void Hold(string what, Action leave) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (KitConfirmDialog.IsOpen) { return; } ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(65, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("A "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(what); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" away from the Config Forge tab is held for its staged changes."); } log.LogInfo(val); try { _content.LeavePageThen(approvedLeave); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(60, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("The discard dialog could not open, so the leave goes ahead: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex); } log2.LogError(val2); approvedLeave(); } void approvedLeave() { _leaveApprovedUntil = Time.unscaledTime + 3f; leave(); } } internal static bool Escape() { if (!TakeBack()) { return false; } EscapeOwner.OwnEscapePress(); return true; } internal static bool TakeBack() { if (_content == null || !_content.IsActive) { return false; } bool flag = TextEntry.IsBlockingInput || KeyCapture.IsBlockingInput; bool flag2 = flag && !TextEntry.IsEditingAny && !KeyCapture.IsCapturing; switch (EscapeLayers.Decide(settingsOpen: true, _content.PickerOpen && !flag2, flag, _content.OnModPage)) { case EscapeStep.CancelPicker: case EscapeStep.ReturnToList: _content.Back(); break; case EscapeStep.EndEdit: if (KeyCapture.IsCapturing) { KeyCapture.Cancel(); } else { TextEntry.Cancel(); } break; default: return false; } return true; } internal static bool PadMove(Selectable control, bool right) { if (IsShowing) { return _content.PadMove(control, right); } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(TabPage), "Show")] private static void PageShowing(TabPage __instance, bool value) { if (!value || (Object)(object)_page == (Object)null || ((Il2CppObjectBase)__instance).Pointer != ((Il2CppObjectBase)_page).Pointer || _content != null || _contentFailed) { return; } try { ModSettingsContent modSettingsContent = new ModSettingsContent(); RectTransform component = ((Component)_page).GetComponent<RectTransform>(); modSettingsContent.Build(aboveSortingOrder: ((Component)component).GetComponentInParent<Canvas>(true).rootCanvas.sortingOrder, area: component, settingsMenu: ModSettingsContent.FindSettingsMenu()); _content = modSettingsContent; } catch (Exception e) { DropContent("built", e); } } private static void DropContent(string what, Exception e) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown _contentFailed = true; _content = null; RectTransform component = ((Component)_page).GetComponent<RectTransform>(); for (int num = ((Transform)component).childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)((Transform)component).GetChild(num)).gameObject); } ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(72, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab's content could not be "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(what); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; the tab page stays empty: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(e); } log.LogError(val); } [HarmonyPostfix] [HarmonyPatch(typeof(TabPage), "Show")] private static void PageShown(TabPage __instance, bool value) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown if ((Object)(object)_page == (Object)null || ((Il2CppObjectBase)__instance).Pointer != ((Il2CppObjectBase)_page).Pointer) { return; } if (!value) { _leaveApprovedUntil = float.NegativeInfinity; } if (!_toggleFailed) { try { if ((Object)(object)_frameSelected != (Object)null) { _frameSelected.SetActive(value); } if (value) { HideForeignParts(); } else { RestoreForeignParts(); } } catch (Exception ex) { _toggleFailed = true; RestoreEachBestEffort(); ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(121, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab's selected frame, or the game's Apply, Discard, Reset and seed panel, could not be shown or hidden: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex); } log.LogError(val); } } ShowContent(value); } private static void ShowContent(bool value) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown if (_content == null) { return; } bool flag = default(bool); if (!value) { try { _content.Hide(); return; } catch (Exception ex) { ManualLogSource log = Plugin.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(60, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab's content could not be hidden cleanly: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogWarning(val); return; } } try { ManualLogSource log2 = Plugin.Log; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("The Config Forge tab shown: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_content.Enter()); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" plates."); } log2.LogInfo(val2); } catch (Exception e) { DropContent("shown", e); } } private static void Add(SettingsMenu menu, ref GameObject page, ref GameObject button) { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Expected O, but got Unknown TabGroupControls strip = menu.MainTabGroup ?? throw new InvalidOperationException("SettingsMenu.MainTabGroup, the tab strip, is not set."); TabButton[] source = ((IEnumerable<TabButton>)((Component)strip).GetComponentsInChildren<TabButton>(true)).Where((TabButton b) => (Object)(object)b.group != (Object)null && ((Il2CppObjectBase)b.group).Pointer == ((Il2CppObjectBase)strip).Pointer).ToArray(); TabButton val = ((IEnumerable<TabButton>)source).FirstOrDefault((Func<TabButton, bool>)((TabButton b) => ((Object)b).name == "ConfigForge_ModSettingsTab")); if ((Object)(object)val != (Object)null) { _strip = strip; _tab = val; return; } TabButton[] source2 = (from b in source where (Object)(object)b.page != (Object)null && (Object)(object)((Il2CppObjectBase)b.page).TryCast<SettingsTabPage>() != (Object)null orderby b.order select b).ToArray(); TabButton val2 = ((IEnumerable<TabButton>)source2).FirstOrDefault((Func<TabButton, bool>)((TabButton b) => (Object)(object)((Il2CppObjectBase)b.page).TryCast<GameplaySettingsTabPage>() != (Object)null)) ?? source2.FirstOrDefault() ?? throw new InvalidOperationException("The tab strip '" + ((Object)strip).name + "' holds no tab bound to a SettingsTabPage to clone."); if (!_templateLogged) { _templateLogged = true; ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(49, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("The Config Forge tab is cloned from '"); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)val2).name); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' (page '"); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)val2.page).name); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("')."); } log.LogInfo(val3); } TabPage page2 = val2.page; SettingsTabPage val4 = ((Il2CppObjectBase)page2).TryCast<SettingsTabPage>(); GameObject[] obj = new GameObject[4] { SharedButton(val4.applyButton, "applyButton"), SharedButton(val4.discardButton, "discardButton"), SharedButton(val4.resetButton, "resetButton"), default(GameObject) }; RectTransform seedPanel = menu.seedPanel; obj[3] = ((seedPanel != null) ? ((Component)seedPanel).gameObject : null); GameObject[] hiddenWhileShown = ((IEnumerable<GameObject>)(object)obj).Where((GameObject o) => (Object)(object)o != (Object)null).ToArray(); Sprite modsTabGlyph = MedallionArt.ModsTabGlyph; string overrideDetails = ModStrings.Get("tab.mod_settings"); page = new GameObject("ConfigForge_ModSettingsPage"); page.SetActive(false); RectTransform obj2 = page.AddComponent<RectTransform>(); Transform transform = ((Component)page2).transform; ((Transform)obj2).SetParent(transform.parent, false); ((Transform)obj2).SetSiblingIndex(transform.GetSiblingIndex() + 1); UiParts.Stretch(obj2); TabPage val5 = page.AddComponent<TabPage>(); val5.AutoPosition = false; button = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Component)val2).transform.parent, false); ((Object)button).name = "ConfigForge_ModSettingsTab"; button.transform.SetSiblingIndex(source.Max((TabButton b) => ((Component)b).transform.GetSiblingIndex()) + 1); TabButton val6 = ((IEnumerable<TabButton>)button.GetComponents<TabButton>()).FirstOrDefault((Func<TabButton, bool>)((TabButton b) => (Object)(object)b.group != (Object)null && ((Il2CppObjectBase)b.group).Pointer == ((Il2CppObjectBase)strip).Pointer)) ?? throw new InvalidOperationException("The cloned tab has no TabButton on the strip."); val6.page = val5; int num = source.Max((TabButton b) => b.order); if (((TabGroup)strip).buttons != null) { Enumerator<TabButton> enumerator = ((TabGroup)strip).buttons.GetEnumerator(); while (enumerator.MoveNext()) { TabButton current = enumerator.Current; if ((Object)(object)current != (Object)null) { num = Math.Max(num, current.order); } } } val6.order = num + 1; val6.selected = false; TabButtonTooltip obj3 = button.GetComponent<TabButtonTooltip>() ?? throw new InvalidOperationException("The cloned tab has no TabButtonTooltip."); ((TabButton)obj3).selected = false; obj3.OverrideDetails = overrideDetails; string[] array = new string[3] { "Icon", "Icon/Icon_Selected", "Icon_Shadow" }; foreach (string text in array) { Image obj4 = ((Component)UiParts.Child(button.transform, text)).GetComponent<Image>() ?? throw new InvalidOperationException("The cloned tab's '" + text + "' has no Image."); obj4.sprite = modsTabGlyph; obj4.preserveAspect = true; } GameObject gameObject = ((Component)UiParts.Child(button.transform, "Frame_Selected")).gameObject; gameObject.SetActive(false); _page = val5; _strip = strip; _tab = val6; _frameSelected = gameObject; _hiddenWhileShown = hiddenWhileShown; _turnedOff = null; Plugin.Log.LogInfo((object)"The Config Forge tab added to the settings page."); } private static GameObject SharedButton(Button button, string field) { return ((button != null) ? ((Component)button).gameObject : null) ?? throw new InvalidOperationException("SettingsTabPage." + field + " is not set."); } private static void HideForeignParts() { if (_turnedOff == null && _hiddenWhileShown != null) { _turnedOff = new bool[_hiddenWhileShown.Length]; for (int i = 0; i < _hiddenWhileShown.Length; i++) { TurnOffIfActive(i); } } } internal static void HoldForeignPartsHidden() { if (_turnedOff != null && _hiddenWhileShown != null) { for (int i = 0; i < _hiddenWhileShown.Length; i++) { TurnOffIfActive(i); } } } private static bool TurnOffIfActive(int i) { GameObject val = _hiddenWhileShown[i]; if ((Object)(object)val == (Object)null || !val.activeSelf) { return false; } _turnedOff[i] = true; val.SetActive(false); return true; } private static void RestoreForeignParts() { if (_turnedOff != null && _hiddenWhileShown != null) { for (int i = 0; i < _hiddenWhileShown.Length; i++) { RestorePart(i); } _turnedOff = null; } } private static void RestorePart(int i) { GameObject val = _hiddenWhileShown[i]; if (_turnedOff[i] && (Object)(object)val != (Object)null && !val.activeSelf) { val.SetActive(true); } } private static void RestoreEachBestEffort() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if (_turnedOff == null || _hiddenWhileShown == null) { return; } bool flag = default(bool); for (int i = 0; i < _hiddenWhileShown.Length; i++) { try { RestorePart(i); } catch (Exception ex) { ManualLogSource log = Plugin.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(61, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("A part hidden on the Config Forge tab could not be restored: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogWarning(val); } } _turnedOff = null; } } public class ConfigForgeTool : MonoBehaviour { private void Update() { EscapeOwner.TrackEscape(); KeyCapture.TrackClick(); PadInput.Tick(); if (!KitConfirmDialog.IsBlockingInput) { if (Input.GetKeyDown((KeyCode)27) && ConfigForgeTab.Escape()) { ConfigForgeTab.Tick(); } else if (KeyCapture.IsBlockingInput) { KeyCapture.Tick(); } else if (!TextEntry.IsBlockingInput) { ConfigForgeTab.Tick(); } } } private void LateUpdate() { ConfigForgeTab.HoldForeignPartsHidden(); } } internal static class ConfigWriter { private sealed class Store : IConfigStore { private static readonly PropertyInfo OrphanedEntriesProperty = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic); private readonly ConfigFile _config; public Store(ConfigFile config) { _config = config; } public string GetSerializedValue(string section, string key) { return Entry(section, key).GetSerializedValue(); } public void SetSerializedValue(string section, string key, string value) { Entry(section, key).SetSerializedValue(value); } public void Save() { _config.Save(); } public void Reload() { Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)(OrphanedEntriesProperty?.GetValue(_config) ?? throw new InvalidOperationException("BepInEx's ConfigFile has no OrphanedEntries to keep if the reload fails, so it was not reloaded")); Dictionary<ConfigDefinition, string> dictionary2 = new Dictionary<ConfigDefinition, string>(dictionary); try { _config.Reload(); } catch { dictionary.Clear(); foreach (KeyValuePair<ConfigDefinition, string> item in dictionary2) { dictionary[item.Key] = item.Value; } throw; } } private ConfigEntryBase Entry(string section, string key) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return _config[new ConfigDefinition(section, key)]; } } private static readonly HashSet<string> RefusalsLogged = new HashSet<string>(); public static IReadOnlyList<StagedChange> Write(ConfigFileChanges file) { ConfigFile val = ModDiscovery.FileOf(file.ConfigFileId); bool saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; try { return ConfigWrite.Write(file.PluginGuid, new Store(val), file.Changes, delegate(string failure, Exception e) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(2, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(failure); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(e); } log.LogError(val2); }, delegate(string failure, Exception e) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(2, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(failure); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(e); } log.LogWarning(val2); }); } finally { val.SaveOnConfigSet = saveOnConfigSet; } } public static ReloadResult ReloadAll(ModCatalog catalog) { List<ConfigFile> list = ModDiscovery.ConfigFiles().ToList(); List<bool> list2 = list.Select((ConfigFile file) => file.SaveOnConfigSet).ToList(); foreach (ConfigFile item in list) { item.SaveOnConfigSet = false; } try { return ConfigReload.Run(catalog, StoreOnDisk, delegate(string failure, Exception e) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(2, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(failure); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(e); } log.LogWarning(val); }); } finally { for (int num = 0; num < list.Count; num++) { list[num].SaveOnConfigSet = list2[num]; } } } private static IConfigStore StoreOnDisk(string configFileId) { ConfigFile val = ModDiscovery.FileOf(configFileId); if (!File.Exists(val.ConfigFilePath)) { return null; } return new Store(val); } public static bool Takes(SettingRow row, string text) { return ModDiscovery.ConverterKeeps(EntryOf(row).SettingType, text); } public static string Canonical(SettingRow row, string text) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown try { ConfigEntryBase val = EntryOf(row); object value; string text2 = ModDiscovery.RoundTrip(val.SettingType, text, out value); if (ModDiscovery.RoundTrip(val.SettingType, text2, out object value2) != text2) { return null; } return ModDiscovery.Allows(val, value2) ? text2 : null; } catch (Exception ex) { if (RefusalsLogged.Add($"{row.ConfigFileId}/{row.Section}/{row.Key}")) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(17, 5, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(row.PluginGuid); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" '"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(row.Section); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("."); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(row.Key); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' refused \""); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\": "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } log.LogWarning(val2); } return null; } } private static ConfigEntryBase EntryOf(SettingRow row) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown return ModDiscovery.FileOf(row.ConfigFileId)[new ConfigDefinition(row.Section, row.Key)]; } } internal sealed class CustomTabs { private static readonly Dictionary<(string Dll, string Tab), bool> Held = new Dictionary<(string, string), bool>(); private static readonly HashSet<string> Logged = new HashSet<string>(); private readonly Dictionary<string, TabButton> _buttons; public IReadOnlyDictionary<string, string> ByPlugin { get; } private CustomTabs(IReadOnlyDictionary<string, string> byPlugin, Dictionary<string, TabButton> buttons) { ByPlugin = byPlugin; _buttons = buttons; } public TabButton Button(string tabName) { return _buttons[tabName]; } public static CustomTabs Read(TabGroup strip, IReadOnlyCollection<string> ownTabs) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown Dictionary<string, TabButton> dictionary = new Dictionary<string, TabButton>(); try { List<string> list = new List<string>(); if (strip.buttons != null) { Enumerator<TabButton> enumerator = strip.buttons.GetEnumerator(); while (enumerator.MoveNext()) { TabButton current = enumerator.Current; if (dictionary.TryAdd(((Object)current).name, current)) { list.Add(((Object)current).name); } } } List<TabPatcher> list2 = Patchers(); Dictionary<string, byte[]> bytes = new Dictionary<string, byte[]>(); IReadOnlyDictionary<string, string> byPlugin = CustomTabRule.Match(list2, list, ownTabs, (string dll, string tab) => Holds(dll, tab, bytes)); foreach (TabPatcher item in list2) { LogOnce(item, byPlugin); } return new CustomTabs(byPlugin, dictionary); } catch (Exception ex) { if (Logged.Add("failed")) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(82, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The custom settings tabs could not be read, so every mod keeps its regular plate: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex); } log.LogWarning(val); } return new CustomTabs(new Dictionary<string, string>(), dictionary); } } private static List<TabPatcher> Patchers() { MethodBase methodBase = Harmony.GetAllPatchedMethods().FirstOrDefault((MethodBase method) => method.DeclaringType == typeof(SettingsMenu) && method.Name == "Start"); Patches val = ((methodBase == null) ? null : Harmony.GetPatchInfo(methodBase)); if (val == null) { return new List<TabPatcher>(); } Assembly own = typeof(CustomTabs).Assembly; ILookup<Assembly, PluginInfo> pluginsOf = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.Values.Where((PluginInfo info) => info.Instance != null && !string.IsNullOrEmpty(info.Location)).ToLookup((PluginInfo info) => info.Instance.GetType().Assembly); return (from assembly in (from patch in val.Prefixes.Concat(val.Postfixes).Concat(val.Transpilers).Concat(val.Finalizers) .Concat(val.ILManipulators) select patch.PatchMethod?.DeclaringType?.Assembly into assembly where assembly != null && assembly != own select assembly).Distinct().ToList().Where(pluginsOf.Contains) select new TabPatcher(pluginsOf[assembly].First().Location, pluginsOf[assembly].Select((PluginInfo info) => info.Metadata.GUID).ToList())).ToList(); } private static bool Holds(string dll, string tab, Dictionary<string, byte[]> bytes) { if (Held.TryGetValue((dll, tab), out var value)) { return value; } if (!bytes.TryGetValue(dll, out byte[] value2)) { value2 = (bytes[dll] = File.ReadAllBytes(dll)); } return Held[(dll, tab)] = DllText.Holds(value2, tab); } private static void LogOnce(TabPatcher patcher, IReadOnlyDictionary<string, string> byPlugin) { string text = string.Join(", ", patcher.PluginGuids); string value; string text2 = (byPlugin.TryGetValue(patcher.PluginGuids[0], out value) ? $"Custom settings tab '{value}' belongs to {text}." : (text + " patches the settings page, and no tab on the strip is its own.")); if (Logged.Add(text2)) { Plugin.Log.LogInfo((object)text2); } } } [HarmonyPatch(typeof(TMP_InputField), "OnPointerDown")] internal static class DoubleClickSelect { private static void Prefix(TMP_InputField __instance, out bool __state) { __state = __instance.m_AllowInput && __instance.m_PointerDownClickStartTime + __instance.m_DoubleClickDelay > Time.unscaledTime; } private static void Postfix(TMP_InputField __instance, bool __state) { if (__state && TextEntry.IsEditing(__instance)) { int length = __instance.text.Length; __instance.selectionAnchorPosition = 0; __instance.selectionFocusPosition = length; __instance.selectionStringAnchorPosition = 0; __instance.selectionStringFocusPosition = length; __instance.ForceLabelUpdate(); } } } internal sealed class EntryFacts { private sealed class HeldScan { private const int MaxDepth = 3; private readonly Assembly _assembly; private readonly List<Type> _types; private readonly HashSet<Type> _holders; private readonly HashSet<object> _held = new HashSet<object>(ReferenceEqualityComparer.Instance); private readonly HashSet<object> _visited = new HashSet<object>(ReferenceEqualityComparer.Instance); private readonly HashSet<ConfigFile> _configFileSet = new HashSet<ConfigFile>(ReferenceEqualityComparer.Instance); internal List<ConfigFile> ConfigFiles { get; } = new List<ConfigFile>(); internal HeldScan(Assembly assembly) { _assembly = assembly; _types = (from type in assembly.GetTypes() where !type.ContainsGenericParameters select type).ToList(); _holders = new HashSet<Type>(); bool flag; do { flag = false; foreach (Type item in _types.Where((Type type) => !_holders.Contains(type) && type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Any((FieldInfo field) => CanHold(field.FieldType))).ToList()) { flag |= _holders.Add(item); } } while (flag); } internal HashSet<object> EntriesHeldBy(object instance) { Expand(instance, 0); foreach (Type type in _types) { foreach (FieldInfo item in from field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where field.IsStatic select field) { Follow(item, null, 0); } } return _held; } private void Expand(object owner, int depth) { Type type = owner.GetType(); while (type != null && type.Assembly == _assembly) { foreach (FieldInfo item in from field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where !field.IsStatic select field) { Follow(item, owner, depth); } type = type.BaseType; } } private void Follow(FieldInfo field, object owner, int depth) { if (CanHold(field.FieldType)) { Collect(field.GetValue(owner), depth); } } private void Collect(object value, int depth) { if (value == null || value is string) { return; } ConfigEntryBase val = (ConfigEntryBase)((value is ConfigEntryBase) ? value : null); if (val == null) { ConfigFile val2 = (ConfigFile)((value is ConfigFile) ? value : null); if (val2 == null) { IEnumerable enumerable; if (!(value is IDictionary dictionary)) { enumerable = value as IEnumerable; if (enumerable == null) { goto IL_0114; } } else { if (depth < 3) { { foreach (DictionaryEntry item in dictionary) { Collect(item.Key, depth + 1); Collect(item.Value, depth + 1); } return; } } enumerable = (IEnumerable)value; } if (depth < 3) { foreach (object item2 in enumerable) { Collect(item2, depth + 1); } return; } goto IL_0114; } AddConfigFile(val2); return; } _held.Add(val); AddConfigFile(val.ConfigFile); return; IL_0114: if (depth < 3 && IsHolder(value.GetType()) && _visited.Add(value)) { Expand(value, depth + 1); } } private void AddConfigFile(ConfigFile file) { if (file != null && _configFileSet.Add(file)) { ConfigFiles.Add(file); } } private bool CanHold(Type type) { if (typeof(Delegate).IsAssignableFrom(type) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>))) { return false; } if (typeof(ConfigEntryBase).IsAssignableFrom(type) || typeof(ConfigFile).IsAssignableFrom(type) || IsHolder(type)) { return true; } if (type.IsArray) { return CanHold(type.GetElementType()); } if (type.IsGenericType) { return type.GetGenericArguments().Any(CanHold); } return false; } private bool IsHolder(Type type) { while (type != null && type.Assembly == _assembly) { if (_holders.Contains(type)) { return true; } type = type.BaseType; } return false; } } private const string SettingChangedField = "SettingChanged"; private const BindingFlags AllFields = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags InstanceField = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const string HandlerFact = "the SettingChanged handlers of its entries"; private const string HeldFact = "the fields that hold its entries and config files"; private static readonly HashSet<string> Logged = new HashSet<string>(); private readonly string _pluginGuid; private readonly HashSet<object> _held; internal IReadOnlyList<ConfigFile> ConfigFiles { get; } private EntryFacts(string pluginGuid, HashSet<object> held, IReadOnlyList<ConfigFile> configFiles) { _pluginGuid = pluginGuid; _held = held; ConfigFiles = configFiles; } internal static EntryFacts Read(string pluginGuid, object instance) { HashSet<object> held = null; List<ConfigFile> configFiles = new List<ConfigFile>(); try { HeldScan heldScan = new HeldScan(instance.GetType().Assembly); held = heldScan.EntriesHeldBy(instance); configFiles = heldScan.ConfigFiles; } catch (Exception e) { LogOnce(pluginGuid, "the fields that hold its entries and config files", Describe(e)); } return new EntryFacts(pluginGuid, held, configFiles); } internal bool HasSettingChangedHandler(ConfigEntryBase entry) { try { FieldInfo field = ((object)entry).GetType().GetField("SettingChanged", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { LogOnce(_pluginGuid, "the SettingChanged handlers of its entries", ((object)entry).GetType().FullName + " has no SettingChanged field"); return false; } return field.GetValue(entry) is Delegate obj && obj.GetInvocationList().Length != 0; } catch (Exception e) { LogOnce(_pluginGuid, "the SettingChanged handlers of its entries", Describe(e)); return false; } } internal bool CopiedAndDropped(ConfigEntryBase entry) { if (_held != null) { return !_held.Contains(entry); } return false; } private static void LogOnce(string pluginGuid, string fact, string reason) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown if (Logged.Add(pluginGuid + "|" + fact)) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(68, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": could not read "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(fact); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" by reflection, so Config Forge ignores that fact: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason); } log.LogWarning(val); } } private static string Describe(Exception e) { if (e is ReflectionTypeLoadException ex) { return ex.LoaderExceptions.FirstOrDefault((Exception inner) => inner != null)?.Message ?? e.Message; } while (e.InnerException != null) { e = e.InnerException; } return e.Message; } } [HarmonyPatch] internal static class EscapeGuard { private static int _backFrame = -1; private static bool _backReachedGame; [HarmonyPrefix] [HarmonyPatch(typeof(MenuShortcutsManager), "Pause_started")] private static bool PauseStarted() { return !EscapeOwner.OwnsEscape; } [HarmonyPrefix] [HarmonyPatch(typeof(MenuShortcutsManager), "Back_performed")] private static bool ShortcutsBackPerformed() { return BackReachesGame(); } [HarmonyPrefix] [HarmonyPatch(typeof(MainMenu), "Back_performed")] private static bool MainMenuBackPerformed() { return BackReachesGame(); } private static bool BackReachesGame() { if (Time.frameCount == _backFrame) { return _backReachedGame; } _backFrame = Time.frameCount; _backReachedGame = KitConfirmDialog.IsOpen || (!EscapeOwner.OwnsEscape && !ConfigForgeTab.TakeBack()); return _backReachedGame; } } internal static class EscapeOwner { private const float EscapeGraceSeconds = 0.3f; private static bool _ownedEscapeHeld; private static float _ownedEscapeReleasedAt = float.NegativeInfinity; public static bool OwnsEscape { get { if (!_ownedEscapeHeld) { return InEscapeGrace; } return true; } } private static bool InEscapeGrace => Time.unscaledTime - _ownedEscapeReleasedAt < 0.3f; public static void TrackEscape() { if (Input.GetKeyDown((KeyCode)27)) { _ownedEscapeHeld = false; _ownedEscapeReleasedAt = float.NegativeInfinity; } if (_ownedEscapeHeld && !Input.GetKey((KeyCode)27)) { _ownedEscapeHeld = false; _ownedEscapeReleasedAt = Time.unscaledTime; } } public static void OwnEscapePress() { _ownedEscapeHeld = true; } } internal static class KeyCapture { private static readonly KeyCode[] Modifiers; private static readonly KeyCode[] Scanned; private static readonly Func<int, bool> IsMouseButtonHeld; private static readonly CancellingClick Click; private static bool _active; private static object _owner; private static bool _shortcut; private static int _startedFrame; private static int _endedFrame; private static KeyCode? _loneModifier; private static Action<string, IReadOnlyList<string>> _captured; private static Action _cancelled; public static bool IsBlockingInput { get { if (!_active) { return Time.frameCount == _endedFrame; } return true; } } public static bool IsCapturing => _active; public static void Start(object owner, bool shortcut, Action<string, IReadOnlyList<string>> captured, Action cancelled) { Cancel(); Click.Forget(); _active = true; _owner = owner; _shortcut = shortcut; _startedFrame = Time.frameCount; _loneModifier = null; _captured = captured; _cancelled = cancelled; } public static bool IsCancellingClick(object owner) { return Click.IsFrom(owner); } public static void TrackClick() { Click.Track(Time.frameCount, IsMouseButtonHeld); } public static void Cancel() { if (_active) { Action cancelled = _cancelled; End(); cancelled(); } } public static void Tick() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!_active || Time.frameCount == _startedFrame) { return; } if (Input.GetMouseButtonDown(1)) { Finish((KeyCode)0, Enumerable.Empty<KeyCode>()); return; } if (Input.GetMouseButtonDown(0)) { Click.Cancelled(_owner, 0); TrackClick(); Cancel(); return; } if (Input.GetKeyDown((KeyCode)27)) { Cancel(); return; } KeyCode[] scanned = Scanned; foreach (KeyCode val in scanned) { if (Input.GetKeyDown(val)) { if (!_shortcut || !Modifiers.Contains(val)) { Finish(val, ((IEnumerable<KeyCode>)Modifiers).Where((Func<KeyCode, bool>)Input.GetKey)); return; } _loneModifier = val; } } KeyCode? loneModifier = _loneModifier; if (loneModifier.HasValue) { KeyCode valueOrDefault = loneModifier.GetValueOrDefault(); if (Input.GetKeyUp(valueOrDefault)) { Finish(valueOrDefault, Enumerable.Empty<KeyCode>()); } } } private unsafe static void Finish(KeyCode main, IEnumerable<KeyCode> held) { Action<string, IReadOnlyList<string>> captured = _captured; IReadOnlyList<string> arg = held.Select((KeyCode key) => ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString()).ToList(); End(); captured(((object)(*(KeyCode*)(&main))/*cast due to .constrained prefix*/).ToString(), arg); } private static void End() { _active = false; _owner = null; _endedFrame = Time.frameCount; _captured = null; _cancelled = null; } unsafe static KeyCapture() { KeyCode[] array = new KeyCode[6]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Modifiers = (KeyCode[])(object)array; Scanned = (from key in ((KeyCode[])Enum.GetValues(typeof(KeyCode))).Distinct() where (int)key != 0 && (int)key != 323 && (int)key != 324 && (int)key != 27 where !((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString().StartsWith("Joystick", StringComparison.Ordinal) select key).ToArray(); IsMouseButtonHeld = Input.GetMouseButton; Click = new CancellingClick(); _endedFrame = -1; } } internal static class MedallionArt { private const string OwnGuidPrefix = "mugsy33."; private const long MaxFolderIconBytes = 2097152L; private const int MaxFolderIconSide = 512; private const int DiscSize = 128; private const int CheckerCells = 4; private static readonly Color CheckerLight = new Color(0.6f, 0.6f, 0.6f, 1f); private static readonly Color CheckerDark = new Color(0.3f, 0.3f, 0.3f, 1f); private const int GlyphInset = 18; private const float GlyphThreshold = 0.29411766f; private const float GlyphGain = 1.4f; private static readonly Dictionary<string, Sprite> Icons = new Dictionary<string, Sprite>(); private static readonly Dictionary<string, Sprite> GreyIcons = new Dictionary<string, Sprite>(); private static readonly Dictionary<string, Sprite> FolderIcons = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, Sprite> GreyFolderIcons = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase); private static Sprite _disc; private static Sprite _modsTab; private static Sprite _modsTabGlyph; private static Sprite _reload; private static Sprite _checker; public static Sprite Disc => _disc ?? (_disc = CreateDisc()); public static Sprite Checker => _checker ?? (_checker = CreateChecker()); public static Sprite ModsTab { get { object obj = _modsTab; if (obj == null) { obj = LoadEmbedded("ModsTab.png") ?? throw new InvalidOperationException("The embedded tab tile 'ModsTab.png' is missing."); _modsTab = (Sprite)obj; } return (Sprite)obj; } } public static Sprite Reload { get { object obj = _reload; if (obj == null) { obj = LoadEmbedded("Reload.png") ?? throw new InvalidOperationException("The embedded reload plate art 'Reload.png' is missing."); _reload = (Sprite)obj; } return (Sprite)obj; } } public static Sprite ModsTabGlyph => _modsTabGlyph ?? (_modsTabGlyph = CreateGlyph(ModsTab.texture)); public static Sprite FindIcon(string folder, IEnumerable<string> pluginGuids, bool greyscale) { Sprite val = FolderArt.First(folder, (string path) => FolderIcon(path, greyscale)); if ((Object)(object)val != (Object)null) { return val; } foreach (string pluginGuid in pluginGuids) { if (pluginGuid.StartsWith("mugsy33.", StringComparison.Ordinal)) { Sprite val2 = (greyscale ? LoadGreyIcon(pluginGuid) : LoadIcon(pluginGuid)); if ((Object)(object)val2 != (Object)null) { return val2; } } } return null; } private static Sprite FolderIcon(string path, bool greyscale) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown Dictionary<string, Sprite> dictionary = (greyscale ? GreyFolderIcons : FolderIcons); if (dictionary.TryGetValue(path, out var value)) { return value; } if (!File.Exists(path)) { return null; } Sprite val2; try { Sprite val = LoadFolderIcon(path); val2 = (Sprite)((greyscale && (Object)(object)val != (Object)null) ? ((object)Greyscale(val.texture)) : ((object)val)); } catch (Exception ex) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(34, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("The medallion art '"); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(path); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' is not used: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message); } log.LogWarning(val3); FolderIcons.TryAdd(path, null); val2 = null; } dictionary[path] = val2; return val2; } private static Sprite LoadFolderIcon(string path) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if (FolderIcons.TryGetValue(path, out Sprite value)) { return value; } Sprite sprite; string text = ReadFolderIcon(path, out sprite); if (text != null) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(35, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The medallion art '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(path); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' is not used: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } log.LogWarning(val); } FolderIcons[path] = sprite; return sprite; } private static string ReadFolderIcon(string path, out Sprite sprite) { //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) sprite = null; byte[] array; try { long length = new FileInfo(path).Length; if (length > 2097152) { return $"it is {length} bytes, more than the {2097152} allowed"; } array = File.ReadAllBytes(path); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { return "it could not be read (" + ex.Message + ")"; } if (!PngHeader.TryRead(array, out var width, out var height)) { return "it is not a PNG"; } if (width > 512 || height > 512) { return $"it is {width} x {height}, larger than {512} x {512}"; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array))) { Object.Destroy((Object)(object)val); return "it is not an image Unity can decode"; } sprite = Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f))); return null; } private static Sprite LoadIcon(string guid) { if (Icons.TryGetValue(guid, out Sprite value)) { return value; } Sprite val = LoadEmbedded("Icons." + guid + ".png"); Icons[guid] = val; return val; } private static Sprite LoadGreyIcon(string guid) { if (GreyIcons.TryGetValue(guid, out Sprite value)) { return value; } Sprite val = LoadIcon(guid); Sprite val2 = (((Object)(object)val == (Object)null) ? null : Greyscale(val.texture)); GreyIcons[guid] = val2; return val2; } private static Sprite Greyscale(Texture2D source) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) Il2CppStructArray<Color> pixels = source.GetPixels(); for (int i = 0; i < ((Il2CppArrayBase<Color>)(object)pixels).Length; i++) { Color val = ((Il2CppArrayBase<Color>)(object)pixels)[i]; float num = 0.299f * val.r + 0.587f * val.g + 0.114f * val.b; ((Il2CppArrayBase<Color>)(object)pixels)[i] = new Color(num, num, num, val.a); } Texture2D val2 = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false); val2.SetPixels(pixels); val2.Apply(); return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val2), new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f))); } private static Sprite LoadEmbedded(string name) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0093: 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) Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetName().Name + "." + name; using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); byte[] array = memoryStream.ToArray(); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array))) { throw new InvalidOperationException("The embedded image '" + text + "' is not a readable PNG."); } return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f))); } private static Sprite CreateDisc() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_0080: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[16384]; float num = 63.5f; float num2 = 63f; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num3 = Mathf.Sqrt(((float)j - num) * ((float)j - num) + ((float)i - num) * ((float)i - num)); array[i * 128 + j] = new Color(1f, 1f, 1f, Mathf.Clamp01(num2 - num3 + 0.5f)); } } val.SetPixels(Il2CppStructArray<Color>.op_Implicit(array)); val.Apply(); return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f))); } private static Sprite CreateChecker() { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(4, 4, (TextureFormat)4, false) { filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1 }; Color[] array = (Color[])(object)new Color[16]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { array[i * 4 + j] = (((j + i) % 2 == 0) ? CheckerLight : CheckerDark); } } val.SetPixels(Il2CppStructArray<Color>.op_Implicit(array)); val.Apply(); return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, 4f, 4f), new Vector2(0.5f, 0.5f))); } private static Sprite CreateGlyph(Texture2D tile) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Expected O, but got Unknown //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) int width = ((Texture)tile).width; int height = ((Texture)tile).height; if (width <= 36 || height <= 36) { throw new InvalidOperationException($"The tab tile is {width} x {height}, too small for its {18}-texel border."); } Il2CppStructArray<Color> pixels = tile.GetPixels(); float[] array = new float[width * height]; for (int i = 0; i < array.Length; i++) { Color val = ((Il2CppArrayBase<Color>)(object)pixels)[i]; array[i] = 0.299f * val.r + 0.587f * val.g + 0.114f * val.b; } bool[] array2 = new bool[width * height]; Queue<int> queue = new Queue<int>(); for (int j = 18; j < width - 18; j++) { queue.Enqueue(18 * width + j); queue.Enqueue((height - 18 - 1) * width + j); } for (int k = 18; k < height - 18; k++) { queue.Enqueue(k * width + 18); queue.Enqueue(k * width + width - 18 - 1); } while (queue.Count > 0) { int num = queue.Dequeue(); if (!array2[num] && !(array[num] > 0.29411766f)) { array2[num] = true; EnqueueNeighbours(queue, num, width, Inside); } } int[] array3 = new int[width * height]; int num2 = 0; int num3 = 0; int num4 = 0; for (int l = 0; l < array3.Length; l++) { if (array2[l] || array3[l] != 0 || !Inside(l % width, l / width)) { continue; } num4++; int num5 = 0; queue.Enqueue(l); while (queue.Count > 0) { int num6 = queue.Dequeue(); if (!array2[num6] && array3[num6] == 0) { array3[num6] = num4; num5++; EnqueueNeighbours(queue, num6, width, Inside); } } if (num5 > num3) { num2 = num4; num3 = num5; } } if (num3 == 0) { throw new InvalidOperationException("The tab tile holds no piece brighter than its stone."); } int num7 = width; int num8 = height; int num9 = -1; int num10 = -1; for (int m = 0; m < array3.Length; m++) { if (array3[m] == num2) { int val2 = m % width; int val3 = m / width; num7 = Math.Min(num7, val2); num9 = Math.Max(num9, val2); num8 = Math.Min(num8, val3); num10 = Math.Max(num10, val3); } } int num11 = num9 - num7 + 1; int num12 = num10 - num8 + 1; Color[] array4 = (Color[])(object)new Color[num11 * num12]; for (int n = 0; n < num12; n++) { for (int num13 = 0; num13 < num11; num13++) { int num14 = (num8 + n) * width + num7 + num13; float num15 = Mathf.Clamp01(array[num14] * 1.4f); array4[n * num11 + num13] = (Color)((array3[num14] == num2) ? new Color(num15, num15, num15, 1f) : Color.clear); } } Texture2D val4 = new Texture2D(num11, num12, (TextureFormat)4, false); val4.SetPixels(Il2CppStructArray<Color>.op_Implicit(array4)); val4.Apply(); return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val4), new Rect(0f, 0f, (float)num11, (float)num12), new Vector2(0.5f, 0.5f))); bool Inside(int x, int y) { if (x >= 18 && y >= 18 && x < width - 18) { return y < height - 18; } return false; } } private static void EnqueueNeighbours(Queue<int> queue, int i, int width, Func<int, int, bool> inside) { int num = i % width; int num2 = i / width; if (inside(num + 1, num2)) { queue.Enqueue(i + 1); } if (inside(num - 1, num2)) { queue.Enqueue(i - 1); } if (inside(num, num2 + 1)) { queue.Enqueue(i + width); } if (inside(num, num2 - 1)) { queue.Enqueue(i - width); } } private static T Keep<T>(T asset) where T : Object { ((Object)asset).hideFlags = (HideFlags)61; return asset; } } internal static class ModDiscovery { private const string KeyboardShortcutTypeName = "KeyboardShortcut"; private static readonly string[] ColourTypeNames = new string[2] { "UnityEngine.Color", "UnityEngine.Color32" }; private const string BrowsableTag = "Browsable"; private const string IsAdvancedTag = "IsAdvanced"; private const string BepInExName = "BepInEx"; private const string EnglishLanguage = "english"; private const string TableResourceSuffix = ".Strings.json"; private static readonly Dictionary<string, TranslationTable> Tables = new Dictionary<string, TranslationTable>(); private static readonly Dictionary<Type, NumberType> NumberTypes = new Dictionary<Type, NumberType> { [typeof(sbyte)] = NumberType.SByte, [typeof(byte)] = NumberType.Byte, [typeof(short)] = NumberType.Int16, [typeof(ushort)] = NumberType.UInt16, [typeof(int)] = NumberType.Int32, [typeof(uint)] = NumberType.UInt32, [typeof(long)] = NumberType.Int64, [typeof(ulong)] = NumberType.UInt64, [typeof(float)] = NumberType.Single, [typeof(double)] = NumberType.Double, [typeof(decimal)] = NumberType.Decimal }; private static readonly HashSet<string> HintProblemsLogged = new HashSet<string>(); private static readonly HashSet<string> TagProblemsLogged = new HashSet<string>(); private static readonly HashSet<string> FileReadsLogged = new HashSet<string>(); private static readonly Dictionary<string, (string Id, ConfigFile File)> Files = new Dictionary<string, (string, ConfigFile)>(StringComparer.OrdinalIgnoreCase); public static List<PluginSnapshot> Snapshot() { Files.Clear(); string language = CurrentLanguage(); List<PluginInfo> list = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.Values.ToList(); HashSet<ConfigFile> standardFiles = new HashSet<ConfigFile>((from config in list.Select(delegate(PluginInfo info) { object instance2 = info.Instance; object obj2 = ((instance2 is BasePlugin) ? instance2 : null); return (obj2 == null) ? null : ((BasePlugin)obj2).Config; }) where config != null select config).Append(ConfigFile.CoreConfig), ReferenceEqualityComparer.Instance); List<PluginSnapshot> list2 = new List<PluginSnapshot>(); foreach (PluginInfo item in list) { PluginSnapshot obj = new PluginSnapshot { Guid = item.Metadata.GUID, Name = item.Metadata.Name, Version = ((object)item.Metadata.Version).ToString(), DllPath = DllPathOf(item) }; object instance = item.Instance; BasePlugin val = (BasePlugin)((instance is BasePlugin) ? instance : null); IReadOnlyList<ConfigFileSnapshot> configFiles; if (val == null) { IReadOnlyList<ConfigFileSnapshot> readOnlyList = new ConfigFileSnapshot[0]; configFiles = readOnlyList; } else { configFiles = FilesOf(item.Metadata.GUID, val, standardFiles); } obj.ConfigFiles = configFiles; obj.Translations = TranslationsOf(item); obj.Language = language; list2.Add(obj); } list2.Add(new PluginSnapshot { Guid = "<BepInEx>", Name = "BepInEx", Version = ((object)Paths.BepInExVersion).ToString(), DllPath = null, ConfigFiles = new ConfigFileSnapshot[1] { FileSnapshot("<BepInEx>", ConfigFile.CoreConfig, null, isStandard: true) } }); return list2; } private static IReadOnlyList<ConfigFileSnapshot> FilesOf(string pluginGuid, BasePlugin plugin, HashSet<ConfigFile> standardFiles) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown EntryFacts entryFacts = EntryFacts.Read(pluginGuid, plugin); List<ConfigFileSnapshot> list = new List<ConfigFileSnapshot> { FileSnapshot(pluginGuid, plugin.Config, entryFacts, isStandard: true) }; try { List<ConfigFileSnapshot> list2 = new List<ConfigFileSnapshot>(); foreach (ConfigFile item in entryFacts.ConfigFiles.Where((ConfigFile config) => !standardFiles.Contains(config))) { list2.Add(FileSnapshot(pluginGuid, item, entryFacts, isStandard: false)); } list.AddRange(list2); } catch (Exception ex) { if (FileReadsLogged.Add(pluginGuid)) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(83, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": a config file it reaches could not be read, so only its standard file is listed: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex); } log.LogWarning(val); } } return list; } public static IEnumerable<ConfigFile> ConfigFiles() { return Files.Values.Select<(string, ConfigFile), ConfigFile>(((string Id, ConfigFile File) known) => known.File); } public static ConfigFile FileOf(string configFile) { if (!Files.TryGetValue(configFile, out (string, ConfigFile) value)) { throw new InvalidOperationException("The config file '" + configFile + "' is not in the last snapshot."); } return value.Item2; } private static ConfigFileSnapshot FileSnapshot(string pluginGuid, ConfigFile config, EntryFacts facts, bool isStandard) { string fullPath = Path.GetFullPath(config.ConfigFilePath); if (!Files.TryGetValue(fullPath, out (string, ConfigFile) value)) { value = (fullPath, config); Files[fullPath] = value; } return new ConfigFileSnapshot { Id = value.Item1, Name = Path.GetFileName(value.Item1), IsStandard = isStandard, Entries = Entries(pluginGuid, value.Item2, facts) }; } private static string CurrentLanguage() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) LocalizationManager instance = LocalizationManager.Instance; if (!((Object)(object)instance == (Object)null)) { return ((object)instance.SystemLanguage/*cast due to .constrained prefix*/).ToString(); } return "english"; } private static TranslationTable TranslationsOf(PluginInfo info) { if (!Tables.TryGetValue(info.Metadata.GUID, out TranslationTable value)) { value = ReadTable(info); Tables[info.Metadata.GUID] = value; } return value; } private static TranslationTable ReadTable(PluginInfo info) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown if (info.Instance == null) { return null; } Assembly assembly = info.Instance.GetType().Assembly; string text = assembly.GetName().Name + ".Strings.json"; try { using Stream stream = assembly.GetManifestResourceStream(text); if (stream == null) { return null; } using StreamReader streamReader = new StreamReader(stream); return TranslationTable.Parse(streamReader.ReadToEnd()); } catch (Exception ex) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(82, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(info.Metadata.GUID); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'s translation table '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' could not be read, so its settings show as it wrote them: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogWarning(val); return null; } } private static List<ConfigEntrySnapshot> Entries(string pluginGuid, ConfigFile config, EntryFacts facts) { return config.Keys.Select((ConfigDefinition definition) => ToSnapshot(pluginGuid, definition, config[definition], facts)).ToList(); } private static ConfigEntrySnapshot ToSnapshot(string pluginGuid, ConfigDefinition definition, ConfigEntryBase entry, EntryFacts facts) { ValueKind valueKind = TypeKindOf(entry); ValueKind valueKind2 = (IsAcceptableValueList(entry.Description.AcceptableValues) ? ValueKind.AcceptableValues : valueKind); NumberType numberType = ((valueKind == ValueKind.Number) ? NumberTypes[entry.SettingType] : NumberType.SByte); string rangeMin; string rangeMax; if (valueKind2 == ValueKind.Number) { (rangeMin, rangeMax) = Range(entry); } else { rangeMin = null; rangeMax = null; } DescriptionHint descriptionHint = DescriptionHint.Parse(entry.Description.Description, valueKind2, numberType); LogHintProblems(pluginGuid, definition, descriptionHint); EntryTags entryTags = ConfigTags.Read(entry.Description.Tags); LogTagProblems(pluginGuid, definition, entryTags); string text = TomlTypeConverter.ConvertToString(entry.DefaultValue, entry.SettingType); return new ConfigEntrySnapshot { Section = definition.Section, Key = definition.Key, Value = entry.GetSerializedValue(), Description = descriptionHint.Text, Kind = valueKind2, TypeKind = valueKind, DefaultValue = text, DefaultTakes = DefaultTakes(entry, text), AllowedValues = AllowedValues(entry, valueKind2), DeclaredTiming = entryTags.DeclaredTiming, HasSettingChangedHandler = (facts?.HasSettingChangedHandler(entry) ?? false), CopiedAndDropped = (facts?.CopiedAndDropped(entry) ?? false), Browsable = !TagSets(entry.Description, "Browsable", value: false), IsAdvanced = TagSets(entry.Description, "IsAdvanced", value: true), ReadOnly = entryTags.ReadOnly, DisplayName = entryTags.DispName, Order = entryTags.Order, TooltipText = entryTags.Description, NumberType = numberType, RangeMin = rangeMin, RangeMax = rangeMax, Step = descriptionHint.Step, HintMin = descriptionHint.Min, HintMax = descriptionHint.Max, ColourHint = descriptionHint.Colour }; } internal static bool ConverterKeeps(Type type, string text) { try { object value; return RoundTrip(type, text, out value) == text; } catch (Exception) { return false; } } internal static string RoundTrip(Type type, string text, out object value) { value = TomlTypeConverter.ConvertToValue(text, type); return TomlTypeConverter.ConvertToString(value, type); } internal static bool Allows(ConfigEntryBase entry, object value) { AcceptableValueBase acceptableValues = entry.Description.AcceptableValues; if (acceptableValues != null) { return acceptableValues.IsValid(value); } return true; } private static bool DefaultTakes(ConfigEntryBase entry, string defaultText) { try { object value; return RoundTrip(entry.SettingType, defaultText, out value) == defaultText && Allows(entry, value); } catch (Exception) { return false; } } private static void LogHintProblems(string pluginGuid, ConfigDefinition definition, DescriptionHint hint) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown if (hint.Problems.Count != 0 && HintProblemsLogged.Add($"{pluginGuid}/{definition.Section}/{definition.Key}")) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(37, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The [ConfigForge: ...] hint on "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Section); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Key); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(" ", hint.Problems)); } log.LogWarning(val); } } private static void LogTagProblems(string pluginGuid, ConfigDefinition definition, EntryTags tags) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown if (tags.Problems.Count != 0 && TagProblemsLogged.Add($"{pluginGuid}/{definition.Section}/{definition.Key}")) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(25, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The config tags on "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Section); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Key); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(" ", tags.Problems)); } log.LogWarning(val); } } private static (string Min, string Max) Range(ConfigEntryBase entry) { AcceptableValueBase acceptableValues = entry.Description.AcceptableValues; if (acceptableValues == null || !((object)acceptableValues).GetType().IsGenericType || ((object)acceptableValues).GetType().GetGenericTypeDefinition() != typeof(AcceptableValueRange<>)) { return (Min: null, Max: null); } Type type = ((object)acceptableValues).GetType(); object value = type.GetProperty("MinValue").GetValue(acceptableValues); object value2 = type.GetProperty("MaxValue").GetValue(acceptableValues); return (Min: TomlTypeConverter.ConvertToString(value, entry.SettingType), Max: TomlTypeConverter.ConvertToString(value2, entry.SettingType)); } private static ValueKind TypeKindOf(ConfigEntryBase entry) { if (entry.SettingType == typeof(bool)) { return ValueKind.Bool; } if (entry.SettingType == typeof(KeyCode)) { return ValueKind.KeyCode; } if (entry.SettingType.Name == "KeyboardShortcut") { return ValueKind.KeyboardShortcut; } if (entry.SettingType.IsEnum) { if (!entry.SettingType.IsDefined(typeof(FlagsAttribute), inherit: false)) { return ValueKind.Enum; } return ValueKind.Other; } if (NumberTypes.ContainsKey(entry.SettingType)) { return ValueKind.Number; } if (entry.SettingType == typeof(string)) { return ValueKind.String; } if (ColourTypeNames.Contains<string>(entry.SettingType.FullName) && ConverterKeeps(entry.SettingType, TomlTypeConverter.ConvertToString(entry.DefaultValue, entry.SettingType))) { return ValueKind.Colour; } return ValueKind.Other; } private static bool IsAcceptableValueList(AcceptableValueBase acceptable) { if (acceptable != null && ((object)acceptable).GetType().IsGenericType) { return ((object)acceptable).GetType().GetGenericTypeDefinition() == typeof(AcceptableValueList<>); } return false; } private static IReadOnlyList<string> AllowedValues(ConfigEntryBase entry, ValueKind kind) { IEnumerable<object> source; switch (kind) { case ValueKind.KeyCode: case ValueKind.KeyboardShortcut: return Enum.GetNames(typeof(KeyCode)); case ValueKind.AcceptableValues: source = ((Array)((object)entry.Description.AcceptableValues).GetType().GetProperty("AcceptableValues").GetValue(entry.Description.AcceptableValues)).Cast<object>(); break; case ValueKind.Bool: source = new object[2] { false, true }; break; case ValueKind.Enum: source = Enum.GetValues(entry.SettingType).Cast<object>(); break; default: source = Enumerable.Empty<object>(); break; } return source.Select((object value) => TomlTypeConverter.ConvertToString(value, entry.SettingType)).Distinct().ToList(); } private static bool TagSets(ConfigDescription description, string name, bool value) { foreach (object item in description.Tags.Where((object tag) => tag != null)) { Type type = item.GetType(); if ((type.GetField(name, BindingFlags.Instance | BindingFlags.Public)?.GetValue(item) ?? type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public)?.GetValue(item)) is bool flag && flag == value) { return true; } } return false; } private static string DllPathOf(PluginInfo info) { string location = info.Location; if (string.IsNullOrEmpty(location)) { return null; } string relativePath = Path.GetRelativePath(Paths.PluginPath, location); if (relativePath.StartsWith("..", StringComparison.Ordinal) || Path.IsPathRooted(relativePath)) { return null; } return location; } } internal sealed class ModSettingsContent { private sealed class RowView { public SettingRow Row; public RectTransform Rect; public TMP_Text Value; public Color RestColor; public Transform Keycaps; public Image[] Pips; public Slider Slider; public TMP_InputField Field; public Image Swatch; public Selectable Stop; public GameObject FocusFrame; } private const int ListView = -1; private const int MaxPips = 10; private const float DisabledAlpha = 0.5f; private const int MostNoteLines = 6; private const float AdvancedButtonRowHeight = 56f; private const float AdvancedButtonHeight = 36f; private const float AdvancedButtonPadding = 20f; private static readonly Color WarningNoteColor = new Color(1f, 40f / 51f, 20f / 51f); private const float WarningNotePadding = 16f; private const float WarningNoteSideMargin = 40f; private static readonly Color ErrorNoteColor = new Color(1f, 0.41960785f, 0.41960785f); private const float ButtonGap = 10f; private const float KeycapHeight = 28f; private const float KeycapPadding = 8f; private const float KeycapGap = 6f; private const float KeycapMinWidth = 28f; private const float SliderValueWidth = 64f; private const float FieldHeight = 28f; private const float FieldTextInset = 6f; private const float SwatchGap = 8f; private const float SwatchInset = 2f; private static readonly Color PlainFieldFill = new Color(0f, 0f, 0f, 0.35f); private const float ResetLabelPadding = 16f; private const int Columns = 3; private const float PlateHeight = 104f; private const float PlateGap = 14f; private const float ViewportMargin = 20f; private const float NameSizeScale = 1.25f; private const float SubtitleMinScale = 0.6f; private const float TextLeft = 104f; private const float MedallionSize = 84f; private const float DiscFraction = 0.78f; private static readonly Color PlateFill = new Color(0.08f, 0.07f, 0.06f, 1f); private static readonly Color GlowHidden = new Color(1f, 1f, 1f, 0f); private static readonly Color SubtitleColor = new Color(0.62f, 0.69f, 0.66f); private static readonly Color DiscColor = new Color(0.16f, 0.24f, 0.24f, 1f); private static readonly Color InitialsColor = new Color(0.85f, 0.88f, 0.87f); private static readonly Color UnsupportedFrameColor = new Color(0.4f, 0.4f, 0.4f); private static readonly Color UnsupportedNameColor = new Color(28f / 51f, 28f / 51f, 28f / 51f); private static readonly Color UnsupportedSubtitleColor = new Color(0.47058824f, 0.47058824f, 0.47058824f); private static readonly Color UnsupportedDiscColor = new Color(0.16862746f, 0.16862746f, 0.16862746f, 1f); private const float UnsupportedMedallionAlpha = 0.6f; private RectTransform _area; private int _aboveSortingOrder; private TMP_Text _pageTitle; private ScrollRect _scroll; private Vector2 _scrollBottom; private float? _listDrop; private RectTransform _content; private GameObject _headerTemplate; private Color _nameColor; private HashSet<string> _ownTabs; private GameObject _plateTemplate; private GameObject _medallionTemplate; private GameObject _rowTemplate; private GameObject _keyRowTemplate; private GameObject _sliderRowTemplate; private Color _sliderValueColor; private static bool _advancedHeaderFailed; private TMP_Text _advancedTitle; private RectTransform _advancedButton; private readonly GameObject[] FieldTemplates = (GameObject[])(object)new GameObject[2]; private RectTransform _picker; private ColorPickerController _pickerController; private RowView _pickerView; private Rgba _pickerShown; private StagedState _pickerBefore; private TMP_Text _pickerHint; private KitTooltip _tooltip; private KitNote _note; private GameObject _allModsButton; private Button _applyButton; private Button _resetButton; private float _resetBaseWidth; private float _resetMaxWidth; private float _valueFontSize; private Color _keyTextColor; private GameObject _keycapTemplate; private Color _keycapBorderColor; private Color _valueColor; private Color _pipColor; private TMP_FontAsset _titleFont; private ModCatalog _catalog; private int _view = -1; private ModPage _page; private readonly List<RowView> Rows = new List<RowView>(); private int _hoveredRow = -1; private bool _invalidNoteShown; private readonly List<object> ContentListeners = new List<object>(); private readonly List<object> ViewListeners = new List<object>(); private readonly List<object> RetiredListeners = new List<object>(); private int _listenersRetiredFrame; private const float FocusScrollMargin = 24f; private const float FocusTooltipIndent = 40f; private readonly Dictionary<int, Button> PlateButtons = new Dictionary<int, Button>(); private Button _reloadPlate; private Button _advancedHeaderButton; private bool _refreshMenu; private Selectable _focusNext; private IntPtr _followed; private Selectable _lastStop; private RowView _typeNext; private readonly HashSet<Button> _disableOnTick = new HashSet<Button>(); internal bool IsActive { get { if ((Object)(object)_area != (Object)null) { return ((Component)_area).gameObject.activeInHierarchy; } return false; } } internal bool PickerOpen => _pickerView != null; internal bool OnModPage => _view != -1; internal bool LeaveWouldAsk => LeaveRule.AsksBeforeLeaving(OnModPage, _page?.StagedChanges.Count ?? 0); private static bool PadMode => (int)MenuManager.CurrentInputMode != 1; public bool Back() { if (_pickerView != null) { ClosePicker(); return true; } if (_view == -1) { return false; } LeavePageThen(ShowList); return true; } internal void LeavePageThen(Action next) { ClosePicker(); if (!LeaveWouldAsk) { next(); return; } _tooltip.Hide(); _hoveredRow = -1; KitConfirmDialog.Ask(KitStrings.ApplyChangesMessage, _aboveSortingOrder, delegate { ApplyPage(); if (!LeaveWouldAsk) { next(); } }, next, Plugin.Log); } public void Tick() { if (Time.frameCount > _listenersRetiredFrame) { RetiredListeners.Clear(); } if (_disableOnTick.Count > 0) { Button[] array = _disableOnTick.ToArray(); _disableOnTick.Clear(); Button[] array2 = array; foreach (Button val in array2) { if ((Object)(object)val != (Object)null) { ((Selectable)val).interactable = false; } } } if (IsActive) { TickFocus(); } if (IsActive && _view != -1) { UpdateTooltip(); if (Input.GetMouseButtonDown(1) && _hoveredRow >= 0 && Rows[_hoveredRow].Row.IsKeyCapture && !Rows[_hoveredRow].Row.ReadOnly) { ClearKey(Rows[_hoveredRow]); } if (_pickerView != null && (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))) { HidePicker(); } } } private void ClearKey(RowView view) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if (_page.ValueOf(view.Row) == "None") { return; } if (!_page.Stage(view.Row, "None")) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(67, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Clearing '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(view.Row.Section); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(view.Row.Key); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' was refused: None is not a value this setting accepts."); } log.LogWarning(val); } RefreshPage(); } public int Enter() { _catalog = new ModCatalog(Paths.PluginPath, ModDiscovery.Snapshot()); Canvas.ForceUpdateCanvases(); UiParts.Label(_allModsButton.transform).text = ModStrings.Get("button.all_mods"); UiParts.Label(((Component)_resetButton).transform).text = ModStrings.Get("button.reset_mod"); ShowList(); return _catalog.Plates.Count; } public void Hide() { KeyCapture.Cancel(); TextEntry.Abandon(); ClosePicker(); _tooltip.Hide(); } private void ShowList() { int view = _view; SetView(-1); _pageTitle.text = ModStrings.Get("list.title"); KitHeader.Add(_headerTemplate, (Transform)(object)_content, ModStrings.Get("header.installed_mods")); FillPlates(_catalog.Plates); ScrollToTop(); Button value; Button next = (Button)(PlateButtons.TryGetValue(view, out value) ? ((object)value) : ((object)((from p in PlateButtons orderby p.Key select p.Value).FirstOrDefault() ?? _reloadPlate))); FocusAfterViewChange((Selectable)(object)next); } private void ShowPage(int plateIndex) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown SetView(plateIndex); FitResetButton(); _page = _catalog.Page(plateIndex); _pageTitle.text = _page.Name; AddPageRows(); RefreshPage(); ScrollToTop(); FocusAfterViewChange((Selectable)(((object)FirstStop()) ?? ((object)(_advancedHeaderButton ?? _allModsButton.GetComponent<Button>())))); ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Mod page shown: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_page.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_page.Sections.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" sections, "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_page.AdvancedCount); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" advanced settings."); } log.LogInfo(val); } private void AddPageRows() { if (_page.IsBepInEx) { AddPageNote(ModStrings.Get("page.bepinex_note")); } foreach (PageSection section in _page.Sections) { AddSection(section); } if (!_page.HasAdvanced) { return; } if (_advancedHeaderFailed || !TryAddAdvancedHeader()) { if (!_page.AdvancedExpanded) { _page.ToggleAdvanced(); } _advancedTitle = KitHeader.Add(_headerTemplate, (Transform)(object)_content, AdvancedHeaderText()); } if (!_page.AdvancedExpanded) { return; } foreach (PageSection advancedSection in _page.AdvancedSections) { AddSection(advancedSection); } } private void AddSection(PageSection section) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (section.FileHeader != null) { AddBoxedLine("FileHeader", RichText.Plain(section.FileHeader), KitFieldFrame.RestColor); } KitHeader.Add(_headerTemplate, (Transform)(object)_content, section.Title); foreach (SettingRow row in section.Rows) { AddRow(row); } } private bool TryAddAdvancedHeader() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Expected O, but got Unknown GameObject val = null; try { RectTransform val2 = UiParts.NewRect("AdvancedHeader", (Transform)(object)_content); val = ((Component)val2).gameObject; val.AddComponent<LayoutElement>().preferredHeight = 56f; RectTransform val3 = UiParts.NewRect("Button", (Transform)(object)val2); Vector2 val4 = (val3.pivot = new Vector2(0.5f, 0.5f)); Vector2 anchorMin = (val3.anchorMax = val4); val3.anchorMin = anchorMin; ((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = PlainFieldFill; Image target = KitFieldFrame.Add((Transform)(object)val3); TMP_Text component = UiParts.CloneInto(KitHeader.Title(_headerTemplate).transform, (Transform)(object)val3).GetComponent<TMP_Text>(); UiParts.StripAll(((Component)component).gameObject, "ContentSizeFitter", "LayoutElement"); UiParts.Stretch(component.rectTransform); component.alignment = (TextAlignmentOptions)514; component.enableWordWrapping = false; ((Graphic)component).raycastTarget = false; ((Graphic)component).color = _nameColor; component.enableAutoSizing = true; component.fontSizeMax = component.fontSize; component.fontSizeMin = component.fontSize * 0.6f; Button val7 = FocusButton(((Component)val3).gameObject, (Graphic)(object)target, _nameColor); UiParts.Hook(val7, ToggleAdvancedGroup, ViewListeners); _advancedHeaderButton = val7; _advancedTitle = component; _advancedButton = val3; ShowAdvancedHeaderText(); return true; } catch (Exception ex) { if ((Object)(object)val != (Object)null) { val.SetActive(false); Object.Destroy((Object)(object)val); } _advancedTitle = null; _advancedButton = null; _advancedHeaderButton = null; _advancedHeaderFailed = true; ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val8 = new BepInExErrorLogInterpolatedStringHandler(103, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("The advanced settings header could not be built; advanced settings show expanded under a plain header: "); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted<Exception>(ex); } log.LogError(val8); return false; } } private void ShowAdvancedHeaderText() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) string text = AdvancedHeaderText(); _advancedTitle.text = text; if (!((Object)(object)_advancedButton == (Object)null)) { _advancedTitle.fontSize = _advancedTitle.fontSizeMax; float num = _advancedTitle.GetPreferredValues(text, float.PositiveInfinity, float.PositiveInfinity).x + 40f; Rect rect = _content.rect; float num2 = Mathf.Min(num, ((Rect)(ref rect)).width - 40f); _advancedButton.sizeDelta = new Vector2(num2, 36f); } } private string AdvancedHeaderText() { if (_advancedHeaderFailed) { return ModStrings.Get("page.advanced_header", _page.AdvancedCount); } if (_page.AdvancedExpanded) { return ModStrings.Get("page.advanced_hide", _page.AdvancedCount); } if (_page.HiddenChangeCount <= 0) { return ModStrings.Get("page.advanced_show", _page.AdvancedCount); } return ModStrings.Get("page.advanced_show_changed", _page.AdvancedCount, _page.HiddenChangeCount); } private void ToggleAdvancedGroup() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) _page.ToggleAdvanced(); Vector2 anchoredPosition = _content.anchoredPosition; ClearContent(); AddPageRows(); RefreshPage(); LayoutRebuilder.ForceRebuildLayoutImmediate(_content); _content.anchoredPosition = anchoredPosition; FocusAfterViewChange((Selectable)(object)_advancedHeaderButton); } private void AddPageNote(string text) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) AddBoxedLine("PageNote", text, WarningNoteColor); } private void AddBoxedLine(string name, string text, Color colour) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) float preferredHeight = _rowTemplate.GetComponent<LayoutElement>().preferredHeight; RectTransform val = UiParts.NewRect(name, (Transform)(object)_content); VerticalLayoutGroup val2 = ((Component)val).gameObject.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)val2).padding = new RectOffset(Mathf.RoundToInt(40f), Mathf.RoundToInt(40f), Mathf.RoundToInt(preferredHeight), Mathf.RoundToInt(preferredHeight)); FitChildren(val2); RectTransform val3 = UiParts.NewRect("Box", (Transform)(object)val); Image obj = ((Component)val3).gameObject.AddComponent<Image>(); ((Graphic)obj).color = PlainFieldFill; ((Graphic)obj).raycastTarget = false; VerticalLayoutGroup val4 = ((Component)val3).gameObject.AddComponent<VerticalLayoutGroup>(); int num = Mathf.RoundToInt(16f); ((LayoutGroup)val4).padding = new RectOffset(num, num, num, num); FitChildren(va