GUI: Plugin configuration is retained between sessions
This commit is contained in:
@@ -10,6 +10,8 @@ using System.ComponentModel;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
@@ -27,6 +29,55 @@ namespace Il2CppInspectorGUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class App : Application, INotifyPropertyChanged
|
public partial class App : Application, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
|
// Converter for IPlugin for System.Text.Json
|
||||||
|
private class PluginConverter : JsonConverter<IPlugin>
|
||||||
|
{
|
||||||
|
public override IPlugin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||||
|
return (IPlugin) JsonSerializer.Deserialize(ref reader, typeof(PluginState), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, IPlugin value, JsonSerializerOptions options) {
|
||||||
|
JsonSerializer.Serialize(writer, value, value.GetType(), options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PluginOptionConverter : JsonConverter<IPluginOption>
|
||||||
|
{
|
||||||
|
public override IPluginOption Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||||
|
return (IPluginOption) JsonSerializer.Deserialize(ref reader, typeof(PluginOptionState), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, IPluginOption value, JsonSerializerOptions options) {
|
||||||
|
JsonSerializer.Serialize(writer, value, value.GetType(), options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save state for plugins
|
||||||
|
private class PluginState : IPlugin
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Name { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Author { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Description { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Version { get; set; }
|
||||||
|
public List<IPluginOption> Options { get; set; }
|
||||||
|
};
|
||||||
|
|
||||||
|
private class PluginOptionState : IPluginOption
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Description { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool Required { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Application startup
|
||||||
public App() : base() {
|
public App() : base() {
|
||||||
// Catch unhandled exceptions for debugging startup failures and plugins
|
// Catch unhandled exceptions for debugging startup failures and plugins
|
||||||
var np = Environment.NewLine + Environment.NewLine;
|
var np = Environment.NewLine + Environment.NewLine;
|
||||||
@@ -50,6 +101,12 @@ namespace Il2CppInspectorGUI
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Load options
|
||||||
|
LoadOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load options from user config
|
||||||
|
internal void LoadOptions() {
|
||||||
// Migrate settings from previous version if necessary
|
// Migrate settings from previous version if necessary
|
||||||
if (User.Default.UpgradeRequired) {
|
if (User.Default.UpgradeRequired) {
|
||||||
User.Default.Upgrade();
|
User.Default.Upgrade();
|
||||||
@@ -57,8 +114,53 @@ namespace Il2CppInspectorGUI
|
|||||||
User.Default.Save();
|
User.Default.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load plugins
|
// Load plugin state (enabled / execution order)
|
||||||
|
var savedPluginState = Array.Empty<ManagedPlugin>();
|
||||||
|
try {
|
||||||
|
savedPluginState = JsonSerializer.Deserialize<ManagedPlugin[]>(User.Default.PluginsState,
|
||||||
|
new JsonSerializerOptions { Converters = { new PluginConverter(), new PluginOptionConverter() } });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not set or invalid - just create a new set
|
||||||
|
catch (JsonException) { }
|
||||||
|
catch (NotSupportedException) { }
|
||||||
|
|
||||||
|
// Load plugins if they aren't already
|
||||||
PluginManager.EnsureInit();
|
PluginManager.EnsureInit();
|
||||||
|
|
||||||
|
// Arrange plugins
|
||||||
|
var loadedPlugins = PluginManager.AsInstance.ManagedPlugins;
|
||||||
|
foreach (var savedState in savedPluginState.Reverse()) {
|
||||||
|
if (loadedPlugins.FirstOrDefault(p => p.Plugin.Id == savedState.Plugin.Id) is ManagedPlugin managedPlugin) {
|
||||||
|
// Re-order to match saved order
|
||||||
|
loadedPlugins.Remove(managedPlugin);
|
||||||
|
loadedPlugins.Insert(0, managedPlugin);
|
||||||
|
|
||||||
|
// Enable/disable to match saved state
|
||||||
|
managedPlugin.Enabled = savedState.Enabled;
|
||||||
|
|
||||||
|
// Set options
|
||||||
|
if (savedState.Plugin.Options != null)
|
||||||
|
foreach (var savedOption in savedState.Plugin.Options)
|
||||||
|
if (managedPlugin.Plugin.Options.FirstOrDefault(o => o.Name == savedOption.Name) is IPluginOption option) {
|
||||||
|
// Ignore invalid values
|
||||||
|
try {
|
||||||
|
option.Value = savedOption.Value is JsonElement ? savedOption.Value.ToString() : savedOption.Value;
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save options in case no save exists or previous save is invalid
|
||||||
|
SaveOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save options to user config
|
||||||
|
internal void SaveOptions() {
|
||||||
|
User.Default.PluginsState = JsonSerializer.Serialize(
|
||||||
|
PluginManager.Plugins.Values.Cast<ManagedPlugin>().Where(p => p.Available).ToArray(),
|
||||||
|
new JsonSerializerOptions { Converters = { new PluginConverter(), new PluginOptionConverter() } });
|
||||||
|
User.Default.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Metadata metadata;
|
private Metadata metadata;
|
||||||
@@ -74,7 +176,7 @@ namespace Il2CppInspectorGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoadOptions LoadOptions { get; private set; }
|
public LoadOptions ImageLoadOptions { get; private set; }
|
||||||
|
|
||||||
public List<AppModel> AppModels { get; } = new List<AppModel>();
|
public List<AppModel> AppModels { get; } = new List<AppModel>();
|
||||||
|
|
||||||
@@ -114,7 +216,7 @@ namespace Il2CppInspectorGUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void ResetLoadOptions() {
|
public void ResetLoadOptions() {
|
||||||
LoadOptions = new LoadOptions {
|
ImageLoadOptions = new LoadOptions {
|
||||||
ImageBase = 0xffffffff_ffffffff,
|
ImageBase = 0xffffffff_ffffffff,
|
||||||
BinaryFilePath = null
|
BinaryFilePath = null
|
||||||
};
|
};
|
||||||
@@ -166,7 +268,7 @@ namespace Il2CppInspectorGUI
|
|||||||
// Attempt to load an IL2CPP binary file
|
// Attempt to load an IL2CPP binary file
|
||||||
public async Task<bool> LoadBinaryAsync(string binaryFile) {
|
public async Task<bool> LoadBinaryAsync(string binaryFile) {
|
||||||
// For loaders which require the file path to find additional files
|
// For loaders which require the file path to find additional files
|
||||||
LoadOptions.BinaryFilePath = binaryFile;
|
ImageLoadOptions.BinaryFilePath = binaryFile;
|
||||||
|
|
||||||
var stream = new MemoryStream(await File.ReadAllBytesAsync(binaryFile));
|
var stream = new MemoryStream(await File.ReadAllBytesAsync(binaryFile));
|
||||||
return await LoadBinaryAsync(stream);
|
return await LoadBinaryAsync(stream);
|
||||||
@@ -178,7 +280,7 @@ namespace Il2CppInspectorGUI
|
|||||||
OnStatusUpdate?.Invoke(this, "Processing binary");
|
OnStatusUpdate?.Invoke(this, "Processing binary");
|
||||||
|
|
||||||
// This may throw other exceptions from the individual loaders as well
|
// This may throw other exceptions from the individual loaders as well
|
||||||
IFileFormatStream stream = FileFormatStream.Load(binaryStream, LoadOptions, StatusUpdate);
|
IFileFormatStream stream = FileFormatStream.Load(binaryStream, ImageLoadOptions, StatusUpdate);
|
||||||
if (stream == null) {
|
if (stream == null) {
|
||||||
throw new InvalidOperationException("Could not determine the binary file format");
|
throw new InvalidOperationException("Could not determine the binary file format");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace Il2CppInspector.GUI
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
var app = (App) Application.Current;
|
var app = (App) Application.Current;
|
||||||
DataContext = app.LoadOptions;
|
DataContext = app.ImageLoadOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void okButton_Click(object sender, RoutedEventArgs e) {
|
private void okButton_Click(object sender, RoutedEventArgs e) {
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ namespace Il2CppInspector.GUI
|
|||||||
|
|
||||||
private void okButton_Click(object sender, RoutedEventArgs e) {
|
private void okButton_Click(object sender, RoutedEventArgs e) {
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
|
|
||||||
|
((Il2CppInspectorGUI.App) Application.Current).SaveOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload list of plugins and reset settings
|
// Reload list of plugins and reset settings
|
||||||
|
|||||||
12
Il2CppInspector.GUI/User.Designer.cs
generated
12
Il2CppInspector.GUI/User.Designer.cs
generated
@@ -46,5 +46,17 @@ namespace Il2CppInspector.GUI {
|
|||||||
this["UpgradeRequired"] = value;
|
this["UpgradeRequired"] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||||
|
public string PluginsState {
|
||||||
|
get {
|
||||||
|
return ((string)(this["PluginsState"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["PluginsState"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,8 @@
|
|||||||
<Setting Name="UpgradeRequired" Type="System.Boolean" Scope="User">
|
<Setting Name="UpgradeRequired" Type="System.Boolean" Scope="User">
|
||||||
<Value Profile="(Default)">True</Value>
|
<Value Profile="(Default)">True</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
|
<Setting Name="PluginsState" Type="System.String" Scope="User">
|
||||||
|
<Value Profile="(Default)" />
|
||||||
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
Reference in New Issue
Block a user