using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.NET.Common; using Candide; using Candide.CandideUI; using Candide.CandideUI.Components; using Candide.CandideUI.Components.Buttons; using Candide.CandideUI.Containers; using Candide.CandideUI.Input; using Candide.CandideUI.PauseMenuUi; using Candide.CandideUI.Windows; using Candide.Database; using Candide.Input; using Candide.MainMenu.Ui; using Candide.Sound; using Candide.Toolkit; using Candide.UserSettings; using CandideCreator.Shared; using CandideCreator.Shared.Graphics; using FontStashSharp.RichText; using HarmonyLib; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using ModSettingsMenu.Api; using ModSettingsMenu.Localization; using ModSettingsMenu.Metadata; using ModSettingsMenu.Ui; using ModSettingsMenu.Update; using Shared.Text; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Mod Settings Menu")] [assembly: AssemblyDescription("Mod Settings Menu for Romestead by Ice Box Studio")] [assembly: AssemblyCompany("Ice Box Studio")] [assembly: AssemblyProduct("Mod Settings Menu")] [assembly: AssemblyCopyright("Copyright © 2026 Ice Box Studio All rights reserved.")] [assembly: ComVisible(false)] [assembly: Guid("A59CDBF0-FC3E-4DD6-B514-8479E0FC91A6")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] [assembly: AssemblyVersion("1.0.6.0")] [module: RefSafetyRules(11)] namespace ModSettingsMenu { [BepInPlugin("IceBoxStudio.Romestead.ModSettingsMenu", "Mod Settings Menu", "1.0.6")] public sealed class ModSettingsMenu : BasePlugin { private Harmony _harmony; public static ModSettingsMenu Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } public override void Load() { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown Instance = this; Logger = ((BasePlugin)this).Log; bool flag = default(bool); try { Logger.LogInfo((object)"============================================="); ManualLogSource logger = Logger; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(16, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("Mod Settings Menu"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" initializing..."); } logger.LogInfo(val); ManualLogSource logger2 = Logger; val = new BepInExInfoLogInterpolatedStringHandler(48, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Author: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("Ice Box Studio"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("(https://steamcommunity.com/id/ibox666/)"); } logger2.LogInfo(val); _harmony = new Harmony("IceBoxStudio.Romestead.ModSettingsMenu"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ManualLogSource logger3 = Logger; val = new BepInExInfoLogInterpolatedStringHandler(13, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("Mod Settings Menu"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" initialized."); } logger3.LogInfo(val); Logger.LogInfo((object)"============================================="); } catch (Exception ex) { ManualLogSource logger4 = Logger; BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(24, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted("Mod Settings Menu"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" initialization error: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex.Message); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\n"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex.StackTrace); } logger4.LogError(val2); } } } public static class PluginInfo { public const string PLUGIN_GUID = "IceBoxStudio.Romestead.ModSettingsMenu"; public const string PLUGIN_NAME = "Mod Settings Menu"; public const string PLUGIN_VERSION = "1.0.6"; public const string PLUGIN_AUTHOR = "Ice Box Studio"; } } namespace ModSettingsMenu.Update { internal static class ModUpdateChecker { private const int MaxManifestBytes = 16384; private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(4.0); private static readonly Dictionary Results = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet StartedChecks = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly object Sync = new object(); private static readonly HttpClient Client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false }) { Timeout = Timeout }; public static ModUpdateCheckResult GetOrStart(ModSettingsRegistration registration) { if (registration == null || string.IsNullOrWhiteSpace(registration.UpdateManifestUrl)) { return ModUpdateCheckResult.NotConfigured(); } lock (Sync) { if (Results.TryGetValue(registration.PluginGuid, out var value)) { return value; } if (StartedChecks.Add(registration.PluginGuid)) { Results[registration.PluginGuid] = ModUpdateCheckResult.Checking(); CheckAsync(registration.PluginGuid, registration.Version, registration.UpdateManifestUrl); } return Results[registration.PluginGuid]; } } private static async Task CheckAsync(string pluginGuid, string currentVersion, string manifestUrl) { ModUpdateCheckResult value = await CheckCoreAsync(currentVersion, manifestUrl).ConfigureAwait(continueOnCapturedContext: false); lock (Sync) { Results[pluginGuid] = value; } } private static async Task CheckCoreAsync(string currentVersion, string manifestUrl) { _ = 4; try { if (!TryValidateHttpsUri(manifestUrl, out var uri)) { return Failed(); } IPAddress[] array = await Dns.GetHostAddressesAsync(uri.Host).ConfigureAwait(continueOnCapturedContext: false); if (array.Length == 0 || array.Any(IsUnsafeAddress)) { return Failed(); } using (CancellationTokenSource cts = new CancellationTokenSource(Timeout)) { using HttpResponseMessage response = await Client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, cts.Token).ConfigureAwait(continueOnCapturedContext: false); if (response.StatusCode != HttpStatusCode.OK) { return Failed(); } string text = response.Content.Headers.ContentType?.MediaType; if (!string.IsNullOrWhiteSpace(text) && !text.Equals("application/json", StringComparison.OrdinalIgnoreCase) && !text.Equals("text/json", StringComparison.OrdinalIgnoreCase) && !text.Equals("text/plain", StringComparison.OrdinalIgnoreCase)) { return Failed(); } long? contentLength = response.Content.Headers.ContentLength; if (contentLength.HasValue && contentLength.Value > 16384) { return Failed(); } ModUpdateCheckResult result; await using (Stream stream = await response.Content.ReadAsStreamAsync(cts.Token).ConfigureAwait(continueOnCapturedContext: false)) { result = ParseManifest(await ReadLimitedStringAsync(stream, cts.Token).ConfigureAwait(continueOnCapturedContext: false), currentVersion); } return result; } IL_0475: ModUpdateCheckResult result2; return result2; } catch (OperationCanceledException) { return Failed(); } catch (Exception ex2) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(21, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Update check failed: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex2.Message); } logger.LogWarning(val); } return Failed(); } } private static ModUpdateCheckResult ParseManifest(string json, string currentVersion) { using JsonDocument jsonDocument = JsonDocument.Parse(json); JsonElement rootElement = jsonDocument.RootElement; if (rootElement.ValueKind != JsonValueKind.Object) { return Failed(); } string text = GetString(rootElement, "version") ?? GetString(rootElement, "latestVersion"); if (string.IsNullOrWhiteSpace(text) || text.Length > 64) { return Failed(); } bool flag = IsRemoteVersionNewer(currentVersion, text); return new ModUpdateCheckResult { Status = (flag ? ModUpdateCheckStatus.UpdateAvailable : ModUpdateCheckStatus.UpToDate), LatestVersion = text }; } private static string GetString(JsonElement root, string propertyName) { if (!root.TryGetProperty(propertyName, out var value) || value.ValueKind != JsonValueKind.String) { return null; } return value.GetString(); } private static async Task ReadLimitedStringAsync(Stream stream, CancellationToken cancellationToken) { using MemoryStream memory = new MemoryStream(); byte[] buffer = new byte[1024]; while (true) { int num = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (num == 0) { break; } if (memory.Length + num > 16384) { throw new InvalidOperationException("Manifest too large."); } memory.Write(buffer, 0, num); } string text = Encoding.UTF8.GetString(memory.ToArray()); return (text.Length > 0 && text[0] == '\ufeff') ? text.Substring(1) : text; } private static bool TryValidateHttpsUri(string url, out Uri uri) { uri = null; if (string.IsNullOrWhiteSpace(url) || url.Length > 2048 || !Uri.TryCreate(url, UriKind.Absolute, out uri)) { return false; } if (!uri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) { return false; } if (uri.UserInfo.Length > 0 || uri.IsFile || uri.IsLoopback || uri.HostNameType == UriHostNameType.Unknown) { return false; } return true; } private static bool IsUnsafeAddress(IPAddress address) { if (IPAddress.IsLoopback(address)) { return true; } if (address.AddressFamily == AddressFamily.InterNetwork) { byte[] addressBytes = address.GetAddressBytes(); if (addressBytes[0] != 10 && addressBytes[0] != 127 && addressBytes[0] != 0 && (addressBytes[0] != 169 || addressBytes[1] != 254) && (addressBytes[0] != 172 || addressBytes[1] < 16 || addressBytes[1] > 31)) { if (addressBytes[0] == 192) { return addressBytes[1] == 168; } return false; } return true; } if (address.AddressFamily == AddressFamily.InterNetworkV6) { if (!address.IsIPv6LinkLocal && !address.IsIPv6SiteLocal && !address.IsIPv6Multicast && !address.Equals(IPAddress.IPv6None) && !address.Equals(IPAddress.IPv6Any)) { return address.Equals(IPAddress.IPv6Loopback); } return true; } return true; } private static bool IsRemoteVersionNewer(string currentVersion, string latestVersion) { int[] array = ParseVersionParts(currentVersion); int[] array2 = ParseVersionParts(latestVersion); int num = Math.Max(array.Length, array2.Length); for (int i = 0; i < num; i++) { int num2 = ((i < array.Length) ? array[i] : 0); int num3 = ((i < array2.Length) ? array2[i] : 0); if (num3 > num2) { return true; } if (num3 < num2) { return false; } } return false; } private static int[] ParseVersionParts(string version) { if (string.IsNullOrWhiteSpace(version)) { return Array.Empty(); } int result; return (from part in version.Split(new char[3] { '.', '-', '_' }, StringSplitOptions.RemoveEmptyEntries) select int.TryParse(new string(part.TakeWhile(char.IsDigit).ToArray()), out result) ? result : 0).ToArray(); } private static ModUpdateCheckResult Failed() { return new ModUpdateCheckResult { Status = ModUpdateCheckStatus.Failed }; } } internal enum ModUpdateCheckStatus { NotConfigured, Checking, UpToDate, UpdateAvailable, Failed } internal sealed class ModUpdateCheckResult { public ModUpdateCheckStatus Status { get; set; } public string LatestVersion { get; set; } public static ModUpdateCheckResult NotConfigured() { return new ModUpdateCheckResult { Status = ModUpdateCheckStatus.NotConfigured }; } public static ModUpdateCheckResult Checking() { return new ModUpdateCheckResult { Status = ModUpdateCheckStatus.Checking }; } } } namespace ModSettingsMenu.Ui { internal sealed class ModConfigEntryEditor : CandideVerticalStackPanel { private readonly ConfigEntryBase _entry; private readonly bool _keybind; private object _originalValue; public ModConfigEntryEditor(ConfigEntryBase entry, Action onChanged, ModSettingsEntryOptions options = null) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown _entry = entry; _keybind = options != null && options.Keybind && ModKeybindValue.IsSupportedType(entry.SettingType); _originalValue = entry.BoxedValue; ((CandideUiElement)this).HorizontalAlignment = (HorizontalAlignment)3; ((CandideUiElement)this).Margin = new CandideThickness(0, 0, 0, 7); ((CandideUiContainerMultipleItems)this).AddChild(CreateHeader(entry, options), false); if (_keybind) { ((CandideUiContainerMultipleItems)this).AddChild(CreateKeybindInfo(entry), false); return; } object obj; if (!string.IsNullOrWhiteSpace(options?.Description)) { obj = options.Description; } else { ConfigDescription description = entry.Description; obj = ((description != null) ? description.Description : null); } string text = (string)obj; if (!string.IsNullOrWhiteSpace(text)) { ((CandideUiContainerMultipleItems)this).AddChild((CandideUiElement)new CandideTextLabel { Text = text, Wrap = true, TextStyle = (CandideTextStyle)9, Margin = new CandideThickness(0, 1, 0, 3), MaxWidth = 290 }, false); } ((CandideUiContainerMultipleItems)this).AddChild(CreateControl(entry, onChanged, options), false); } public bool HasChanges() { if (_keybind) { return false; } return !object.Equals(_originalValue, _entry.BoxedValue); } public void Undo() { if (!_keybind) { _entry.BoxedValue = _originalValue; } } private static CandideUiElement CreateHeader(ConfigEntryBase entry, ModSettingsEntryOptions options) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown return (CandideUiElement)new CandideTextLabel { Text = (string.IsNullOrWhiteSpace(options?.DisplayName) ? entry.Definition.Key : options.DisplayName), TextStyle = (CandideTextStyle)0, TextColor = Color.White, MaxWidth = 300, Wrap = true }; } private static CandideUiElement CreateControl(ConfigEntryBase entry, Action onChanged, ModSettingsEntryOptions options) { //IL_003e: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown Type settingType = entry.SettingType; if (settingType == typeof(bool)) { CandideCheckboxLabel val = new CandideCheckboxLabel((CheckboxType)1, (int?)210, false) { Text = LocalizationManager.Instance.GetText("entry.bool_label"), Margin = new CandideThickness(0, 2, 0, 0) }; val.Checkbox.IsToggledOn = (bool)entry.BoxedValue; val.Checkbox.Toggled += delegate(object _, bool value) { entry.BoxedValue = value; onChanged(); }; return (CandideUiElement)val; } ConfigDescription description = entry.Description; if (((description != null) ? description.AcceptableValues : null) != null && TryCreateRangeSliderControl(entry, onChanged, options, out var control)) { return control; } ConfigDescription description2 = entry.Description; if (((description2 != null) ? description2.AcceptableValues : null) != null && TryCreateValueListControl(entry, onChanged, out var control2)) { return control2; } if (settingType.IsEnum) { return CreateEnumControl(entry, onChanged); } if (settingType == typeof(int)) { return CreateIntControl(entry, onChanged); } if (settingType == typeof(string)) { return CreateTextControl(entry, onChanged, isString: true); } return CreateTextControl(entry, onChanged, isString: false); } public void Commit() { if (!_keybind) { _originalValue = _entry.BoxedValue; } } private static CandideUiElement CreateKeybindInfo(ConfigEntryBase entry) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown CandideVerticalStackPanel val = new CandideVerticalStackPanel { HorizontalAlignment = (HorizontalAlignment)3, Margin = new CandideThickness(0, 1, 0, 0) }; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)new CandideTextLabel { Text = LocalizationManager.Instance.GetText("entry.keybind_configure_hint"), Wrap = true, TextStyle = (CandideTextStyle)9, TextColor = new Color(255, 224, 161), MaxWidth = 290, Margin = new CandideThickness(0, 0, 0, 2) }, false); CandideTextLabel val2 = new CandideTextLabel(); val2.Text = LocalizationManager.Instance.GetText("entry.keybind_current", ModKeybindValue.FromEntry(entry).ToDisplayString()); val2.Wrap = true; val2.TextStyle = (CandideTextStyle)9; ((CandideUiElement)val2).MaxWidth = 290; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)val2, false); return (CandideUiElement)(object)val; } private static bool TryCreateValueListControl(ConfigEntryBase entry, Action onChanged, out CandideUiElement control) { control = null; AcceptableValueBase acceptableValues = entry.Description.AcceptableValues; if (!(((object)acceptableValues).GetType().GetProperty("AcceptableValues")?.GetValue(acceptableValues) is Array { Length: not 0 } array)) { return false; } ValueSpinnerValue[] array2 = new ValueSpinnerValue[array.Length]; object boxedValue = entry.BoxedValue; ValueSpinnerValue val = null; for (int i = 0; i < array.Length; i++) { object value = array.GetValue(i); ValueSpinnerValue val2 = (array2[i] = new ValueSpinnerValue { Value = value, Name = (value?.ToString() ?? string.Empty) }); if (object.Equals(value, boxedValue)) { val = val2; } } CandideValueSpinner obj = new CandideValueSpinner((IReadOnlyCollection>)(object)array2); ((CandideUiElement)obj).Width = 180; obj.OnClickLeftOrRightSoundEvent = "event:/interface/main menu/ui_mainmenu_click"; CandideValueSpinner val3 = obj; if (val != null) { val3.Value = val; } val3.OnValueChanged += delegate(object _, ValueSpinnerValue val4) { entry.BoxedValue = val4.Value; onChanged(); }; control = (CandideUiElement)(object)val3; return true; } private static bool TryCreateRangeSliderControl(ConfigEntryBase entry, Action onChanged, ModSettingsEntryOptions options, out CandideUiElement control) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Expected O, but got Unknown //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown control = null; AcceptableValueBase acceptableValues = entry.Description.AcceptableValues; if (acceptableValues == null || !((object)acceptableValues).GetType().IsGenericType || ((object)acceptableValues).GetType().GetGenericTypeDefinition() != typeof(AcceptableValueRange<>)) { return false; } Type settingType = entry.SettingType; if (!IsSupportedSliderRangeType(settingType)) { return false; } if (!TryGetDouble(((object)acceptableValues).GetType().GetProperty("MinValue")?.GetValue(acceptableValues), out var min) || !TryGetDouble(((object)acceptableValues).GetType().GetProperty("MaxValue")?.GetValue(acceptableValues), out var max) || !TryGetDouble(entry.BoxedValue, out var result) || max <= min) { return false; } CandideGrid val = new CandideGrid { ColumnsProportions = { Proportion.Auto }, ColumnsProportions = { Proportion.Auto }, HorizontalAlignment = (HorizontalAlignment)0, Margin = new CandideThickness(0, 2, 0, 0) }; double step = GetRangeStep(settingType, min, max, options); result = SnapRangeValue(result, min, max, step); object value = ConvertRangeValue(result, settingType); float sliderStepCount = GetSliderStepCount(min, max, step); CandideHorizontalSlider val2 = new CandideHorizontalSlider { Minimum = 0f, Maximum = sliderStepCount, StepValue = 1f, Value = GetSliderStepIndex(result, min, max, step, sliderStepCount), Width = 210 }; HorizontalBar val3 = new HorizontalBar { GridColumn = 0 }; ((CandideUiContainerSingleItem)val3).SetChild((CandideUiElement)(object)val2); CandideTextLabel valueText = new CandideTextLabel { Text = FormatRangeValue(value, settingType), GridColumn = 1, Width = 70, TextAlign = (TextHorizontalAlignment)2, VerticalAlignment = (VerticalAlignment)1, Margin = new CandideThickness(6, 0, 0, 0) }; val2.ValueChangedByUser += delegate(object _, float sliderValue) { object rangeValue = GetRangeValue(sliderValue, min, max, step, sliderStepCount, settingType); entry.BoxedValue = rangeValue; valueText.Text = FormatRangeValue(rangeValue, settingType); onChanged(); }; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)val3, false); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)valueText, false); control = (CandideUiElement)(object)val; return true; } private static double GetRangeStep(Type settingType, double min, double max, ModSettingsEntryOptions options) { double? num = options?.SliderStep; if (num.HasValue) { double valueOrDefault = num.GetValueOrDefault(); if (valueOrDefault > 0.0) { return Math.Min(valueOrDefault, max - min); } } if (!IsIntegerType(settingType)) { return 0.1; } return 1.0; } private static float GetSliderStepCount(double min, double max, double step) { if (step <= 0.0 || max <= min) { return 1f; } double num = (max - min) / step; double num2 = Math.Round(num); double num3 = ((Math.Abs(num - num2) < 1E-06) ? num2 : Math.Ceiling(num)); if (num3 < 1.0) { return 1f; } if (num3 > 3.4028234663852886E+38) { return float.MaxValue; } return (float)num3; } private static float GetSliderStepIndex(double value, double min, double max, double step, float sliderStepCount) { if (step <= 0.0 || sliderStepCount <= 0f) { return 0f; } if (value >= max) { return sliderStepCount; } double num = Math.Round((value - min) / step); if (num < 0.0) { return 0f; } if (num > (double)sliderStepCount) { return sliderStepCount; } return (float)num; } private static object GetRangeValue(float sliderValue, double min, double max, double step, float sliderStepCount, Type settingType) { return ConvertRangeValue(SnapRangeValue((sliderValue >= sliderStepCount) ? max : (min + step * (double)sliderValue), min, max, step), settingType); } private static object ConvertRangeValue(double value, Type settingType) { if (settingType == typeof(int)) { return (int)Math.Round(value); } if (settingType == typeof(long)) { return (long)Math.Round(value); } if (settingType == typeof(short)) { return (short)Math.Round(value); } if (settingType == typeof(byte)) { return (byte)Math.Round(value); } if (settingType == typeof(float)) { return (float)value; } if (settingType == typeof(double)) { return value; } if (settingType == typeof(decimal)) { return (decimal)value; } return value; } private static double SnapRangeValue(double value, double min, double max, double step) { if (value <= min) { return min; } if (value >= max) { return max; } if (step > 0.0) { value = min + Math.Round((value - min) / step) * step; } if (value < min) { value = min; } if (value > max) { value = max; } return value; } private static bool TryGetDouble(object value, out double result) { try { result = Convert.ToDouble(value, CultureInfo.InvariantCulture); return true; } catch { result = 0.0; return false; } } private static bool IsSupportedSliderRangeType(Type type) { if (!IsIntegerType(type) && !(type == typeof(float)) && !(type == typeof(double))) { return type == typeof(decimal); } return true; } private static bool IsIntegerType(Type type) { if (!(type == typeof(int)) && !(type == typeof(long)) && !(type == typeof(short))) { return type == typeof(byte); } return true; } private static string FormatRangeValue(object value, Type settingType) { if (IsIntegerType(settingType)) { return Convert.ToInt64(value, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture); } return Convert.ToDouble(value, CultureInfo.InvariantCulture).ToString("G5", CultureInfo.InvariantCulture); } private static CandideUiElement CreateEnumControl(ConfigEntryBase entry, Action onChanged) { Array values = Enum.GetValues(entry.SettingType); ValueSpinnerValue[] array = new ValueSpinnerValue[values.Length]; object boxedValue = entry.BoxedValue; ValueSpinnerValue val = null; for (int i = 0; i < values.Length; i++) { object value = values.GetValue(i); ValueSpinnerValue val2 = (array[i] = new ValueSpinnerValue { Value = value, Name = value.ToString() }); if (object.Equals(value, boxedValue)) { val = val2; } } CandideValueSpinner obj = new CandideValueSpinner((IReadOnlyCollection>)(object)array); ((CandideUiElement)obj).Width = 180; obj.OnClickLeftOrRightSoundEvent = "event:/interface/main menu/ui_mainmenu_click"; CandideValueSpinner val3 = obj; if (val != null) { val3.Value = val; } val3.OnValueChanged += delegate(object _, ValueSpinnerValue val4) { entry.BoxedValue = val4.Value; onChanged(); }; return (CandideUiElement)(object)val3; } private static CandideUiElement CreateIntControl(ConfigEntryBase entry, Action onChanged) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown CandideIntSpinnerLabel val = new CandideIntSpinnerLabel { Text = "", Margin = new CandideThickness(0, 2, 0, 0) }; val.IntSpinner.AllowPlayerInput = true; val.IntSpinner.Value = (int)entry.BoxedValue; val.IntSpinner.ValueChangedByUser += delegate(object _, int value) { entry.BoxedValue = value; onChanged(); }; return (CandideUiElement)val; } private static CandideUiElement CreateTextControl(ConfigEntryBase entry, Action onChanged, bool isString) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_00a0: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Expected O, but got Unknown CandideGrid val = new CandideGrid { ColumnsProportions = { Proportion.Fill }, ColumnsProportions = { Proportion.Auto }, HorizontalAlignment = (HorizontalAlignment)3, MaxWidth = 300, Margin = new CandideThickness(0, 2, 0, 0) }; CandideTextInputBox input = new CandideTextInputBox { Text = (isString ? (((string)entry.BoxedValue) ?? string.Empty) : entry.GetSerializedValue()), SelectAllWhenSelected = true, Width = 220, Height = 18, Padding = new CandideThickness(4, 2), Background = new Color(22, 19, 15, 190), GridColumn = 0 }; input.TextChangedByUser += delegate(object _, ValueChangedEventArgs args) { if (isString) { entry.BoxedValue = args.NewValue ?? string.Empty; } else { entry.SetSerializedValue(args.NewValue ?? string.Empty); } onChanged(); }; CandideLabelButton val2 = new CandideLabelButton(48, (int?)null) { Text = LocalizationManager.Instance.GetText("entry.reset"), GridColumn = 1, Margin = new CandideThickness(5, 0, 0, 0), Padding = new CandideThickness(4, 2), OnClickedSoundEvent = "event:/interface/navigate" }; ((CandideButtonBase)val2).OnClickAction = delegate { string text = entry.DefaultValue?.ToString() ?? string.Empty; input.Text = text; if (isString) { entry.BoxedValue = text; } else { entry.SetSerializedValue(text); } onChanged(); }; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)input, false); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)val2, false); return (CandideUiElement)val; } } internal sealed class ModConfigIconLabel : CandideGrid { private readonly CandideIcon _builtinIcon; private readonly ModIconImage _customIcon; private readonly CandideTextLabel _label; private bool _hideIcon; public string Icon { get { return _builtinIcon.Icon; } set { _builtinIcon.Icon = value; UpdateIconVisibility(); } } public string IconPath { get { return _customIcon.IconPath; } set { _customIcon.IconPath = value; UpdateIconVisibility(); } } public string Text { get { return _label.Text; } set { if (!(_label.Text == value)) { _label.Text = value; ((CandideUiElement)_label).Visible = !string.IsNullOrWhiteSpace(value); ((CandideUiElement)this).InvalidateMeasure(); } } } public Color TextColor { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _label.TextColor; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) _label.TextColor = value; } } public bool HideIcon { get { return _hideIcon; } set { _hideIcon = value; UpdateIconVisibility(); } } public ModConfigIconLabel(IconFlag sizeFlags, bool flipOrientation = false, int? labelWidth = null, bool useTranslationCenteredText = false) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_00d2: 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_00e3: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown _builtinIcon = new CandideIcon(sizeFlags) { GridColumn = (flipOrientation ? 1 : 0) }; ModIconImage modIconImage = new ModIconImage(sizeFlags); ((CandideUiElement)modIconImage).GridColumn = (flipOrientation ? 1 : 0); ((CandideUiElement)modIconImage).Visible = false; _customIcon = modIconImage; _label = (CandideTextLabel)(useTranslationCenteredText ? new TranslationCenteredTextLayout { Width = labelWidth, Margin = (flipOrientation ? new CandideThickness(0, 0, 4, 0) : new CandideThickness(4, 0, 0, 0)), VerticalAlignment = (VerticalAlignment)1, TextAlign = (TextHorizontalAlignment)(flipOrientation ? 2 : 0), HorizontalAlignment = (HorizontalAlignment)3, GridColumn = ((!flipOrientation) ? 1 : 0), Visible = false } : new CandideTextLabel { Width = labelWidth, Margin = (flipOrientation ? new CandideThickness(0, 0, 4, 0) : new CandideThickness(4, 0, 0, 0)), VerticalAlignment = (VerticalAlignment)1, TextAlign = (TextHorizontalAlignment)(flipOrientation ? 2 : 0), HorizontalAlignment = (HorizontalAlignment)3, GridColumn = ((!flipOrientation) ? 1 : 0), Visible = false }); if (flipOrientation) { base.ColumnsProportions.Add(Proportion.Fill); base.ColumnsProportions.Add(Proportion.Auto); ((CandideUiContainerMultipleItems)this).AddChild((CandideUiElement)(object)_label, false); ((CandideUiContainerMultipleItems)this).AddChild((CandideUiElement)(object)_builtinIcon, false); ((CandideUiContainerMultipleItems)this).AddChild((CandideUiElement)(object)_customIcon, false); } else { base.ColumnsProportions.Add(Proportion.Auto); base.ColumnsProportions.Add(Proportion.Fill); ((CandideUiContainerMultipleItems)this).AddChild((CandideUiElement)(object)_builtinIcon, false); ((CandideUiContainerMultipleItems)this).AddChild((CandideUiElement)(object)_customIcon, false); ((CandideUiContainerMultipleItems)this).AddChild((CandideUiElement)(object)_label, false); } } private void UpdateIconVisibility() { bool flag = !_hideIcon && _customIcon.HasTexture; ((CandideUiElement)_customIcon).Visible = flag; ((CandideUiElement)_builtinIcon).Visible = !_hideIcon && !flag; ((CandideUiElement)this).InvalidateMeasure(); } } internal static class ModConfigInfoBlock { internal static CandideUiElement Create(ModPluginConfig pluginConfig) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00da: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown ModSettingsRegistration registration = pluginConfig.Registration; if (registration == null) { return null; } string text = BuildMetaText(registration); bool flag = !string.IsNullOrWhiteSpace(registration.Description); bool hasValue = registration.NexusModsId.HasValue; bool flag2 = !string.IsNullOrWhiteSpace(registration.UpdateManifestUrl); if (string.IsNullOrWhiteSpace(text) && !flag && !hasValue && !flag2) { return null; } CandideVerticalStackPanel val = new CandideVerticalStackPanel { HorizontalAlignment = (HorizontalAlignment)3, Width = 300, MaxWidth = 300, Padding = new CandideThickness(7, 6), Margin = new CandideThickness(0, 0, 0, 8), Background = new Color(26, 18, 12, 190) }; CandideUiElement val2 = CreateHeader(registration, text, hasValue, flag2); if (val2 != null) { ((CandideUiContainerMultipleItems)val).AddChild(val2, false); } if (flag) { ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)new CandideTextLabel { Text = registration.Description, TextStyle = (CandideTextStyle)9, TextColor = Color.White, Wrap = true, MaxWidth = 286, Margin = new CandideThickness(0, (val2 != null) ? 4 : 0, 0, 0) }, false); } return (CandideUiElement)(object)val; } internal static string GetNexusModsUrl(int nexusModsId) { if (nexusModsId <= 0) { return null; } return "https://www.nexusmods.com/romestead/mods/" + nexusModsId; } private static CandideUiElement CreateHeader(ModSettingsRegistration registration, string meta, bool hasNexusModsLink, bool hasUpdateCheck) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown CandideUiElement val = CreateLinksPanel(registration, hasNexusModsLink, hasUpdateCheck); if (string.IsNullOrWhiteSpace(meta) && val == null) { return null; } CandideGrid val2 = new CandideGrid { HorizontalAlignment = (HorizontalAlignment)3, Width = 286, MaxWidth = 286, ColumnsProportions = { Proportion.Fill }, ColumnsProportions = { Proportion.Auto }, RowsProportions = { Proportion.Auto } }; if (!string.IsNullOrWhiteSpace(meta)) { ((CandideUiContainerMultipleItems)val2).AddChild((CandideUiElement)new CandideTextLabel { Text = meta, TextStyle = (CandideTextStyle)9, TextColor = new Color(226, 207, 177), Wrap = true, MaxWidth = ((val == null) ? 286 : 110), GridColumn = 0 }, false); } if (val != null) { ((CandideUiContainerMultipleItems)val2).AddChild(val, false); } return (CandideUiElement)(object)val2; } private static CandideUiElement CreateLinksPanel(ModSettingsRegistration registration, bool hasNexusModsLink, bool hasUpdateCheck) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown if (!hasNexusModsLink && !hasUpdateCheck) { return null; } CandideHorizontalStackPanel val = new CandideHorizontalStackPanel { GridRow = 0, GridColumn = 1, HorizontalAlignment = (HorizontalAlignment)2, MaxWidth = 190, Margin = new CandideThickness(6, 0, 0, 4) }; if (hasNexusModsLink) { ((CandideUiContainerMultipleItems)val).AddChild(CreateTextLink(LocalizationManager.Instance.GetText("button.nexusmods"), GetNexusModsUrl(registration.NexusModsId.Value)), false); } if (hasUpdateCheck) { ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)new ModUpdateStatusLabel(registration), false); } return (CandideUiElement)(object)val; } private static CandideUiElement CreateTextLink(string text, string url) { //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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown CandideTextLabel val = new CandideTextLabel { Text = text, TextStyle = (CandideTextStyle)9, TextColor = new Color(226, 207, 177), TextAlign = (TextHorizontalAlignment)2, HorizontalAlignment = (HorizontalAlignment)2, MaxWidth = 105, Margin = new CandideThickness(0, 0, 7, 0), OnClickedSoundEvent = "event:/interface/navigate" }; ((CandideUiElement)val).Clicked += delegate { UrlHelper.OpenUrl(url, false); }; return (CandideUiElement)val; } private static string BuildMetaText(ModSettingsRegistration registration) { if (!string.IsNullOrWhiteSpace(registration.Version) && !string.IsNullOrWhiteSpace(registration.Author)) { return registration.Version + " - " + registration.Author; } if (!string.IsNullOrWhiteSpace(registration.Version)) { return registration.Version; } if (!string.IsNullOrWhiteSpace(registration.Author)) { return registration.Author; } return null; } } internal sealed class ModConfigListItem : CandideListBase { private readonly ModConfigIconLabel _iconLabel; public string Icon { get { return _iconLabel.Icon; } set { _iconLabel.Icon = value; } } public string IconPath { get { return _iconLabel.IconPath; } set { _iconLabel.IconPath = value; } } public string Text { get { return _iconLabel.Text; } set { _iconLabel.Text = value; } } public Color TextColor { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _iconLabel.TextColor; } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) _iconLabel.TextColor = value; } } public ModConfigListItem(string iconId, string iconPath, IconFlag sizeFlag, int labelWidth) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) ((CandideUiElement)this).Padding = new CandideThickness(2, 2, 6, 3); ((CandideUiElement)this).HorizontalAlignment = (HorizontalAlignment)3; ((CandideToggleButton)this).LockWhenToggledOn = true; CandidePanel val = new CandidePanel { HorizontalAlignment = (HorizontalAlignment)3 }; _iconLabel = new ModConfigIconLabel(sizeFlag, flipOrientation: false, labelWidth, useTranslationCenteredText: true) { Icon = iconId, IconPath = iconPath }; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)_iconLabel, false); ((CandideUiContainerSingleItem)this).SetChild((CandideUiElement)(object)val); } } internal sealed class ModConfigPanel : CandideUiContainerSingleItem, ISettingsCategoryUi { private readonly ModConfigIconLabel _titleIconLabel; private readonly CandidePanelSingleChild _contentPanel; private readonly CandideHorizontalStackPanel _buttonPanel; private readonly YesButton _yesButton; private readonly NoIconLabelButton _noButton; private readonly List _editors; private ConfigFile _currentConfigFile; private ModPluginConfig _currentPluginConfig; private bool _currentConfigFileOriginalSaveOnConfigSet; private bool _hasCurrentConfigFileOriginalSaveOnConfigSet; public string CurrentPluginGuid => _currentPluginConfig?.Guid; public ModConfigPanel() { //IL_002a: 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) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00d4: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Expected O, but got Unknown ModConfigIconLabel obj = new ModConfigIconLabel((IconFlag)1) { Text = "Mod Settings", Icon = "cog" }; ((CandideUiElement)obj).Padding = new CandideThickness(6); ((CandideUiElement)obj).HorizontalAlignment = (HorizontalAlignment)3; ((CandideUiElement)obj).Margin = new CandideThickness(6, 0, 0, 12); _titleIconLabel = obj; _editors = new List(); ((CandideUiContainerSingleItem)this)..ctor(); ((CandideUiElement)this).HorizontalAlignment = (HorizontalAlignment)3; ((CandideUiElement)this).VerticalAlignment = (VerticalAlignment)3; CandideGrid val = new CandideGrid { RowsProportions = { Proportion.Auto }, RowsProportions = { Proportion.Fill }, RowsProportions = { Proportion.Auto }, RowsProportions = { Proportion.Auto }, ColumnsProportions = { Proportion.Fill }, VerticalAlignment = (VerticalAlignment)3, HorizontalAlignment = (HorizontalAlignment)3 }; _contentPanel = new CandidePanelSingleChild { Padding = new CandideThickness(8, 0, 0, 0), GridRow = 1, HorizontalAlignment = (HorizontalAlignment)3 }; _buttonPanel = new CandideHorizontalStackPanel { GridRow = 3, Padding = new CandideThickness(8, 8, 0, 0), HorizontalAlignment = (HorizontalAlignment)1, ControllerUseDefaultNavigation = true }; _yesButton = new YesButton(60) { StringId = StringId.op_Implicit("Ui_Apply"), OnClickAction = Save, OnClickedSoundEvent = "event:/interface/navigate", Enabled = false, Margin = new CandideThickness(3, 0, 3, 3), Padding = new CandideThickness(6, 4) }; _noButton = new NoIconLabelButton(60) { StringId = StringId.op_Implicit("Ui_Cancel"), OnClickAction = Reset, OnClickedSoundEvent = "event:/interface/navigate", Enabled = false, Margin = new CandideThickness(3, 0, 3, 3), Padding = new CandideThickness(6, 4) }; ((CandideUiContainerMultipleItems)_buttonPanel).AddChild((CandideUiElement)(object)_yesButton, false); ((CandideUiContainerMultipleItems)_buttonPanel).AddChild((CandideUiElement)(object)_noButton, false); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)_titleIconLabel, false); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)_contentPanel, false); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)new CandideHorizontalSeparator { HorizontalAlignment = (HorizontalAlignment)3, GridRow = 2, Padding = new CandideThickness(0, 1, 0, 0) }, false); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)_buttonPanel, false); ((CandideUiContainerSingleItem)this).SetChild((CandideUiElement)(object)val); } public void ShowPlugin(ModPluginConfig pluginConfig) { //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Expected O, but got Unknown //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Expected O, but got Unknown LocalizationManager.Instance.RefreshLanguage(forceNotify: false); ConfigFile configFile = pluginConfig.ConfigFile; if (_currentConfigFile != null && _currentConfigFile != configFile) { EndEditing(undo: true); } BeginEditing(configFile); _currentPluginConfig = pluginConfig; _editors.Clear(); _titleIconLabel.Text = pluginConfig.Name; _titleIconLabel.Icon = pluginConfig.Icon; _titleIconLabel.IconPath = pluginConfig.IconPath; ((CandideUiElement)_buttonPanel).Visible = true; ConfigEntryBase[] array = (from entry in configFile.Values where !ModSettingsMetadataResolver.IsEntryHidden(pluginConfig, entry) orderby ModSettingsMetadataResolver.GetSectionOrder(pluginConfig, entry.Definition.Section), ModSettingsMetadataResolver.GetEntryOrder(pluginConfig, entry), entry.Definition.Section, entry.Definition.Key select entry).ToArray(); CandideVerticalStackPanel val = new CandideVerticalStackPanel { HorizontalAlignment = (HorizontalAlignment)3, MaxWidth = 306 }; CandideUiElement val2 = ModConfigInfoBlock.Create(pluginConfig); if (val2 != null) { ((CandideUiContainerMultipleItems)val).AddChild(val2, false); } if (array.Length == 0) { ((CandideUiElement)_buttonPanel).Visible = false; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)new CandideTextLabel { Text = LocalizationManager.Instance.GetText("panel.no_public_entries"), Wrap = true, TextStyle = (CandideTextStyle)9, MaxWidth = 290, HorizontalAlignment = (HorizontalAlignment)3, Margin = new CandideThickness(0, 4, 0, 0) }, false); ((CandideUiContainerSingleItem)_contentPanel).SetChild((CandideUiElement)(object)CreateScroll((CandideUiElement)(object)val)); return; } string text = null; ConfigEntryBase[] array2 = array; foreach (ConfigEntryBase val3 in array2) { if (text != val3.Definition.Section) { if (text != null) { ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)new CandideHorizontalSeparator { HorizontalAlignment = (HorizontalAlignment)3, Margin = new CandideThickness(0, 3, 0, 6) }, false); } ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)new CandideTextLabel { Text = ModSettingsMetadataResolver.GetSectionDisplayName(pluginConfig, val3.Definition.Section), TextColor = new Color(255, 224, 161), Margin = new CandideThickness(0, 0, 0, 4) }, false); text = val3.Definition.Section; } ModConfigEntryEditor modConfigEntryEditor = new ModConfigEntryEditor(val3, UpdateButtons, ModSettingsMetadataResolver.GetEntryOptions(pluginConfig, val3)); _editors.Add(modConfigEntryEditor); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)modConfigEntryEditor, false); } ((CandideUiContainerSingleItem)_contentPanel).SetChild((CandideUiElement)(object)CreateScroll((CandideUiElement)(object)val)); UpdateButtons(); } public bool HasChanges() { return _editors.Any((ModConfigEntryEditor editor) => editor.HasChanges()); } public void Undo() { Reset(); } public void UserSave() { Save(); } public override void Update(GameTime gameTime) { ((CandideUiContainerSingleItem)this).Update(gameTime); if (_currentPluginConfig == null) { _titleIconLabel.Text = LocalizationManager.Instance.GetText("panel.title"); _titleIconLabel.Icon = "cog"; _titleIconLabel.IconPath = null; } UpdateButtons(); } private void Save() { ConfigFile currentConfigFile = _currentConfigFile; if (currentConfigFile != null) { currentConfigFile.Save(); } foreach (ModConfigEntryEditor editor in _editors) { editor.Commit(); } ((CandideUiElement)_yesButton).Enabled = false; ((CandideUiElement)_noButton).Enabled = false; } private void Reset() { UndoEditors(); if (_currentConfigFile != null && _currentPluginConfig != null) { ShowPlugin(_currentPluginConfig); } } private void UpdateButtons() { bool enabled = HasChanges(); ((CandideUiElement)_yesButton).Enabled = enabled; ((CandideUiElement)_noButton).Enabled = enabled; } public void EndEditing(bool undo) { if (undo) { UndoEditors(); } RestoreSaveOnConfigSet(); _editors.Clear(); _currentConfigFile = null; _currentPluginConfig = null; } private void BeginEditing(ConfigFile configFile) { if (_currentConfigFile != configFile) { _currentConfigFile = configFile; _currentConfigFileOriginalSaveOnConfigSet = configFile.SaveOnConfigSet; _hasCurrentConfigFileOriginalSaveOnConfigSet = true; configFile.SaveOnConfigSet = false; } } private void RestoreSaveOnConfigSet() { if (_currentConfigFile != null && _hasCurrentConfigFileOriginalSaveOnConfigSet) { _currentConfigFile.SaveOnConfigSet = _currentConfigFileOriginalSaveOnConfigSet; _hasCurrentConfigFileOriginalSaveOnConfigSet = false; } } private void UndoEditors() { foreach (ModConfigEntryEditor editor in _editors) { editor.Undo(); } } private static CandideVerticalScrollViewer CreateScroll(CandideUiElement child) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown CandideVerticalScrollViewer val = new CandideVerticalScrollViewer { Width = 316, Height = 340, ShowVerticalScrollBar = true }; ((CandideUiContainerSingleItem)val).SetChild(child); return val; } } internal sealed class ModConfigWindow : CandideExtendedCustomGraphicsWindow { private readonly CandideGrid _panel = new CandideGrid { HorizontalAlignment = (HorizontalAlignment)3, VerticalAlignment = (VerticalAlignment)3, Padding = new CandideThickness(5), DefaultColumnProportion = Proportion.Auto }; private readonly CandideListView _listView = new CandideListView { Width = 109, Height = 438, Padding = new CandideThickness(0, 6), GridColumn = 0, ShowVerticalScrollBar = false, ControllerAutoSelectHovered = false }; private readonly ModConfigPanel _settingsPanel; private readonly Action _onBack; private readonly CandideIconLabelButton _backButton; private readonly Dictionary _listItemsByGuid; private bool _isInitialized; private string _lastLocale; public ModConfigWindow(Action onBack) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_007a: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown ModConfigPanel modConfigPanel = new ModConfigPanel(); ((CandideUiElement)modConfigPanel).Width = 336; ((CandideUiElement)modConfigPanel).Height = 438; ((CandideUiElement)modConfigPanel).GridColumn = 1; ((CandideUiElement)modConfigPanel).Padding = new CandideThickness(10, 0, 0, 0); _settingsPanel = modConfigPanel; _listItemsByGuid = new Dictionary(StringComparer.OrdinalIgnoreCase); ((CandideExtendedCustomGraphicsWindow)this)..ctor(new CustomBackgroundArgs { SpriteSheet = Content.SpriteSheet("media/interface/new_ui_parts/ui_pause_menu") }); _onBack = onBack; SoundPlayer.PlayEventOneShot("event:/interface/open_window", 1f, 1f); base.ExitButton.OnClickAction = ((CandideWindow)this).Close; ((CandideWindow)this).Closing += delegate { _settingsPanel.EndEditing(undo: true); }; ((CandideWindow)this).Closed += delegate { SoundPlayer.PlayEventOneShot("event:/interface/close_window", 1f, 1f); _onBack?.Invoke(); }; _backButton = new CandideIconLabelButton("arrow:left", (IconFlag)1, (int?)69) { StringId = StringId.op_Implicit("Ui_Back"), OnClickAction = ((CandideWindow)this).Close, Margin = new CandideThickness(1, 0, 1, 2), HorizontalAlignment = (HorizontalAlignment)0, VerticalAlignment = (VerticalAlignment)2 }; RebuildPanelChildren(); ((CandideUiContainerSingleItem)this).SetChild((CandideUiElement)(object)_panel); BuildUi(); _lastLocale = LocalizationManager.Instance.CurrentLocale; } private void BuildUi() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) LocalizationManager.Instance.RefreshLanguage(forceNotify: false); ModSettingsRegistry.RequestRefresh(); _listView.ClearAllItems(); _listItemsByGuid.Clear(); CandideThickness padding = default(CandideThickness); ((CandideThickness)(ref padding))..ctor(2, 2, 6, 3); CandideThickness margin = default(CandideThickness); ((CandideThickness)(ref margin))..ctor(1, 0, 1, 2); _listView.AddNonItem((CandideUiElement)new TranslationCenteredTextLayout(109, 18) { Text = LocalizationManager.Instance.GetText("window.mod_list_title"), TextAlign = (TextHorizontalAlignment)1, HorizontalAlignment = (HorizontalAlignment)3, Margin = new CandideThickness(0, 0, 0, 4) }); ModPluginConfig[] array = ModPluginConfigSource.GetPluginConfigs().ToArray(); if (array.Length == 0) { _listView.AddNonItem((CandideUiElement)new CandideTextLabel { Text = LocalizationManager.Instance.GetText("window.no_configs"), TextAlign = (TextHorizontalAlignment)1, HorizontalAlignment = (HorizontalAlignment)3, Margin = new CandideThickness(0, 4, 0, 0) }); return; } ModPluginConfig[] array2 = array; foreach (ModPluginConfig config in array2) { ModConfigListItem obj = new ModConfigListItem(config.Icon, config.IconPath, (IconFlag)0, 92) { Text = config.Name }; ((CandideUiElement)obj).Padding = padding; ((CandideUiElement)obj).Margin = margin; ((CandideToggleButton)obj).OnToggledSoundEvent = "event:/interface/main menu/ui_mainmenu_click"; ((CandideToggleButton)obj).OnToggledOnAction = delegate { _settingsPanel.ShowPlugin(config); }; ModConfigListItem modConfigListItem = obj; _listItemsByGuid[config.Guid] = modConfigListItem; _listView.AddItem((CandideToggleButton)(object)modConfigListItem, false); } } private void RebuildPanelChildren() { _panel.ClearChildren(); ((CandideUiContainerMultipleItems)_panel).AddChild((CandideUiElement)(object)_listView, false); ((CandideUiContainerMultipleItems)_panel).AddChild((CandideUiElement)(object)_settingsPanel, false); ((CandideUiContainerMultipleItems)_panel).AddChild((CandideUiElement)(object)_backButton, false); } public override bool OnUiClosePressed() { if (((CandideUiContainerSingleItem)this).OnUiClosePressed()) { return true; } ((CandideWindow)this).Close(); return true; } public override void Update(GameTime gameTime) { ((CandideWindow)this).Update(gameTime); LocalizationManager.Instance.RefreshLanguage(forceNotify: false); if (_lastLocale != LocalizationManager.Instance.CurrentLocale) { _lastLocale = LocalizationManager.Instance.CurrentLocale; string currentPluginGuid = _settingsPanel.CurrentPluginGuid; RebuildPanelChildren(); _isInitialized = false; BuildUi(); if (!string.IsNullOrWhiteSpace(currentPluginGuid) && SelectPlugin(currentPluginGuid)) { _isInitialized = true; } } if (!_isInitialized && _listView.Items.Count > 0) { _listView.Items[0].IsToggled = true; _isInitialized = true; } } private bool SelectPlugin(string pluginGuid) { if (_listItemsByGuid.TryGetValue(pluginGuid, out var value)) { ((CandideToggleButton)value).IsToggled = true; return true; } ModPluginConfig modPluginConfig = ModPluginConfigSource.GetPluginConfigs().ToArray().FirstOrDefault((ModPluginConfig item) => item.Guid == pluginGuid); if (modPluginConfig == null) { return false; } _settingsPanel.ShowPlugin(modPluginConfig); return true; } } internal sealed class ModIconImage : CandideUiComponent { private IconFlag _iconFlags; private string _iconPath; public string IconPath { get { return _iconPath; } set { if (!(_iconPath == value)) { _iconPath = value; ((CandideUiElement)this).InvalidateMeasure(); } } } public IconFlag IconFlags { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return _iconFlags; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) _iconFlags = value; ((CandideUiElement)this).InvalidateMeasure(); } } public bool DrawSmooth { get; set; } = true; public bool HasTexture => ModIconLoader.TryLoad(_iconPath) != null; public ModIconImage(IconFlag iconFlags = (IconFlag)1) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) IconFlags = iconFlags; } public override void Update(GameTime gameTime) { } protected override void InternalDraw(UiRenderContext context) { //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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) Texture2D val = ModIconLoader.TryLoad(_iconPath); if (val != null) { Vector2 iconSizeForFlags = CandideIcon.GetIconSizeForFlags(_iconFlags); float num = MathHelper.Min(iconSizeForFlags.X / (float)val.Width, iconSizeForFlags.Y / (float)val.Height); Vector2 val2 = new Vector2((float)val.Width, (float)val.Height) * num * (float)CandideUiSystem.Scale; Vector2 val3 = iconSizeForFlags * (float)CandideUiSystem.Scale; Rectangle actualBounds = ((CandideUiElement)this).ActualBounds; Point location = ((Rectangle)(ref actualBounds)).Location; Vector2 val4 = ((Point)(ref location)).ToVector2() + (val3 - val2) / 2f; TextureFiltering textureFiltering = context.GetTextureFiltering(); if (DrawSmooth) { context.SetTextureFiltering((TextureFiltering)1); } context.DrawSprite(val, (Rectangle?)null, val4, new Vector2(num), 0f); context.SetTextureFiltering(textureFiltering); } } protected override Vector2 InternalMeasure(Vector2 availableSize) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) return CandideIcon.GetIconSizeForFlags(_iconFlags) * (float)CandideUiSystem.Scale; } } internal static class ModIconLoader { private static readonly Dictionary Cache = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet FailedPaths = new HashSet(StringComparer.OrdinalIgnoreCase); public static Texture2D TryLoad(string path) { string text = NormalizePath(path); if (string.IsNullOrWhiteSpace(text)) { return null; } if (Cache.TryGetValue(text, out var value)) { return value; } if (FailedPaths.Contains(text)) { return null; } try { if (Globals.GraphicsDevice == null) { return null; } if (!File.Exists(text)) { FailedPaths.Add(text); return null; } using (FileStream fileStream = File.OpenRead(text)) { value = Texture2D.FromStream(Globals.GraphicsDevice, (Stream)fileStream); } Cache[text] = value; return value; } catch { FailedPaths.Add(text); return null; } } private static string NormalizePath(string path) { if (string.IsNullOrWhiteSpace(path)) { return null; } try { return Path.GetFullPath(path.Trim().Trim('"')); } catch { return path.Trim().Trim('"'); } } } internal sealed class ModPluginConfig { public string Name { get; set; } public string Guid { get; set; } public ConfigFile ConfigFile { get; set; } public ModSettingsRegistration Registration { get; set; } public string Icon => Registration?.Icon ?? "cog"; public string IconPath => Registration?.IconPath; public int Order => Registration?.Order ?? 1000; } internal static class ModPluginConfigSource { public static IEnumerable GetPluginConfigs() { NetChainloader chainloader = NetChainloader.Instance; if (chainloader == null) { yield break; } HashSet registeredGuids = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (ModSettingsRegistration item in from item in ModSettingsRegistry.GetRegistrations() orderby item.Order, item.DisplayName select item) { registeredGuids.Add(item.PluginGuid); if (!item.HideWhenEmpty || item.ConfigFile.Values.Count != 0) { yield return new ModPluginConfig { Name = item.DisplayName, Guid = item.PluginGuid, ConfigFile = item.ConfigFile, Registration = item }; } } foreach (PluginInfo item2 in ((BaseChainloader)(object)chainloader).Plugins.Values.OrderBy((PluginInfo plugin) => plugin.Metadata.Name)) { if (!registeredGuids.Contains(item2.Metadata.GUID)) { object instance = item2.Instance; BasePlugin val = (BasePlugin)((instance is BasePlugin) ? instance : null); if (val != null && val.Config != null && val.Config.Values.Count != 0) { yield return new ModPluginConfig { Name = item2.Metadata.Name, Guid = item2.Metadata.GUID, ConfigFile = val.Config }; } } } } } internal static class ModSettingsIconRegistry { public const string IconId = "mod_settings_menu:settings"; private const string ResourceName = "ModSettingsMenu.Assets.mod_settings_icon.png"; private static bool _registered; public static void Register() { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if ((_registered && IconDataBase.IconDataMap.ContainsKey("mod_settings_menu:settings")) || Globals.GraphicsDevice == null || Content.DefaultNormalMap == null || Content.DefaultMetalMap == null) { return; } try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ModSettingsMenu.Assets.mod_settings_icon.png"); if (stream != null) { Texture2D val = Texture2D.FromStream(Globals.GraphicsDevice, stream); ((GraphicsResource)val).Name = "mod_settings_menu:settings"; Icon value = new Icon(new SpriteSheet(val, Content.DefaultNormalMap, Content.DefaultMetalMap, 24, 24, default(Vector2)), 0); Dictionary variations = new Dictionary { [(IconFlag)1] = value, [(IconFlag)9] = value, [(IconFlag)17] = value, [(IconFlag)33] = value, [(IconFlag)25] = value, [(IconFlag)36] = value }; IconDataBase.IconDataMap.Remove("mod_settings_menu:settings"); IconDataBase.AddIcons((IEnumerable)(object)new IconData[1] { new IconData { Id = "mod_settings_menu:settings", Variations = variations } }); _registered = true; } } catch (Exception ex) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(46, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to register mod settings toolbar icon: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex.Message); } logger.LogWarning(val2); } } } } internal sealed class ModUpdateStatusLabel : CandideTextLabel { private readonly ModSettingsRegistration _registration; private ModUpdateCheckStatus _lastStatus; private string _lastVersion; public ModUpdateStatusLabel(ModSettingsRegistration registration) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) _registration = registration; ((CandideTextLabel)this).TextStyle = (CandideTextStyle)9; base.TextColor = Color.LightGray; ((CandideTextLabel)this).TextAlign = (TextHorizontalAlignment)2; ((CandideUiElement)this).HorizontalAlignment = (HorizontalAlignment)2; ((CandideTextLabel)this).Wrap = false; ((CandideUiElement)this).MaxWidth = 78; UpdateText(force: true); } public override void Update(GameTime gameTime) { ((CandideTextLabel)this).Update(gameTime); UpdateText(force: false); } private void UpdateText(bool force) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) ModUpdateCheckResult orStart = ModUpdateChecker.GetOrStart(_registration); if (force || _lastStatus != orStart.Status || !(_lastVersion == orStart.LatestVersion)) { _lastStatus = orStart.Status; _lastVersion = orStart.LatestVersion; base.TextColor = GetStatusColor(orStart.Status); ((CandideUiElement)this).Visible = orStart.Status == ModUpdateCheckStatus.UpdateAvailable || orStart.Status == ModUpdateCheckStatus.UpToDate || orStart.Status == ModUpdateCheckStatus.Failed; ((CandideTextLabel)this).Text = GetStatusText(orStart); } } private static string GetStatusText(ModUpdateCheckResult result) { LocalizationManager instance = LocalizationManager.Instance; return result.Status switch { ModUpdateCheckStatus.UpToDate => instance.GetText("update.up_to_date"), ModUpdateCheckStatus.UpdateAvailable => instance.GetText("update.available", result.LatestVersion), ModUpdateCheckStatus.Failed => instance.GetText("update.failed"), _ => string.Empty, }; } private static Color GetStatusColor(ModUpdateCheckStatus status) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0058: Unknown result type (might be due to invalid IL or missing references) return (Color)(status switch { ModUpdateCheckStatus.UpToDate => new Color(104, 205, 112), ModUpdateCheckStatus.UpdateAvailable => new Color(255, 72, 72), ModUpdateCheckStatus.Failed => new Color(196, 170, 132), _ => new Color(226, 207, 177), }); } } } namespace ModSettingsMenu.Patches { [HarmonyPatch(typeof(CandideControlsSettings), "BuildUi")] internal static class ControlsSettingsBuildUiPatch { private static readonly FieldInfo SettingsPanelField = AccessTools.Field(typeof(CandideControlsSettings), "_settingsPanel"); private static readonly FieldInfo IsGamePadField = AccessTools.Field(typeof(CandideControlsSettings), "_isGamePad"); private static readonly FieldInfo SettingsField = AccessTools.Field(typeof(CandideControlsSettings), "_settings"); private static readonly ConditionalWeakTable States = new ConditionalWeakTable(); private static readonly ConditionalWeakTable StatesBySettings = new ConditionalWeakTable(); private static void Postfix(CandideControlsSettings __instance) { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown try { object? obj = SettingsPanelField?.GetValue(__instance); CandideVerticalStackPanel val = (CandideVerticalStackPanel)((obj is CandideVerticalStackPanel) ? obj : null); if (val != null) { ModControlsState value = States.GetValue(__instance, (CandideControlsSettings _) => new ModControlsState()); object? obj2 = SettingsField?.GetValue(__instance); ControlsUserSettings val2 = (ControlsUserSettings)((obj2 is ControlsUserSettings) ? obj2 : null); if (val2 != null) { StatesBySettings.Remove(val2); StatesBySettings.Add(val2, value); } value.Rebuild(FindKeybinds()); if (value.Editors.Count != 0) { object obj3 = IsGamePadField?.GetValue(__instance); AddModKeybinds(val, value, obj3 is bool && (bool)obj3); } } } catch (Exception ex) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(39, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Failed to build mod keybind controls: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(ex.Message); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("\n"); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(ex.StackTrace); } logger.LogError(val3); } } } internal static bool HasChanges(CandideControlsSettings instance) { if (States.TryGetValue(instance, out var value)) { return value.HasChanges(); } return false; } internal static void Save(CandideControlsSettings instance) { if (States.TryGetValue(instance, out var value)) { value.Save(); } } internal static void Undo(CandideControlsSettings instance) { if (States.TryGetValue(instance, out var value)) { value.Undo(); } } internal static void ResetToDefaults(ControlsUserSettings settings) { if (StatesBySettings.TryGetValue(settings, out var value)) { value.ResetToDefaults(); } } private static List FindKeybinds() { ModSettingsRegistry.RequestRefresh(); return (from config in ModPluginConfigSource.GetPluginConfigs() orderby config.Order, config.Name select config).SelectMany(GetKeybinds).ToList(); } private static IEnumerable GetKeybinds(ModPluginConfig pluginConfig) { return from item in pluginConfig.ConfigFile.Values.Select((ConfigEntryBase entry) => new { Entry = entry, Options = ModSettingsMetadataResolver.GetEntryOptions(pluginConfig, entry) }).Where(item => { ModSettingsEntryOptions options = item.Options; return options != null && options.Keybind && ModKeybindValue.IsSupportedType(item.Entry.SettingType) && !ModSettingsMetadataResolver.IsEntryHiddenByMetadata(pluginConfig, item.Entry); }) orderby ModSettingsMetadataResolver.GetSectionOrder(pluginConfig, item.Entry.Definition.Section), ModSettingsMetadataResolver.GetEntryOrder(pluginConfig, item.Entry), item.Entry.Definition.Section, item.Entry.Definition.Key select new ModKeybindDescriptor(pluginConfig, item.Entry, item.Options); } private static void AddModKeybinds(CandideVerticalStackPanel settingsPanel, ModControlsState state, bool isGamePad) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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_0022: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown ((CandideUiContainerMultipleItems)settingsPanel).AddChild((CandideUiElement)new CandideHorizontalSeparator { HorizontalAlignment = (HorizontalAlignment)3, Margin = new CandideThickness(0, 8, 0, 3) }, false); string a = null; foreach (ModKeybindEditor editor in state.Editors) { if (!string.Equals(a, editor.PluginGuid, StringComparison.OrdinalIgnoreCase)) { ((CandideUiContainerMultipleItems)settingsPanel).AddChild((CandideUiElement)new CandideTextLabel { Text = editor.PluginName, TextColor = new Color(255, 224, 161), TextStyle = (CandideTextStyle)2, HorizontalAlignment = (HorizontalAlignment)0, TextAlign = (TextHorizontalAlignment)0, Wrap = true, MaxWidth = 340, Height = 16, TransformScale = new Vector2(0.92f), Margin = new CandideThickness(0, 1, 0, 0) }, false); a = editor.PluginGuid; } ((CandideUiContainerMultipleItems)settingsPanel).AddChild(CreateRow(editor, isGamePad), false); } } private static CandideUiElement CreateRow(ModKeybindEditor editor, bool isGamePad) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown CandideHorizontalStackPanel val = new CandideHorizontalStackPanel { Margin = new CandideThickness(0, 3), HorizontalAlignment = (HorizontalAlignment)0 }; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)new TranslationCenteredTextLayout { Text = editor.DisplayName, VerticalAlignment = (VerticalAlignment)1, TextAlign = (TextHorizontalAlignment)2, TextStyle = (CandideTextStyle)0, Width = 120, Margin = new CandideThickness(0, 0, 6, 0) }, false); ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)editor.CreateInputGrid(isGamePad), false); return (CandideUiElement)val; } } [HarmonyPatch(typeof(UserSettingsCategory), "ResetToDefault")] internal static class ControlsSettingsResetToDefaultPatch { private static void Postfix(ControlsUserSettings __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown try { ControlsSettingsBuildUiPatch.ResetToDefaults(__instance); } catch (Exception ex) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(39, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to reset mod keybind defaults: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\n"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.StackTrace); } logger.LogError(val); } } } } [HarmonyPatch(typeof(CandideControlsSettings), "HasChanges")] internal static class ControlsSettingsHasChangesPatch { private static void Postfix(CandideControlsSettings __instance, ref bool __result) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown try { __result = __result || ControlsSettingsBuildUiPatch.HasChanges(__instance); } catch (Exception ex) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(38, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to check mod keybind changes: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\n"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.StackTrace); } logger.LogError(val); } } } } [HarmonyPatch(typeof(CandideControlsSettings), "UserSave")] internal static class ControlsSettingsUserSavePatch { private static readonly FieldInfo SettingsField = AccessTools.Field(typeof(CandideControlsSettings), "_settings"); private static void Postfix(CandideControlsSettings __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown try { object? obj = SettingsField?.GetValue(__instance); ControlsUserSettings val = (ControlsUserSettings)((obj is ControlsUserSettings) ? obj : null); if (val == null || !((UserSettingsCategory)(object)val).HasChanges) { ControlsSettingsBuildUiPatch.Save(__instance); } } catch (Exception ex) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(30, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to save mod keybinds: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex.Message); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\n"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex.StackTrace); } logger.LogError(val2); } } } } [HarmonyPatch(typeof(CandideControlsSettings), "Undo")] internal static class ControlsSettingsUndoPatch { private static void Postfix(CandideControlsSettings __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown try { ControlsSettingsBuildUiPatch.Undo(__instance); } catch (Exception ex) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(37, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to undo mod keybind changes: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\n"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.StackTrace); } logger.LogError(val); } } } } internal sealed class ModControlsState { private readonly List _editors = new List(); private bool _resetToDefaults; public IReadOnlyList Editors => _editors; public void Rebuild(IReadOnlyList descriptors) { Dictionary dictionary = _editors.ToDictionary((ModKeybindEditor editor) => editor.Entry); _editors.Clear(); bool resetToDefaults = _resetToDefaults; _resetToDefaults = false; foreach (ModKeybindDescriptor descriptor in descriptors) { if (!dictionary.TryGetValue(descriptor.Entry, out var value)) { value = new ModKeybindEditor(descriptor); } else { value.UpdateDescriptor(descriptor); if (resetToDefaults) { value.ResetToDefault(); } else if (!value.HasChanges) { value.SyncFromEntry(); } } if (resetToDefaults) { value.ResetToDefault(); } _editors.Add(value); } } public bool HasChanges() { return _editors.Any((ModKeybindEditor editor) => editor.HasChanges); } public void Undo() { _resetToDefaults = false; foreach (ModKeybindEditor editor in _editors) { editor.Undo(); } } public void ResetToDefaults() { _resetToDefaults = true; foreach (ModKeybindEditor editor in _editors) { editor.ResetToDefault(); } } public void Save() { ModKeybindEditor[] array = _editors.Where((ModKeybindEditor editor) => editor.HasChanges).ToArray(); if (array.Length == 0) { return; } ConfigFile[] array2 = array.Select((ModKeybindEditor editor) => editor.Entry.ConfigFile).Distinct().ToArray(); Dictionary dictionary = array2.ToDictionary((ConfigFile configFile) => configFile, (ConfigFile configFile) => configFile.SaveOnConfigSet); try { ConfigFile[] array3 = array2; for (int num = 0; num < array3.Length; num++) { array3[num].SaveOnConfigSet = false; } ModKeybindEditor[] array4 = array; foreach (ModKeybindEditor modKeybindEditor in array4) { modKeybindEditor.Entry.BoxedValue = modKeybindEditor.CreateBoxedValue(); } array3 = array2; for (int num = 0; num < array3.Length; num++) { array3[num].Save(); } array4 = array; for (int num = 0; num < array4.Length; num++) { array4[num].Commit(); } _resetToDefaults = false; } finally { foreach (KeyValuePair item in dictionary) { item.Key.SaveOnConfigSet = item.Value; } } } } internal sealed class ModKeybindDescriptor { public string PluginGuid { get; } public string PluginName { get; } public ConfigEntryBase Entry { get; } public string DisplayName { get; } public ModKeybindDescriptor(ModPluginConfig pluginConfig, ConfigEntryBase entry, ModSettingsEntryOptions options) { PluginGuid = pluginConfig.Guid; PluginName = pluginConfig.Name; Entry = entry; DisplayName = (string.IsNullOrWhiteSpace(options?.DisplayName) ? entry.Definition.Key : options.DisplayName); } } internal sealed class ModKeybindEditor { private readonly CandideBindingInput[] _inputs = (CandideBindingInput[])(object)new CandideBindingInput[3]; private ModKeybindDescriptor _descriptor; private ModKeybindValue _original; private bool _isGamePad; public ConfigEntryBase Entry => _descriptor.Entry; public ModKeybindValue Current { get; private set; } public bool HasChanges => !Current.Equals(_original); public string PluginGuid => _descriptor.PluginGuid; public string PluginName => _descriptor.PluginName; public string DisplayName => _descriptor.DisplayName; private bool IsSingleKey => Entry.SettingType == typeof(Keys); public ModKeybindEditor(ModKeybindDescriptor descriptor) { _descriptor = descriptor; SyncFromEntry(); } public void UpdateDescriptor(ModKeybindDescriptor descriptor) { _descriptor = descriptor; } public void SyncFromEntry() { _original = ModKeybindValue.FromEntry(Entry); Current = _original.Clone(); UpdateInputTexts(); } public void Commit() { _original = Current.Clone(); UpdateInputTexts(); } public void Undo() { Current = _original.Clone(); UpdateInputTexts(); } public void ResetToDefault() { Current = ModKeybindValue.FromDefault(Entry); UpdateInputTexts(); } public object CreateBoxedValue() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!IsSingleKey) { return Current.ToConfigString(); } return Current.ToSingleKey(); } public CandideGrid CreateInputGrid(bool isGamePad) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown Array.Clear(_inputs, 0, _inputs.Length); _isGamePad = isGamePad; CandideGrid val = new CandideGrid { Width = 220 }; for (int i = 0; i < 3; i++) { int index = i; CandideBindingInput val2 = new CandideBindingInput(isGamePad, DisplayName, index, (Func)((MouseButtons? mouseButton) => OnMouseRegistered(mouseButton, index)), (Func)((Keys key) => OnKeyboardRegistered(key, index)), (Func)((Buttons _) => false)) { Enabled = CanEditSlot(isGamePad, index) }; _inputs[index] = val2; ((CandideUiContainerMultipleItems)val).AddChild((CandideUiElement)(object)val2, false); } UpdateInputTexts(); return val; } private bool CanEditSlot(bool isGamePad, int index) { if (isGamePad) { return false; } if (IsSingleKey) { return index == 0; } return true; } private bool OnMouseRegistered(MouseButtons? mouseButton, int index) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (IsSingleKey || !mouseButton.HasValue) { return false; } Current.SetMouse(index, mouseButton.Value); UpdateInputTexts(); return true; } private bool OnKeyboardRegistered(Keys key, int index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((int)key == 8) { return true; } if ((int)key == 46 || (int)key == 0) { Current.ClearMouseKeyboardSlot(index); } else { Current.SetKey(index, key, IsSingleKey); } UpdateInputTexts(); return true; } private void UpdateInputTexts() { for (int i = 0; i < _inputs.Length; i++) { if (_inputs[i] != null) { _inputs[i].Text = (_isGamePad ? Current.FormatButtonSlot(i) : Current.FormatMouseKeyboardSlot(i)); } } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class MainMenuWindowPatch { private static readonly FieldInfo SettingsButtonField = AccessTools.Field(typeof(MainMenuWindow), "_btnSettings"); private static readonly ConditionalWeakTable ModConfigButtons = new ConditionalWeakTable(); private static void Postfix(MainMenuWindow __instance) { try { CandideUiElement child = ((CandideUiContainerSingleItem)__instance).Child; CandideVerticalStackPanel val = (CandideVerticalStackPanel)(object)((child is CandideVerticalStackPanel) ? child : null); if (val == null) { return; } LocalizationManager.Instance.RefreshLanguage(forceNotify: false); if (ModConfigButtons.TryGetValue(__instance, out var _)) { return; } object? obj = SettingsButtonField?.GetValue(__instance); CandideUiElement val2 = (CandideUiElement)((obj is CandideUiElement) ? obj : null); if (val2 == null) { return; } CandideButtonBase obj2 = MainMenuWindow.CreateMenuButton(LocalizationManager.Instance.GetText("menu.button"), (string)null, false, (Action)null, true); CandideLabelButton val3 = (CandideLabelButton)(object)((obj2 is CandideLabelButton) ? obj2 : null); if (val3 == null) { return; } ((CandideButtonBase)val3).OnClickAction = (Action)Delegate.Combine(((CandideButtonBase)val3).OnClickAction, (Action)delegate { CandideDesktop desktop = ((CandideUiElement)__instance).Desktop; if (desktop != null) { desktop.CloseAll(); ModConfigWindow modConfigWindow = new ModConfigWindow(delegate { MainMenuUi.ShowUi(desktop); }); ((CandideUiElement)modConfigWindow).HorizontalAlignment = (HorizontalAlignment)1; ((CandideUiElement)modConfigWindow).VerticalAlignment = (VerticalAlignment)1; ((CandideUiElement)modConfigWindow).DragDirection = (DragDirection)0; ((CandideWindow)modConfigWindow).Show(desktop, (int?)null, (int?)null); } }); if (InsertAfterSettings(val, val2, (CandideUiElement)(object)val3)) { ModConfigButtons.Add(__instance, val3); } } catch { } } private static bool InsertAfterSettings(CandideVerticalStackPanel stack, CandideUiElement settingsButton, CandideUiElement modConfigButton) { List childrenCopy = ((CandideUiContainerMultipleItems)stack).ChildrenCopy; int num = FindSettingsButtonIndex(childrenCopy, settingsButton); if (num < 0) { return false; } ((CandideGrid)stack).ClearChildren(); for (int i = 0; i < childrenCopy.Count; i++) { ((CandideUiContainerMultipleItems)stack).AddChild(childrenCopy[i], false); if (i == num) { ((CandideUiContainerMultipleItems)stack).AddChild(modConfigButton, false); } } return true; } private static int FindSettingsButtonIndex(IReadOnlyList children, CandideUiElement settingsButton) { for (int i = 0; i < children.Count; i++) { if (children[i] == settingsButton) { return i; } } return -1; } internal static bool TryGetModConfigButton(MainMenuWindow window, out CandideLabelButton button) { return ModConfigButtons.TryGetValue(window, out button); } } [HarmonyPatch(typeof(CandideWindow), "Update")] internal static class MainMenuWindowUpdatePatch { private static void Postfix(CandideWindow __instance) { try { MainMenuWindow val = (MainMenuWindow)(object)((__instance is MainMenuWindow) ? __instance : null); if (val != null) { LocalizationManager.Instance.RefreshLanguage(forceNotify: false); string text = LocalizationManager.Instance.GetText("menu.button"); if (MainMenuWindowPatch.TryGetModConfigButton(val, out var button) && button.Text != text) { button.Text = text; } } } catch { } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class TopPanelWindowPatch { private static readonly ConditionalWeakTable Buttons = new ConditionalWeakTable(); private static void Postfix(TopPanelWindow __instance) { TopPanelButtonInjector.Inject(__instance, Buttons); } internal static bool TryGetButton(TopPanelWindow window, out CandideIconButton button) { return Buttons.TryGetValue(window, out button); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class TopPanelWindowConsolePatch { private static readonly ConditionalWeakTable Buttons = new ConditionalWeakTable(); private static void Postfix(TopPanelWindowConsole __instance) { TopPanelButtonInjector.Inject(__instance, Buttons); } internal static bool TryGetButton(TopPanelWindowConsole window, out CandideIconButton button) { return Buttons.TryGetValue(window, out button); } } [HarmonyPatch(typeof(CandideWindow), "Update")] internal static class TopPanelWindowUpdatePatch { private static void Postfix(CandideWindow __instance) { try { LocalizationManager.Instance.RefreshLanguage(forceNotify: false); ModSettingsIconRegistry.Register(); string text = LocalizationManager.Instance.GetText("menu.button"); TopPanelWindow val = (TopPanelWindow)(object)((__instance is TopPanelWindow) ? __instance : null); if (val != null && TopPanelWindowPatch.TryGetButton(val, out var button)) { TopPanelButtonInjector.UpdateButton(button, text); return; } TopPanelWindowConsole val2 = (TopPanelWindowConsole)(object)((__instance is TopPanelWindowConsole) ? __instance : null); if (val2 != null && TopPanelWindowConsolePatch.TryGetButton(val2, out button)) { TopPanelButtonInjector.UpdateButton(button, text); } } catch { } } } internal static class TopPanelButtonInjector { public static void Inject(TWindow window, ConditionalWeakTable buttons) where TWindow : CandideWindow { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown try { ModSettingsIconRegistry.Register(); if (!buttons.TryGetValue(window, out var _)) { CandideUiElement child = ((CandideUiContainerSingleItem)(object)window).Child; CandideHorizontalStackPanel val = (CandideHorizontalStackPanel)(object)((child is CandideHorizontalStackPanel) ? child : null); if (val != null) { LocalizationManager.Instance.RefreshLanguage(forceNotify: false); CandideIconButton val2 = CreateButton((CandideWindow)(object)window); AddBeforeLastSeparator(val, (CandideUiElement)(object)val2); buttons.Add(window, val2); } } } catch (Exception ex) { ManualLogSource logger = ModSettingsMenu.Logger; if (logger != null) { bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(48, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Failed to inject mod settings top panel button: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(ex.Message); } logger.LogWarning(val3); } } } public static void UpdateButton(CandideIconButton button, string text) { if (button.Icon != "mod_settings_menu:settings") { button.Icon = "mod_settings_menu:settings"; } button.GetTooltipContent = () => (IEnumerable)(object)new CandideTextLabel[1] { new CandideTextLabel { Text = text } }; } private static CandideIconButton CreateButton(CandideWindow owner) { //IL_0013: 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_001f: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown CandideIconButton val = new CandideIconButton("mod_settings_menu:settings", (IconFlag)1) { HorizontalAlignment = (HorizontalAlignment)1, Padding = new CandideThickness(2, 2, 3, 3), OnClickedSoundEvent = "event:/interface/navigate" }; UpdateButton(val, LocalizationManager.Instance.GetText("menu.button")); ((CandideButtonBase)val).OnClickAction = delegate { CandideDesktop desktop = ((CandideUiElement)owner).Desktop; if (desktop != null) { CandideWindow topBarWindow = PlayerUi.TopBarWindow; PlayerUi.CloseAllNonOverlay(desktop, true); PlayerUi.IsShowingPlayerUi = true; ModConfigWindow modConfigWindow = new ModConfigWindow(delegate { PlayerUi.IsShowingPlayerUi = false; PlayerUi.EnsureTopBarVisible(desktop); }); ((CandideUiElement)modConfigWindow).HorizontalAlignment = (HorizontalAlignment)1; ((CandideUiElement)modConfigWindow).VerticalAlignment = (VerticalAlignment)1; ((CandideUiElement)modConfigWindow).DragDirection = (DragDirection)0; ((CandideWindow)modConfigWindow).Show(desktop, (int?)null, (int?)null); if (topBarWindow != null) { ((CandideUiElement)topBarWindow).RequestBringToFront = true; } } }; return val; } private static void AddBeforeLastSeparator(CandideHorizontalStackPanel stack, CandideUiElement button) { List childrenCopy = ((CandideUiContainerMultipleItems)stack).ChildrenCopy; int num = childrenCopy.Count; for (int num2 = childrenCopy.Count - 1; num2 >= 0; num2--) { if (childrenCopy[num2] is CandideVerticalSeparator) { num = num2; break; } } ((CandideGrid)stack).ClearChildren(); for (int i = 0; i < childrenCopy.Count; i++) { if (i == num) { ((CandideUiContainerMultipleItems)stack).AddChild(button, false); } ((CandideUiContainerMultipleItems)stack).AddChild(childrenCopy[i], false); } if (num == childrenCopy.Count) { ((CandideUiContainerMultipleItems)stack).AddChild(button, false); } } } } namespace ModSettingsMenu.Metadata { internal static class ModSettingsMetadataResolver { internal static bool IsEntryHidden(ModPluginConfig pluginConfig, ConfigEntryBase entry) { return IsEntryHiddenByMetadata(pluginConfig, entry); } internal static bool IsEntryHiddenByMetadata(ModPluginConfig pluginConfig, ConfigEntryBase entry) { ModSettingsEntryOptions entryOptions = GetEntryOptions(pluginConfig, entry); if (entryOptions == null || !entryOptions.Hidden) { return GetSectionOptions(pluginConfig, entry.Definition.Section)?.Hidden ?? false; } return true; } internal static string GetSectionDisplayName(ModPluginConfig pluginConfig, string section) { ModSettingsSectionOptions sectionOptions = GetSectionOptions(pluginConfig, section); if (!string.IsNullOrWhiteSpace(sectionOptions?.DisplayName)) { return sectionOptions.DisplayName; } return section; } internal static int GetSectionOrder(ModPluginConfig pluginConfig, string section) { ModSettingsRegistration modSettingsRegistration = pluginConfig?.Registration; ModSettingsSectionOptions sectionOptions = ModSettingsTagReader.GetSectionOptions(pluginConfig?.ConfigFile, section); if (modSettingsRegistration != null && modSettingsRegistration.Sections.TryGetValue(section, out var value)) { if (value.HasOrder) { return value.Order; } if (sectionOptions == null || !sectionOptions.HasOrder) { return value.Order; } return sectionOptions.Order; } if (sectionOptions == null || !sectionOptions.HasOrder) { return 1000; } return sectionOptions.Order; } internal static int GetEntryOrder(ModPluginConfig pluginConfig, ConfigEntryBase entry) { ModSettingsEntryOptions entryOptions = ModSettingsTagReader.GetEntryOptions(entry); ModSettingsRegistration modSettingsRegistration = pluginConfig?.Registration; if (modSettingsRegistration != null && modSettingsRegistration.Entries.TryGetValue(entry.Definition, out var value)) { if (value.HasOrder) { return value.Order; } if (entryOptions == null || !entryOptions.HasOrder) { return value.Order; } return entryOptions.Order; } if (entryOptions == null || !entryOptions.HasOrder) { return 1000; } return entryOptions.Order; } internal static ModSettingsEntryOptions GetEntryOptions(ModPluginConfig pluginConfig, ConfigEntryBase entry) { ModSettingsEntryOptions entryOptions = ModSettingsTagReader.GetEntryOptions(entry); ModSettingsRegistration modSettingsRegistration = pluginConfig?.Registration; if (modSettingsRegistration == null || !modSettingsRegistration.Entries.TryGetValue(entry.Definition, out var value)) { return entryOptions; } if (entryOptions == null) { return value; } ModSettingsEntryOptions modSettingsEntryOptions = entryOptions.Clone(); modSettingsEntryOptions.Apply(value); return modSettingsEntryOptions; } private static ModSettingsSectionOptions GetSectionOptions(ModPluginConfig pluginConfig, string section) { ModSettingsRegistration modSettingsRegistration = pluginConfig?.Registration; if (modSettingsRegistration != null && modSettingsRegistration.Sections.TryGetValue(section, out var value)) { return value; } return ModSettingsTagReader.GetSectionOptions(pluginConfig?.ConfigFile, section); } } internal static class ModSettingsTagReader { internal static ModSettingsSectionOptions GetSectionOptions(ConfigFile configFile, string section) { if (configFile == null) { return null; } ModSettingsSectionOptions modSettingsSectionOptions = null; foreach (ConfigEntryBase value in configFile.Values) { if (value.Definition.Section != section) { continue; } ConfigDescription description = value.Description; object[] array = ((description != null) ? description.Tags : null) ?? Array.Empty(); foreach (object obj in array) { ModSettingsSectionTag sectionTag; if (obj is ModSettingsSectionTag modSettingsSectionTag) { if (!(modSettingsSectionTag.Section != section)) { if (modSettingsSectionOptions == null) { modSettingsSectionOptions = new ModSettingsSectionOptions(section); } modSettingsSectionOptions.Apply(modSettingsSectionTag); } } else if (TryReadSectionTag(obj, section, out sectionTag)) { if (modSettingsSectionOptions == null) { modSettingsSectionOptions = new ModSettingsSectionOptions(section); } modSettingsSectionOptions.Apply(sectionTag); } } } return modSettingsSectionOptions; } internal static ModSettingsEntryOptions GetEntryOptions(ConfigEntryBase entry) { ModSettingsEntryOptions modSettingsEntryOptions = null; ConfigDescription description = entry.Description; object[] array = ((description != null) ? description.Tags : null) ?? Array.Empty(); foreach (object obj in array) { ModSettingsEntryTag entryTag = obj as ModSettingsEntryTag; if (entryTag != null || TryReadEntryTag(obj, out entryTag)) { if (modSettingsEntryOptions == null) { modSettingsEntryOptions = new ModSettingsEntryOptions(entry.Definition); } modSettingsEntryOptions.Apply(entryTag); } } return modSettingsEntryOptions; } private static bool TryReadSectionTag(object tag, string section, out ModSettingsSectionTag sectionTag) { sectionTag = null; if (tag == null) { return false; } string text = ReadStringProperty(tag, "Section"); if (text != section) { return false; } if (!(TryReadStringProperty(tag, "DisplayName", out var result) | TryReadIntProperty(tag, "Order", out var result2) | TryReadBoolProperty(tag, "Hidden", out var result3))) { return false; } sectionTag = new ModSettingsSectionTag { Section = text, DisplayName = result, Order = result2, Hidden = result3 }; return true; } private static bool TryReadEntryTag(object tag, out ModSettingsEntryTag entryTag) { entryTag = null; if (tag == null) { return false; } if (!(TryReadStringProperty(tag, "DisplayName", out var result) | TryReadStringProperty(tag, "Description", out var result2) | TryReadIntProperty(tag, "Order", out var result3) | TryReadDoubleProperty(tag, "SliderStep", out var result4) | TryReadBoolProperty(tag, "Keybind", out var result5) | TryReadBoolProperty(tag, "IsKeybind", out var result6) | TryReadBoolProperty(tag, "Hidden", out var result7))) { return false; } entryTag = new ModSettingsEntryTag { DisplayName = result, Description = result2, Order = result3, SliderStep = result4, Keybind = (result5 ?? result6), Hidden = result7 }; return true; } private static bool TryReadStringProperty(object value, string propertyName, out string result) { result = ReadStringProperty(value, propertyName); return !string.IsNullOrWhiteSpace(result); } private static string ReadStringProperty(object value, string propertyName) { return ReadProperty(value, propertyName) as string; } private static bool TryReadIntProperty(object value, string propertyName, out int? result) { result = null; object obj = ReadProperty(value, propertyName); if (obj == null) { return false; } try { result = Convert.ToInt32(obj, CultureInfo.InvariantCulture); return true; } catch { return false; } } private static bool TryReadDoubleProperty(object value, string propertyName, out double? result) { result = null; object obj = ReadProperty(value, propertyName); if (obj == null) { return false; } try { result = Convert.ToDouble(obj, CultureInfo.InvariantCulture); return true; } catch { return false; } } private static bool TryReadBoolProperty(object value, string propertyName, out bool? result) { result = null; object obj = ReadProperty(value, propertyName); if (obj == null) { return false; } try { result = Convert.ToBoolean(obj, CultureInfo.InvariantCulture); return true; } catch { return false; } } private static object ReadProperty(object value, string propertyName) { return value.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public)?.GetValue(value); } } } namespace ModSettingsMenu.Localization { internal static class LocalizationHelper { public static readonly string[] SupportedLanguages = new string[4] { "zh_CN", "zh_TW", "en", "ja_JP" }; public static Dictionary GetDefaultTranslations(string language) { Dictionary dictionary = new Dictionary(); switch (language) { case "zh_CN": dictionary.Add("menu.button", "模组配置"); dictionary.Add("window.mod_list_title", "模组"); dictionary.Add("window.no_configs", "无配置"); dictionary.Add("panel.title", "模组配置"); dictionary.Add("panel.no_public_entries", "这个模组没有公开配置项。"); dictionary.Add("button.nexusmods", "打开 Nexus 页面"); dictionary.Add("update.up_to_date", "已最新"); dictionary.Add("update.available", "更新:{0}"); dictionary.Add("update.failed", "检测失败"); dictionary.Add("entry.bool_label", "启用"); dictionary.Add("entry.reset", "重置"); dictionary.Add("entry.keybind_configure_hint", "这是一个模组快捷键。请在游戏设置 > 控制 页面中修改。"); dictionary.Add("entry.keybind_current", "当前绑定:{0}"); break; case "zh_TW": dictionary.Add("menu.button", "模組配置"); dictionary.Add("window.mod_list_title", "模組"); dictionary.Add("window.no_configs", "無配置"); dictionary.Add("panel.title", "模組配置"); dictionary.Add("panel.no_public_entries", "這個模組沒有公開配置項。"); dictionary.Add("button.nexusmods", "開啟 Nexus 頁面"); dictionary.Add("update.up_to_date", "已最新"); dictionary.Add("update.available", "更新:{0}"); dictionary.Add("update.failed", "檢查失敗"); dictionary.Add("entry.bool_label", "啟用"); dictionary.Add("entry.reset", "重設"); dictionary.Add("entry.keybind_configure_hint", "這是一個模組快捷鍵。請在遊戲設定 > 控制 頁面中修改。"); dictionary.Add("entry.keybind_current", "目前綁定:{0}"); break; case "ja_JP": dictionary.Add("menu.button", "MOD設定"); dictionary.Add("window.mod_list_title", "MOD"); dictionary.Add("window.no_configs", "設定なし"); dictionary.Add("panel.title", "MOD設定"); dictionary.Add("panel.no_public_entries", "このMODには公開設定項目がありません。"); dictionary.Add("button.nexusmods", "Nexusを開く"); dictionary.Add("update.up_to_date", "最新"); dictionary.Add("update.available", "更新:{0}"); dictionary.Add("update.failed", "確認失敗"); dictionary.Add("entry.bool_label", "有効"); dictionary.Add("entry.reset", "リセット"); dictionary.Add("entry.keybind_configure_hint", "これはMODのキーバインドです。変更はゲームの設定 > 操作で行ってください。"); dictionary.Add("entry.keybind_current", "現在の割り当て: {0}"); break; case "en": dictionary.Add("menu.button", "Mod Settings"); dictionary.Add("window.mod_list_title", "Mods"); dictionary.Add("window.no_configs", "No configs"); dictionary.Add("panel.title", "Mod Settings"); dictionary.Add("panel.no_public_entries", "This mod has no public config entries."); dictionary.Add("button.nexusmods", "Open Nexus"); dictionary.Add("update.up_to_date", "Latest"); dictionary.Add("update.available", "Update: {0}"); dictionary.Add("update.failed", "Update failed"); dictionary.Add("entry.bool_label", "Enabled"); dictionary.Add("entry.reset", "Reset"); dictionary.Add("entry.keybind_configure_hint", "This is a mod keybind. Configure it in the game's Settings > Controls page."); dictionary.Add("entry.keybind_current", "Current binding: {0}"); break; } return dictionary; } } internal sealed class LocalizationManager { private static LocalizationManager _instance; private readonly Dictionary> _localizations = new Dictionary>(StringComparer.OrdinalIgnoreCase); private string _currentLocale = "en"; public static LocalizationManager Instance => _instance ?? (_instance = new LocalizationManager()); public string CurrentLocale => _currentLocale; public event Action LanguageChanged; private LocalizationManager() { Initialize(); } public void Initialize() { _localizations.Clear(); string[] supportedLanguages = LocalizationHelper.SupportedLanguages; foreach (string text in supportedLanguages) { Dictionary defaultTranslations = LocalizationHelper.GetDefaultTranslations(text); if (defaultTranslations.Count > 0) { _localizations[text] = defaultTranslations; } } RefreshLanguage(forceNotify: false); } public void RefreshLanguage(bool forceNotify = true) { string text = NormalizeLocale(Globals.LanguageCode); if (!_localizations.ContainsKey(text)) { text = "en"; } bool num = !string.Equals(_currentLocale, text, StringComparison.OrdinalIgnoreCase); _currentLocale = text; if (num || forceNotify) { this.LanguageChanged?.Invoke(); } } public string GetText(string key, params object[] args) { RefreshLanguage(forceNotify: false); string text = TryGetText(_currentLocale, key) ?? TryGetText("en", key) ?? TryGetText("zh_CN", key) ?? key; if (args == null || args.Length == 0) { return text; } return string.Format(text, args); } private string TryGetText(string locale, string key) { if (!_localizations.TryGetValue(locale, out var value) || !value.TryGetValue(key, out var value2)) { return null; } return value2; } private static string NormalizeLocale(string languageCode) { switch (languageCode) { case "zh_CN": case "zh_TW": case "ja_JP": case "en": return languageCode; default: return "en"; } } } } namespace ModSettingsMenu.Api { public static class ModKeybindTags { public static ModSettingsEntryTag Keybind(string displayName = null, string description = null, int? order = null, bool? hidden = null) { return ModSettingsTags.Keybind(displayName, description, order, hidden); } } public sealed class ModKeybindValue { public const int SlotCount = 3; private readonly Keys?[] _keys = new Keys?[3]; private readonly MouseButtons?[] _mouseButtons = new MouseButtons?[3]; private readonly Buttons?[] _buttons = new Buttons?[3]; public IReadOnlyList Keys => _keys; public IReadOnlyList MouseButtons => _mouseButtons; public IReadOnlyList Buttons => _buttons; internal static bool IsSupportedType(Type type) { if (!(type == typeof(Keys))) { return type == typeof(string); } return true; } public static ModKeybindValue FromEntry(ConfigEntryBase entry) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (entry.SettingType == typeof(Keys)) { return FromSingleKey((Keys)((entry.BoxedValue is Keys val) ? ((int)val) : 0)); } return Parse(entry.BoxedValue as string); } internal static ModKeybindValue FromDefault(ConfigEntryBase entry) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (entry.SettingType == typeof(Keys)) { return FromSingleKey((Keys)((entry.DefaultValue is Keys val) ? ((int)val) : 0)); } return Parse(entry.DefaultValue as string); } private static ModKeybindValue FromSingleKey(Keys key) { //IL_0006: 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) ModKeybindValue modKeybindValue = new ModKeybindValue(); if ((int)key != 0) { modKeybindValue._keys[0] = key; } return modKeybindValue; } public static ModKeybindValue Parse(string raw) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) ModKeybindValue modKeybindValue = new ModKeybindValue(); if (string.IsNullOrWhiteSpace(raw)) { return modKeybindValue; } if (!raw.Contains(":") && Enum.TryParse(raw, ignoreCase: true, out Keys result) && (int)result != 0) { modKeybindValue._keys[0] = result; return modKeybindValue; } string[] array = raw.Split(';'); foreach (string text in array) { int num = text.IndexOf(':'); if (num > 0) { string prefix = text.Substring(0, num).Trim().ToUpperInvariant(); string[] array2 = text.Substring(num + 1).Split(','); for (int j = 0; j < 3 && j < array2.Length; j++) { ApplySlot(modKeybindValue, prefix, j, array2[j]); } } } return modKeybindValue; } internal ModKeybindValue Clone() { ModKeybindValue modKeybindValue = new ModKeybindValue(); for (int i = 0; i < 3; i++) { modKeybindValue._keys[i] = _keys[i]; modKeybindValue._mouseButtons[i] = _mouseButtons[i]; modKeybindValue._buttons[i] = _buttons[i]; } return modKeybindValue; } public Keys ToSingleKey() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return _keys[0].GetValueOrDefault(); } public string ToConfigString() { return $"K:{FormatSlots((IReadOnlyList)_keys)};M:{FormatSlots((IReadOnlyList)_mouseButtons)};B:{FormatSlots((IReadOnlyList)_buttons)}"; } public string ToDisplayString() { string text = FormatBoundMouseKeyboardSlots(); string text2 = FormatBoundButtonSlots(); if (string.IsNullOrWhiteSpace(text2)) { if (!string.IsNullOrWhiteSpace(text)) { return text; } return "-"; } if (string.IsNullOrWhiteSpace(text)) { return "Controller: " + text2; } return text + " | Controller: " + text2; } public override string ToString() { return ToConfigString(); } internal void SetKey(int index, Keys key, bool singleKey = false) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) CheckIndex(index); ClearMouseKeyboardSlot(index); if ((int)key != 0) { RemoveKey(key); _keys[index] = key; } if (singleKey) { for (int i = 1; i < 3; i++) { ClearMouseKeyboardSlot(i); } } } internal void SetMouse(int index, MouseButtons mouseButton) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) CheckIndex(index); ClearMouseKeyboardSlot(index); RemoveMouse(mouseButton); _mouseButtons[index] = mouseButton; } internal void SetButton(int index, Buttons button) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) CheckIndex(index); _buttons[index] = null; if ((int)button != 0) { RemoveButton(button); _buttons[index] = button; } } internal void ClearMouseKeyboardSlot(int index) { CheckIndex(index); _keys[index] = null; _mouseButtons[index] = null; } internal void ClearButtonSlot(int index) { CheckIndex(index); _buttons[index] = null; } internal void ClearSlot(int index) { ClearMouseKeyboardSlot(index); ClearButtonSlot(index); } internal string FormatMouseKeyboardSlot(int index) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) CheckIndex(index); if (_keys[index].HasValue) { return ((object)_keys[index].Value/*cast due to .constrained prefix*/).ToString(); } if (_mouseButtons[index].HasValue) { return $"Mouse {_mouseButtons[index].Value}"; } return "-"; } internal string FormatButtonSlot(int index) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) CheckIndex(index); ref Buttons? reference = ref _buttons[index]; return (reference.HasValue ? ((object)reference.GetValueOrDefault()/*cast due to .constrained prefix*/).ToString() : null) ?? "-"; } internal string FormatMouseKeyboardSlots() { return FormatDisplaySlots(FormatMouseKeyboardSlot); } internal string FormatButtonSlots() { return FormatDisplaySlots(FormatButtonSlot); } private string FormatBoundMouseKeyboardSlots() { return FormatBoundSlots(FormatMouseKeyboardSlot); } private string FormatBoundButtonSlots() { return FormatBoundSlots(FormatButtonSlot); } private bool Equals(ModKeybindValue other) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (other == null) { return false; } for (int i = 0; i < 3; i++) { if (_keys[i] != other._keys[i] || _mouseButtons[i] != other._mouseButtons[i] || _buttons[i] != other._buttons[i]) { return false; } } return true; } public override bool Equals(object obj) { return Equals(obj as ModKeybindValue); } public override int GetHashCode() { int num = 17; for (int i = 0; i < 3; i++) { num = num * 31 + _keys[i].GetHashCode(); num = num * 31 + _mouseButtons[i].GetHashCode(); num = num * 31 + _buttons[i].GetHashCode(); } return num; } private static void ApplySlot(ModKeybindValue value, string prefix, int index, string rawSlot) { //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) string text = rawSlot?.Trim(); if (string.IsNullOrWhiteSpace(text) || text == "-") { return; } if (text.StartsWith("Mouse ", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Mouse ".Length).Trim(); } if (prefix == null) { return; } Buttons result; Keys result2; MouseButtons result3; switch (prefix.Length) { case 1: { char c = prefix[0]; if (c != 'B') { if (c == 'K') { goto IL_0107; } if (c != 'M') { break; } goto IL_0128; } goto IL_0146; } case 7: switch (prefix[0]) { default: return; case 'B': if (!(prefix == "BUTTONS")) { return; } break; case 'G': if (!(prefix == "GAMEPAD")) { return; } break; } goto IL_0146; case 3: if (!(prefix == "KEY")) { break; } goto IL_0107; case 4: if (!(prefix == "KEYS")) { break; } goto IL_0107; case 5: if (!(prefix == "MOUSE")) { break; } goto IL_0128; case 6: if (!(prefix == "BUTTON")) { break; } goto IL_0146; case 2: break; IL_0146: if (Enum.TryParse(text, ignoreCase: true, out result) && (int)result != 0) { value._buttons[index] = result; } break; IL_0107: if (Enum.TryParse(text, ignoreCase: true, out result2) && (int)result2 != 0) { value._keys[index] = result2; } break; IL_0128: if (Enum.TryParse(text, ignoreCase: true, out result3)) { value._mouseButtons[index] = result3; } break; } } private void RemoveKey(Keys key) { //IL_0011: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 3; i++) { if (_keys[i] == (Keys?)key) { _keys[i] = null; } } } private void RemoveMouse(MouseButtons mouseButton) { //IL_0011: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 3; i++) { if (_mouseButtons[i] == (MouseButtons?)mouseButton) { _mouseButtons[i] = null; } } } private void RemoveButton(Buttons button) { //IL_0011: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 3; i++) { if (_buttons[i] == (Buttons?)button) { _buttons[i] = null; } } } private static string FormatSlots(IReadOnlyList slots) where T : struct { string[] array = new string[3]; for (int i = 0; i < 3; i++) { array[i] = slots[i]?.ToString() ?? "-"; } return string.Join(",", array); } private static string FormatDisplaySlots(Func formatSlot) { string[] array = new string[3]; for (int i = 0; i < 3; i++) { array[i] = formatSlot(i); } return string.Join(", ", array); } private static string FormatBoundSlots(Func formatSlot) { List list = new List(); for (int i = 0; i < 3; i++) { string text = formatSlot(i); if (!string.IsNullOrWhiteSpace(text) && text != "-") { list.Add(text); } } return string.Join(" / ", list); } private static void CheckIndex(int index) { if (index < 0 || index >= 3) { throw new ArgumentOutOfRangeException("index"); } } } public sealed class ModSettingsEntryOptions { private int _order; private bool _hidden; private bool _keybind; public ConfigDefinition Definition { get; } public string DisplayName { get; set; } public string Description { get; set; } public double? SliderStep { get; set; } public bool Keybind { get { return _keybind; } set { _keybind = value; HasKeybind = true; } } public int Order { get { return _order; } set { _order = value; HasOrder = true; } } public bool Hidden { get { return _hidden; } set { _hidden = value; HasHidden = true; } } internal bool HasOrder { get; private set; } internal bool HasHidden { get; private set; } internal bool HasKeybind { get; private set; } internal ModSettingsEntryOptions(ConfigDefinition definition) { Definition = definition; } internal ModSettingsEntryOptions Clone() { ModSettingsEntryOptions modSettingsEntryOptions = new ModSettingsEntryOptions(Definition) { DisplayName = DisplayName, Description = Description, SliderStep = SliderStep }; if (HasOrder) { modSettingsEntryOptions.Order = Order; } if (HasHidden) { modSettingsEntryOptions.Hidden = Hidden; } if (HasKeybind) { modSettingsEntryOptions.Keybind = Keybind; } return modSettingsEntryOptions; } internal void Apply(ModSettingsEntryTag tag) { if (tag != null) { if (!string.IsNullOrWhiteSpace(tag.DisplayName)) { DisplayName = tag.DisplayName; } if (!string.IsNullOrWhiteSpace(tag.Description)) { Description = tag.Description; } if (tag.SliderStep.HasValue) { SliderStep = tag.SliderStep.Value; } if (tag.Keybind.HasValue) { Keybind = tag.Keybind.Value; } if (tag.Order.HasValue) { Order = tag.Order.Value; } if (tag.Hidden.HasValue) { Hidden = tag.Hidden.Value; } } } internal void Apply(ModSettingsEntryOptions options) { if (options != null) { if (!string.IsNullOrWhiteSpace(options.DisplayName)) { DisplayName = options.DisplayName; } if (!string.IsNullOrWhiteSpace(options.Description)) { Description = options.Description; } if (options.SliderStep.HasValue) { SliderStep = options.SliderStep.Value; } if (options.HasKeybind) { Keybind = options.Keybind; } if (options.HasOrder) { Order = options.Order; } if (options.HasHidden) { Hidden = options.Hidden; } } } } public sealed class ModSettingsEntryTag { public string DisplayName { get; set; } public string Description { get; set; } public double? SliderStep { get; set; } public bool? Keybind { get; set; } public int? Order { get; set; } public bool? Hidden { get; set; } } public sealed class ModSettingsModOptions { public string Icon { get; set; } public string IconPath { get; set; } public string Version { get; set; } public string Author { get; set; } public string Description { get; set; } public int? NexusModsId { get; set; } public string UpdateManifestUrl { get; set; } public int? Order { get; set; } public bool? HideWhenEmpty { get; set; } } public sealed class ModSettingsRegistration { private readonly Dictionary _sections = new Dictionary(); private readonly Dictionary _entries = new Dictionary(); public string PluginGuid { get; } public string DisplayName { get; set; } public ConfigFile ConfigFile { get; } public string Icon { get; set; } = "cog"; public string IconPath { get; set; } public string Version { get; set; } public string Author { get; set; } public string Description { get; set; } public int? NexusModsId { get; set; } public string UpdateManifestUrl { get; set; } public int Order { get; set; } public bool HideWhenEmpty { get; set; } = true; public IReadOnlyDictionary Sections => _sections; public IReadOnlyDictionary Entries => _entries; internal ModSettingsRegistration(string pluginGuid, string displayName, ConfigFile configFile) { PluginGuid = pluginGuid ?? throw new ArgumentNullException("pluginGuid"); DisplayName = (string.IsNullOrWhiteSpace(displayName) ? pluginGuid : displayName); ConfigFile = configFile ?? throw new ArgumentNullException("configFile"); } internal void Apply(ModSettingsModOptions options) { if (options != null) { if (!string.IsNullOrWhiteSpace(options.Icon)) { Icon = options.Icon; } if (!string.IsNullOrWhiteSpace(options.IconPath)) { IconPath = options.IconPath; } if (!string.IsNullOrWhiteSpace(options.Version)) { Version = options.Version; } if (!string.IsNullOrWhiteSpace(options.Author)) { Author = options.Author; } if (!string.IsNullOrWhiteSpace(options.Description)) { Description = options.Description; } if (options.NexusModsId.HasValue) { NexusModsId = options.NexusModsId.Value; } if (!string.IsNullOrWhiteSpace(options.UpdateManifestUrl)) { UpdateManifestUrl = options.UpdateManifestUrl; } if (options.Order.HasValue) { Order = options.Order.Value; } if (options.HideWhenEmpty.HasValue) { HideWhenEmpty = options.HideWhenEmpty.Value; } } } public ModSettingsRegistration ConfigureSection(string section, Action configure) { if (string.IsNullOrWhiteSpace(section)) { throw new ArgumentException("Section cannot be empty.", "section"); } if (!_sections.TryGetValue(section, out var value)) { value = new ModSettingsSectionOptions(section); _sections.Add(section, value); } configure?.Invoke(value); return this; } public ModSettingsRegistration ConfigureEntry(string section, string key, Action configure) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown return ConfigureEntry(new ConfigDefinition(section, key), configure); } public ModSettingsRegistration ConfigureEntry(ConfigDefinition definition, Action configure) { if (definition == (ConfigDefinition)null) { throw new ArgumentNullException("definition"); } if (!_entries.TryGetValue(definition, out var value)) { value = new ModSettingsEntryOptions(definition); _entries.Add(definition, value); } configure?.Invoke(value); return this; } } public static class ModSettingsRegistry { private static readonly object Sync = new object(); private static readonly Dictionary Items = new Dictionary(); public static event Action RefreshRequested; public static ModSettingsRegistration Register(string pluginGuid, string displayName, ConfigFile configFile, Action configure = null) { ModSettingsRegistration modSettingsRegistration = new ModSettingsRegistration(pluginGuid, displayName, configFile); configure?.Invoke(modSettingsRegistration); lock (Sync) { Items[pluginGuid] = modSettingsRegistration; return modSettingsRegistration; } } public static ModSettingsRegistration Register(string pluginGuid, string displayName, ConfigFile configFile, ModSettingsModOptions options) { ModSettingsRegistration modSettingsRegistration = new ModSettingsRegistration(pluginGuid, displayName, configFile); modSettingsRegistration.Apply(options); lock (Sync) { Items[pluginGuid] = modSettingsRegistration; return modSettingsRegistration; } } public static bool Unregister(string pluginGuid) { lock (Sync) { return Items.Remove(pluginGuid); } } public static bool TryGet(string pluginGuid, out ModSettingsRegistration registration) { lock (Sync) { return Items.TryGetValue(pluginGuid, out registration); } } public static IReadOnlyCollection GetRegistrations() { lock (Sync) { return new List(Items.Values); } } internal static void RequestRefresh() { Action refreshRequested = ModSettingsRegistry.RefreshRequested; if (refreshRequested == null) { return; } Delegate[] invocationList = refreshRequested.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action action = (Action)invocationList[i]; try { action(); } catch { } } } } public sealed class ModSettingsSectionOptions { private int _order; private bool _hidden; public string Section { get; } public string DisplayName { get; set; } public int Order { get { return _order; } set { _order = value; HasOrder = true; } } public bool Hidden { get { return _hidden; } set { _hidden = value; HasHidden = true; } } internal bool HasOrder { get; private set; } internal bool HasHidden { get; private set; } internal ModSettingsSectionOptions(string section) { Section = section; } internal void Apply(ModSettingsSectionTag tag) { if (tag != null) { if (!string.IsNullOrWhiteSpace(tag.DisplayName)) { DisplayName = tag.DisplayName; } if (tag.Order.HasValue) { Order = tag.Order.Value; } if (tag.Hidden.HasValue) { Hidden = tag.Hidden.Value; } } } } public sealed class ModSettingsSectionTag { public string Section { get; set; } public string DisplayName { get; set; } public int? Order { get; set; } public bool? Hidden { get; set; } } public static class ModSettingsTags { public static ModSettingsEntryTag Entry(string displayName = null, string description = null, int? order = null, double? sliderStep = null, bool? hidden = null) { return new ModSettingsEntryTag { DisplayName = displayName, Description = description, Order = order, SliderStep = sliderStep, Hidden = hidden }; } public static ModSettingsEntryTag Keybind(string displayName = null, string description = null, int? order = null, bool? hidden = null) { return new ModSettingsEntryTag { DisplayName = displayName, Description = description, Order = order, Hidden = hidden, Keybind = true }; } public static ModSettingsSectionTag Section(string section, string displayName = null, int? order = null, bool? hidden = null) { return new ModSettingsSectionTag { Section = section, DisplayName = displayName, Order = order, Hidden = hidden }; } } }