using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Ryuka.Sulfur.NativeUI;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("SULFUR Config")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SULFUR Config")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5a9d2c4e-e1a5-45a4-a09b-2e2945f22014")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Ryuka.SulfurConfig;
internal sealed class ConfigEntryModel
{
public string PluginGuid;
public string PluginName;
public string Section;
public string Key;
public string Description;
public string DisplayName;
public Type SettingType;
public ConfigEntryBase Entry;
public string AppliedValue;
public string DraftValue;
public string DefaultValue;
public bool RequiresRestart;
public bool LiveApply;
public bool Advanced;
public bool Hidden;
public bool Dangerous;
public List<string> Badges = new List<string>();
public List<string> ValueList = new List<string>();
public float? MinValue;
public float? MaxValue;
public string RangeText;
public bool IsDirty => AppliedValue != DraftValue;
public static ConfigEntryModel Create(string pluginGuid, string pluginName, string section, string key, ConfigEntryBase entry)
{
ConfigEntryModel configEntryModel = new ConfigEntryModel();
string text = ((entry.Description != null) ? entry.Description.Description : "");
configEntryModel.PluginGuid = pluginGuid;
configEntryModel.PluginName = pluginName;
configEntryModel.Section = section;
configEntryModel.Key = key;
configEntryModel.DisplayName = SulfurLocalization.Get(pluginGuid, "entry." + section + "." + key + ".name", key);
configEntryModel.Description = SulfurLocalization.Get(pluginGuid, "entry." + section + "." + key + ".description", text);
configEntryModel.SettingType = entry.SettingType;
configEntryModel.Entry = entry;
configEntryModel.AppliedValue = entry.GetSerializedValue();
configEntryModel.DraftValue = configEntryModel.AppliedValue;
configEntryModel.DefaultValue = SerializeDefaultValue(entry.DefaultValue, entry.SettingType);
configEntryModel.RequiresRestart = HasAnyTag(entry, "SULFURConfigRestartRequired", "SulfurConfigRestartRequired", "RyukaConfigRestartRequired", "RequiresRestart", "RestartRequired");
configEntryModel.LiveApply = HasAnyTag(entry, "SULFURConfigLiveApply", "SulfurConfigLiveApply", "RyukaConfigLiveApply", "LiveApply", "RuntimeEditable");
configEntryModel.Advanced = HasAnyTag(entry, "SULFURConfigAdvanced", "SulfurConfigAdvanced", "RyukaConfigAdvanced", "Advanced");
configEntryModel.Hidden = HasAnyTag(entry, "SULFURConfigHidden", "SulfurConfigHidden", "RyukaConfigHidden", "Hidden", "HideFromSULFURConfig", "HideFromSulfurConfig", "HideFromRyukaConfig", "HideFromConfigPanel", "HideFromREPOConfig", "HideREPOConfig");
configEntryModel.Dangerous = HasAnyTag(entry, "SULFURConfigDangerous", "SulfurConfigDangerous", "RyukaConfigDangerous", "Dangerous", "Unsafe");
configEntryModel.ReadAcceptableValues();
configEntryModel.BuildBadges();
return configEntryModel;
}
public bool GetBoolDraft()
{
bool result;
return bool.TryParse(DraftValue, out result) && result;
}
public float GetFloatDraft()
{
if (float.TryParse(DraftValue, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
return result;
}
return 0f;
}
public float GetDefaultNumericMin()
{
return -999999f;
}
public float GetDefaultNumericMax()
{
return 999999f;
}
public void SetDraft(string value)
{
DraftValue = value ?? "";
}
public void SetDefaultDraft()
{
DraftValue = DefaultValue ?? "";
}
public void Apply()
{
Entry.SetSerializedValue(DraftValue);
Entry.ConfigFile.Save();
AppliedValue = Entry.GetSerializedValue();
DraftValue = AppliedValue;
}
public string GetLocalizedValueLabel(string rawValue)
{
return SulfurLocalization.Get(PluginGuid, "value." + Section + "." + Key + "." + rawValue, rawValue);
}
private void ReadAcceptableValues()
{
if (Entry.Description == null || Entry.Description.AcceptableValues == null)
{
return;
}
object acceptableValues = Entry.Description.AcceptableValues;
Type type = acceptableValues.GetType();
PropertyInfo property = type.GetProperty("AcceptableValues");
if (property != null && property.GetValue(acceptableValues, null) is Array array)
{
foreach (object item in array)
{
if (item != null)
{
ValueList.Add(item.ToString());
}
}
}
PropertyInfo property2 = type.GetProperty("MinValue");
PropertyInfo property3 = type.GetProperty("MaxValue");
if (property2 != null && property3 != null)
{
object value = property2.GetValue(acceptableValues, null);
object value2 = property3.GetValue(acceptableValues, null);
if (TryToFloat(value, out var result) && TryToFloat(value2, out var result2))
{
MinValue = result;
MaxValue = result2;
}
}
}
private void BuildBadges()
{
if (SettingType != null)
{
Badges.Add(SettingType.Name);
}
if (MinValue.HasValue && MaxValue.HasValue)
{
RangeText = "Allowed range: " + MinValue.Value.ToString("0.###", CultureInfo.InvariantCulture) + " - " + MaxValue.Value.ToString("0.###", CultureInfo.InvariantCulture);
Badges.Add("Range");
}
if (ValueList.Count > 0)
{
Badges.Add("Values: " + ValueList.Count);
}
}
private static string SerializeDefaultValue(object value, Type type)
{
if (value == null)
{
return "";
}
if (type == typeof(float))
{
return ((float)value).ToString(CultureInfo.InvariantCulture);
}
if (type == typeof(double))
{
return ((double)value).ToString(CultureInfo.InvariantCulture);
}
if (type == typeof(int))
{
return ((int)value).ToString(CultureInfo.InvariantCulture);
}
if (type == typeof(bool))
{
return ((bool)value) ? "true" : "false";
}
return value.ToString();
}
private static bool TryToFloat(object value, out float result)
{
result = 0f;
if (value == null)
{
return false;
}
try
{
result = Convert.ToSingle(value, CultureInfo.InvariantCulture);
return true;
}
catch
{
return false;
}
}
private static bool HasAnyTag(ConfigEntryBase entry, params string[] tagNames)
{
if (entry == null || entry.Description == null || entry.Description.Tags == null)
{
return false;
}
object[] tags = entry.Description.Tags;
foreach (object obj in tags)
{
if (obj == null)
{
continue;
}
string a = obj.ToString();
foreach (string b in tagNames)
{
if (string.Equals(a, b, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
return false;
}
}
internal sealed class ConfigPluginGroup
{
public string Guid;
public string Name;
public string DisplayName;
public string Description;
public string Location;
public List<ConfigSectionGroup> Sections = new List<ConfigSectionGroup>();
}
internal static class ConfigScanner
{
public static List<ConfigPluginGroup> Scan(ManualLogSource logger)
{
List<ConfigPluginGroup> list = new List<ConfigPluginGroup>();
foreach (PluginInfo value2 in Chainloader.PluginInfos.Values)
{
if (value2 == null || (Object)(object)value2.Instance == (Object)null || value2.Metadata == null)
{
continue;
}
ConfigFile config = value2.Instance.Config;
if (config == null)
{
continue;
}
string text = value2.Metadata.GUID ?? "unknown.guid";
string text2 = value2.Metadata.Name ?? text;
string text3 = value2.Location ?? "";
SulfurLocalization.LoadPluginLocalization(text, text3);
string text4 = SulfurLocalization.Get(text, "plugin.name", text2);
string description = SulfurLocalization.Get(text, "plugin.description", "");
ConfigPluginGroup configPluginGroup = new ConfigPluginGroup
{
Guid = text,
Name = text2,
DisplayName = text4 + " (" + text + ")",
Description = description,
Location = text3
};
foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
{
ConfigEntryBase value = item.Value;
if (value != null)
{
ConfigEntryModel model = ConfigEntryModel.Create(text, text2, item.Key.Section, item.Key.Key, value);
ConfigSectionGroup configSectionGroup = configPluginGroup.Sections.FirstOrDefault((ConfigSectionGroup x) => x.Name == model.Section);
if (configSectionGroup == null)
{
configSectionGroup = new ConfigSectionGroup
{
Name = model.Section,
DisplayName = SulfurLocalization.Get(text, "section." + model.Section, model.Section)
};
configPluginGroup.Sections.Add(configSectionGroup);
}
configSectionGroup.Entries.Add(model);
}
}
if (configPluginGroup.Sections.Count > 0)
{
list.Add(configPluginGroup);
}
}
foreach (ConfigPluginGroup item2 in list)
{
item2.Sections = item2.Sections.OrderBy((ConfigSectionGroup x) => x.DisplayName).ToList();
foreach (ConfigSectionGroup section in item2.Sections)
{
section.Entries = section.Entries.OrderBy((ConfigEntryModel x) => x.DisplayName).ToList();
}
}
return list.OrderBy((ConfigPluginGroup x) => x.DisplayName).ToList();
}
}
internal sealed class ConfigSectionGroup
{
public string Name;
public string DisplayName;
public List<ConfigEntryModel> Entries = new List<ConfigEntryModel>();
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("ryuka.sulfur.config", "SULFUR Config", "0.2.1")]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "ryuka.sulfur.config";
public const string PluginName = "SULFUR Config";
public const string PluginVersion = "0.2.1";
private ConfigNativePage nativePage;
internal static ManualLogSource Log { get; private set; }
private void Awake()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
SulfurLocalization.LoadPluginLocalization("ryuka.sulfur.config", ((BaseUnityPlugin)this).Info.Location);
nativePage = new ConfigNativePage(((BaseUnityPlugin)this).Logger);
SulfurOptionsApi.RegisterPage(new SulfurOptionsPage
{
PageId = "ryuka.sulfur.config",
DisplayName = "SULFUR Config",
SortOrder = 9999,
GetDisplayName = () => L("page.name", "SULFUR Config"),
BuildPage = nativePage.Build
});
((BaseUnityPlugin)this).Logger.LogInfo((object)"SULFUR Config registered native options page.");
}
private void OnDestroy()
{
SulfurOptionsApi.UnregisterPage("ryuka.sulfur.config");
if (Log == ((BaseUnityPlugin)this).Logger)
{
Log = null;
}
}
internal static string L(string key, string fallback)
{
return SulfurLocalization.Get("ryuka.sulfur.config", key, fallback);
}
}
internal sealed class ConfigNativePage
{
private readonly ManualLogSource logger;
private List<ConfigPluginGroup> groups = new List<ConfigPluginGroup>();
private readonly Dictionary<string, string> draftCache = new Dictionary<string, string>();
private bool needsScan = true;
private int lastLocalizationVersion = -1;
private string filterDraft = "";
private string activeFilter = "";
private string status = "";
private bool showOnlyDirty;
private bool showOnlyRyuka;
private bool showAdvanced;
private bool showHidden;
private bool showRestartRequired;
private bool showLiveApply;
private bool showDangerous;
public ConfigNativePage(ManualLogSource logger)
{
this.logger = logger;
}
public void Build(SulfurOptionsContext ctx)
{
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: 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_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_018e: Unknown result type (might be due to invalid IL or missing references)
//IL_01ba: Expected O, but got Unknown
SulfurLocalization.RefreshCurrentLanguage(true);
if (lastLocalizationVersion != SulfurLocalization.LanguageVersion)
{
lastLocalizationVersion = SulfurLocalization.LanguageVersion;
needsScan = true;
}
EnsureScanned();
int num = CountEntries(groups);
int num2 = CountDirty(groups);
ctx.SetFooter(Plugin.L("badge.entries", "Entries") + ": " + num + " | " + Plugin.L("badge.dirty", "Pending") + ": " + num2, string.IsNullOrWhiteSpace(status) ? Plugin.L("footer.ready", "Ready. Changes are not saved until you click Apply.") : status, Plugin.L("button.apply_dirty", "Apply"), (Action)delegate
{
ApplyDirty(ctx);
});
ctx.AddSection(Plugin.L("section.tools", "Tools"));
SulfurOptionsSettingRows.AddSettingText(ctx, new SulfurSettingRow
{
Label = Plugin.L("filter.label", "Filter"),
Description = Plugin.L("filter.description", "Search by mod name, GUID, section, key, or description."),
IsDirty = (filterDraft != activeFilter),
ShowDefaultButton = false,
DirtyText = Plugin.L("badge.dirty", "Pending"),
CleanText = Plugin.L("badge.clean", "Unchanged")
}, filterDraft, (Action<string>)delegate(string value)
{
filterDraft = value ?? "";
ctx.SetFooterStatus(Plugin.L("status.filter_draft", "Filter draft changed."));
});
ctx.AddSmallButton(Plugin.L("button.apply_filter", "Apply Filter"), (Action)delegate
{
activeFilter = filterDraft ?? "";
status = Plugin.L("status.filter_applied", "Filter applied.");
ctx.Rebuild();
});
ctx.AddSmallButton(Plugin.L("button.clear_filter", "Clear Filter"), (Action)delegate
{
filterDraft = "";
activeFilter = "";
status = Plugin.L("status.filter_cleared", "Filter cleared.");
ctx.Rebuild();
});
ctx.AddSmallButton(Plugin.L("button.refresh", "Refresh"), (Action)delegate
{
needsScan = true;
status = Plugin.L("status.refreshing", "Refreshing config list.");
ctx.Rebuild();
});
ctx.AddSmallButton(showOnlyDirty ? Plugin.L("filter.dirty_on", "Pending: ON") : Plugin.L("filter.dirty_off", "Pending: OFF"), (Action)delegate
{
showOnlyDirty = !showOnlyDirty;
ctx.Rebuild();
});
ctx.AddSmallButton(showOnlyRyuka ? Plugin.L("filter.ryuka_on", "Ryuka: ON") : Plugin.L("filter.ryuka_off", "Ryuka: OFF"), (Action)delegate
{
showOnlyRyuka = !showOnlyRyuka;
ctx.Rebuild();
});
ctx.AddSmallButton(showAdvanced ? Plugin.L("filter.advanced_on", "Advanced: ON") : Plugin.L("filter.advanced_off", "Advanced: OFF"), (Action)delegate
{
showAdvanced = !showAdvanced;
ctx.Rebuild();
});
ctx.AddSmallButton(showHidden ? Plugin.L("filter.hidden_on", "Hidden: ON") : Plugin.L("filter.hidden_off", "Hidden: OFF"), (Action)delegate
{
showHidden = !showHidden;
ctx.Rebuild();
});
ctx.AddSmallButton(showRestartRequired ? Plugin.L("filter.restart_on", "Restart: ON") : Plugin.L("filter.restart_off", "Restart: OFF"), (Action)delegate
{
showRestartRequired = !showRestartRequired;
ctx.Rebuild();
});
ctx.AddSmallButton(showLiveApply ? Plugin.L("filter.live_on", "Live: ON") : Plugin.L("filter.live_off", "Live: OFF"), (Action)delegate
{
showLiveApply = !showLiveApply;
ctx.Rebuild();
});
ctx.AddSmallButton(showDangerous ? Plugin.L("filter.dangerous_on", "Dangerous: ON") : Plugin.L("filter.dangerous_off", "Dangerous: OFF"), (Action)delegate
{
showDangerous = !showDangerous;
ctx.Rebuild();
});
ctx.AddSpacer(12f);
int num3 = 0;
int num4 = 0;
foreach (ConfigPluginGroup group in groups)
{
List<ConfigSectionGroup> visibleSections = GetVisibleSections(group);
if (visibleSections.Count == 0)
{
continue;
}
int num5 = visibleSections.Sum((ConfigSectionGroup s) => s.Entries.Count(EntryMatches));
int num6 = visibleSections.Sum((ConfigSectionGroup s) => s.Entries.Count((ConfigEntryModel e) => EntryMatches(e) && e.IsDirty));
bool flag = HasFilterOrSpecialFilter();
bool flag2 = SulfurOptionsFoldoutExtensions.AddPluginFoldoutWithBadges(ctx, "plugin." + group.Guid, group.DisplayName, false, flag, new string[2]
{
Plugin.L("badge.entries", "Entries") + ": " + num5,
(num6 > 0) ? (Plugin.L("badge.dirty", "Pending") + ": " + num6) : Plugin.L("badge.clean", "Unchanged")
});
num3++;
if (!flag2)
{
continue;
}
if (!string.IsNullOrWhiteSpace(group.Description))
{
ctx.AddDescription(group.Description);
}
foreach (ConfigSectionGroup item in visibleSections)
{
List<ConfigEntryModel> list = item.Entries.Where(EntryMatches).ToList();
if (list.Count == 0)
{
continue;
}
int num7 = list.Count((ConfigEntryModel x) => x.IsDirty);
if (!SulfurOptionsFoldoutExtensions.AddSectionFoldout(ctx, "plugin." + group.Guid + ".section." + item.Name, item.DisplayName, false, flag))
{
continue;
}
using (ctx.BeginThemedGroup("section.content." + group.Guid + "." + item.Name))
{
ctx.AddBadgeRow(new string[2]
{
Plugin.L("badge.entries", "Entries") + ": " + list.Count,
(num7 > 0) ? (Plugin.L("badge.dirty", "Pending") + ": " + num7) : Plugin.L("badge.clean", "Unchanged")
});
foreach (ConfigEntryModel item2 in list)
{
DrawEntry(ctx, item2);
num4++;
}
}
}
}
if (num3 == 0)
{
ctx.AddWarning(Plugin.L("message.no_results", "No config entries match the current filters."));
}
}
private void EnsureScanned()
{
if (needsScan || groups == null || groups.Count <= 0)
{
groups = ConfigScanner.Scan(logger);
RestoreDrafts(groups);
needsScan = false;
}
}
private void DrawEntry(SulfurOptionsContext ctx, ConfigEntryModel entry)
{
//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_0039: 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_0051: 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: 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_0095: 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_00b7: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: 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_0127: 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)
//IL_0151: 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_017b: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: 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_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01ce: Expected O, but got Unknown
SulfurSettingHandle handle = null;
SulfurSettingRow val = new SulfurSettingRow
{
Label = entry.DisplayName,
Description = entry.Description,
IndentLevel = 1,
IsDirty = entry.IsDirty,
RequiresRestart = entry.RequiresRestart,
LiveApply = entry.LiveApply,
Advanced = entry.Advanced,
Hidden = entry.Hidden,
Dangerous = entry.Dangerous,
Message = (entry.IsDirty ? Plugin.L("message.pending_warning", "This setting has unsaved pending changes. Click Apply to write it to cfg.") : entry.RangeText),
MessageKind = (SulfurMessageKind)(entry.IsDirty ? 1 : 0),
DirtyText = Plugin.L("badge.dirty", "Pending"),
CleanText = Plugin.L("badge.clean", "Unchanged"),
RestartRequiredText = Plugin.L("badge.restart_required", "Restart Required"),
LiveApplyText = Plugin.L("badge.live_apply", "Live Apply"),
AdvancedText = Plugin.L("badge.advanced", "Advanced"),
HiddenText = Plugin.L("badge.hidden", "Hidden"),
DangerousText = Plugin.L("badge.dangerous", "Dangerous"),
DefaultButtonText = Plugin.L("button.default", "Default"),
ExtraBadges = entry.Badges.ToArray(),
OnDefault = delegate
{
entry.SetDefaultDraft();
SaveDraft(entry);
status = Plugin.L("status.default_draft", "Default draft set: ") + entry.Key;
UpdatePendingUi(ctx, entry, handle);
}
};
Type type = entry.SettingType;
if (type == typeof(bool))
{
SulfurOptionsSettingRows.AddSettingToggleEx(ctx, val, entry.GetBoolDraft(), (Action<bool, SulfurSettingHandle>)delegate(bool value, SulfurSettingHandle h)
{
entry.SetDraft(value ? "true" : "false");
SaveDraft(entry);
status = Plugin.L("status.changed", "Pending change: ") + entry.Key;
UpdatePendingUi(ctx, entry, h);
}, ref handle);
}
else if (entry.ValueList.Count > 0)
{
List<string> list = entry.ValueList.Select(entry.GetLocalizedValueLabel).ToList();
int num = entry.ValueList.IndexOf(entry.DraftValue);
if (num < 0)
{
num = 0;
}
SulfurOptionsSettingRows.AddSettingCycleEx(ctx, val, (IReadOnlyList<string>)list, num, (Action<int, string, SulfurSettingHandle>)delegate(int newIndex, string selectedDisplayValue, SulfurSettingHandle h)
{
if (newIndex >= 0 && newIndex < entry.ValueList.Count)
{
entry.SetDraft(entry.ValueList[newIndex]);
}
SaveDraft(entry);
status = Plugin.L("status.changed", "Pending change: ") + entry.Key;
UpdatePendingUi(ctx, entry, h);
}, ref handle);
}
else if (type.IsEnum)
{
List<string> rawValues = Enum.GetNames(type).ToList();
List<string> list2 = rawValues.Select(entry.GetLocalizedValueLabel).ToList();
int num2 = rawValues.IndexOf(entry.DraftValue);
if (num2 < 0)
{
num2 = 0;
}
SulfurOptionsSettingRows.AddSettingCycleEx(ctx, val, (IReadOnlyList<string>)list2, num2, (Action<int, string, SulfurSettingHandle>)delegate(int newIndex, string selectedDisplayValue, SulfurSettingHandle h)
{
if (newIndex >= 0 && newIndex < rawValues.Count)
{
entry.SetDraft(rawValues[newIndex]);
}
SaveDraft(entry);
status = Plugin.L("status.changed", "Pending change: ") + entry.Key;
UpdatePendingUi(ctx, entry, h);
}, ref handle);
}
else if (type == typeof(int) || type == typeof(float) || type == typeof(double))
{
float floatDraft = entry.GetFloatDraft();
float num3 = (entry.MinValue.HasValue ? entry.MinValue.Value : entry.GetDefaultNumericMin());
float num4 = (entry.MaxValue.HasValue ? entry.MaxValue.Value : entry.GetDefaultNumericMax());
int num5 = ((!(type == typeof(int))) ? 3 : 0);
SulfurOptionsSettingRows.AddSettingNumberEx(ctx, val, floatDraft, num3, num4, num5, (Action<float, SulfurSettingHandle>)delegate(float value, SulfurSettingHandle h)
{
if (type == typeof(int))
{
entry.SetDraft(Mathf.RoundToInt(value).ToString(CultureInfo.InvariantCulture));
}
else
{
entry.SetDraft(value.ToString("0.###", CultureInfo.InvariantCulture));
}
SaveDraft(entry);
status = Plugin.L("status.changed", "Pending change: ") + entry.Key;
UpdatePendingUi(ctx, entry, h);
}, ref handle);
}
else
{
SulfurOptionsSettingRows.AddSettingTextEx(ctx, val, entry.DraftValue, (Action<string, SulfurSettingHandle>)delegate(string value, SulfurSettingHandle h)
{
entry.SetDraft(value);
SaveDraft(entry);
status = Plugin.L("status.changed", "Pending change: ") + entry.Key;
UpdatePendingUi(ctx, entry, h);
}, ref handle);
}
}
private void UpdatePendingUi(SulfurOptionsContext ctx, ConfigEntryModel entry, SulfurSettingHandle handle)
{
if (handle != null)
{
handle.SetDirty(entry.IsDirty, Plugin.L("badge.dirty", "Pending"), Plugin.L("badge.clean", "Unchanged"));
handle.SetMessage(entry.IsDirty ? Plugin.L("message.pending_warning", "This setting has unsaved pending changes. Click Apply to write it to cfg.") : entry.RangeText, (SulfurMessageKind)(entry.IsDirty ? 1 : 0));
}
UpdateFooter(ctx);
}
private void UpdateFooter(SulfurOptionsContext ctx)
{
if (ctx != null)
{
ctx.SetFooter(Plugin.L("badge.entries", "Entries") + ": " + CountEntries(groups) + " | " + Plugin.L("badge.dirty", "Pending") + ": " + CountDirty(groups), string.IsNullOrWhiteSpace(status) ? Plugin.L("footer.ready", "Ready. Changes are not saved until you click Apply.") : status, Plugin.L("button.apply_dirty", "Apply"), (Action)delegate
{
ApplyDirty(ctx);
});
}
}
private void ApplyDirty(SulfurOptionsContext ctx)
{
int num = 0;
int num2 = 0;
foreach (ConfigPluginGroup group in groups)
{
foreach (ConfigSectionGroup section in group.Sections)
{
foreach (ConfigEntryModel entry in section.Entries)
{
if (entry.IsDirty)
{
try
{
entry.Apply();
ClearDraft(entry);
num++;
}
catch (Exception ex)
{
num2++;
logger.LogWarning((object)("Failed to apply " + entry.PluginGuid + " / " + entry.Section + " / " + entry.Key + ": " + ex.Message));
}
}
}
}
}
status = Plugin.L("status.apply_result", "Applied and saved: ") + num + ", " + Plugin.L("status.failed", "Failed: ") + num2 + ".";
ctx.Rebuild();
}
private List<ConfigSectionGroup> GetVisibleSections(ConfigPluginGroup plugin)
{
List<ConfigSectionGroup> list = new List<ConfigSectionGroup>();
if (plugin == null)
{
return list;
}
if (showOnlyRyuka && !Contains(plugin.Guid, "ryuka") && !Contains(plugin.Name, "ryuka"))
{
return list;
}
bool pluginTextHit = MatchesFilter(plugin.DisplayName) || MatchesFilter(plugin.Guid) || MatchesFilter(plugin.Name) || MatchesFilter(plugin.Description);
foreach (ConfigSectionGroup section in plugin.Sections)
{
bool sectionTextHit = MatchesFilter(section.DisplayName) || MatchesFilter(section.Name);
if (section.Entries.Any((ConfigEntryModel entry) => EntryPassesSpecialFilters(entry) && (NoTextFilter() || pluginTextHit || sectionTextHit || EntryTextMatches(entry))))
{
list.Add(section);
}
}
return list;
}
private bool SectionMatches(ConfigSectionGroup section)
{
return section?.Entries.Any(EntryMatches) ?? false;
}
private bool EntryMatches(ConfigEntryModel entry)
{
if (entry == null)
{
return false;
}
if (!EntryPassesSpecialFilters(entry))
{
return false;
}
if (NoTextFilter())
{
return true;
}
return EntryTextMatches(entry);
}
private bool EntryPassesSpecialFilters(ConfigEntryModel entry)
{
if (entry == null)
{
return false;
}
if (showOnlyDirty && !entry.IsDirty)
{
return false;
}
if (showAdvanced)
{
if (!entry.Advanced)
{
return false;
}
}
else if (entry.Advanced)
{
return false;
}
if (showHidden)
{
if (!entry.Hidden)
{
return false;
}
}
else if (entry.Hidden)
{
return false;
}
if (showRestartRequired && !entry.RequiresRestart)
{
return false;
}
if (showLiveApply && !entry.LiveApply)
{
return false;
}
if (showDangerous && !entry.Dangerous)
{
return false;
}
return true;
}
private bool EntryTextMatches(ConfigEntryModel entry)
{
return MatchesFilter(entry.PluginName) || MatchesFilter(entry.PluginGuid) || MatchesFilter(entry.Section) || MatchesFilter(entry.Key) || MatchesFilter(entry.DisplayName) || MatchesFilter(entry.Description);
}
private bool MatchesFilter(string value)
{
if (NoTextFilter())
{
return true;
}
return Contains(value, activeFilter);
}
private bool NoTextFilter()
{
return string.IsNullOrWhiteSpace(activeFilter);
}
private bool HasFilterOrSpecialFilter()
{
return !NoTextFilter() || showOnlyDirty || showOnlyRyuka || showAdvanced || showHidden || showRestartRequired || showLiveApply || showDangerous;
}
private void SaveDraft(ConfigEntryModel entry)
{
if (entry != null)
{
string draftKey = GetDraftKey(entry);
if (entry.IsDirty)
{
draftCache[draftKey] = entry.DraftValue;
}
else
{
draftCache.Remove(draftKey);
}
}
}
private void ClearDraft(ConfigEntryModel entry)
{
if (entry != null)
{
draftCache.Remove(GetDraftKey(entry));
}
}
private void RestoreDrafts(List<ConfigPluginGroup> source)
{
if (source == null || draftCache.Count == 0)
{
return;
}
foreach (ConfigPluginGroup item in source)
{
foreach (ConfigSectionGroup section in item.Sections)
{
foreach (ConfigEntryModel entry in section.Entries)
{
if (draftCache.TryGetValue(GetDraftKey(entry), out var value))
{
entry.SetDraft(value);
}
}
}
}
}
private static string GetDraftKey(ConfigEntryModel entry)
{
return entry.PluginGuid + "\u001f" + entry.Section + "\u001f" + entry.Key;
}
private static bool Contains(string text, string filter)
{
return !string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(filter) && text.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
}
private static int CountEntries(List<ConfigPluginGroup> source)
{
return source?.Sum((Func<ConfigPluginGroup, int>)CountEntries) ?? 0;
}
private static int CountDirty(List<ConfigPluginGroup> source)
{
return source?.Sum((Func<ConfigPluginGroup, int>)CountDirty) ?? 0;
}
private static int CountEntries(ConfigPluginGroup plugin)
{
if (plugin == null || plugin.Sections == null)
{
return 0;
}
return plugin.Sections.Sum((ConfigSectionGroup s) => s.Entries.Count);
}
private static int CountDirty(ConfigPluginGroup plugin)
{
if (plugin == null || plugin.Sections == null)
{
return 0;
}
return plugin.Sections.Sum((ConfigSectionGroup s) => s.Entries.Count((ConfigEntryModel e) => e.IsDirty));
}
}