Plugins/GUI: Tidy up
This commit is contained in:
@@ -20,6 +20,13 @@ using Il2CppInspector.PluginAPI.V100;
|
|||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
|
public enum OptionBehaviour
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
IgnoreInvalid,
|
||||||
|
NoValidation
|
||||||
|
}
|
||||||
|
|
||||||
// Internal settings for a plugin
|
// Internal settings for a plugin
|
||||||
public class ManagedPlugin
|
public class ManagedPlugin
|
||||||
{
|
{
|
||||||
@@ -40,6 +47,34 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// The current stack trace of the plugin
|
// The current stack trace of the plugin
|
||||||
internal Stack<string> StackTrace = new Stack<string>();
|
internal Stack<string> StackTrace = new Stack<string>();
|
||||||
|
|
||||||
|
// Get options as dictionary
|
||||||
|
public Dictionary<string, object> GetOptions()
|
||||||
|
=> Plugin.Options.ToDictionary(o => o.Name, o => o.Value);
|
||||||
|
|
||||||
|
// Set options to values with optional validation behaviour
|
||||||
|
public void SetOptions(Dictionary<string, object> options, OptionBehaviour behaviour = OptionBehaviour.None) {
|
||||||
|
foreach (var option in options)
|
||||||
|
// Throw an exception on the first invalid option
|
||||||
|
if (behaviour == OptionBehaviour.None)
|
||||||
|
this[option.Key] = option.Value;
|
||||||
|
|
||||||
|
// Don't set invalid options but don't throw an exception either
|
||||||
|
else if (behaviour == OptionBehaviour.IgnoreInvalid)
|
||||||
|
try {
|
||||||
|
this[option.Key] = option.Value;
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
// Force set options with no validation
|
||||||
|
else if (behaviour == OptionBehaviour.NoValidation) {
|
||||||
|
if (Plugin.Options.FirstOrDefault(o => o.Name == option.Key) is IPluginOption target) {
|
||||||
|
var validationCondition = target.If;
|
||||||
|
target.If = () => false;
|
||||||
|
target.Value = option.Value;
|
||||||
|
target.If = validationCondition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event arguments for error handler
|
// Event arguments for error handler
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ namespace Il2CppInspectorGUI
|
|||||||
public List<IPluginOption> Options { get; set; }
|
public List<IPluginOption> Options { get; set; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Save state for plugin options
|
||||||
private class PluginOptionState : IPluginOption
|
private class PluginOptionState : IPluginOption
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
@@ -139,6 +140,7 @@ namespace Il2CppInspectorGUI
|
|||||||
var loadedPlugins = PluginManager.AsInstance.ManagedPlugins;
|
var loadedPlugins = PluginManager.AsInstance.ManagedPlugins;
|
||||||
foreach (var savedState in savedPluginState.Reverse()) {
|
foreach (var savedState in savedPluginState.Reverse()) {
|
||||||
if (loadedPlugins.FirstOrDefault(p => p.Plugin.Id == savedState.Plugin.Id) is ManagedPlugin managedPlugin) {
|
if (loadedPlugins.FirstOrDefault(p => p.Plugin.Id == savedState.Plugin.Id) is ManagedPlugin managedPlugin) {
|
||||||
|
|
||||||
// Re-order to match saved order
|
// Re-order to match saved order
|
||||||
loadedPlugins.Remove(managedPlugin);
|
loadedPlugins.Remove(managedPlugin);
|
||||||
loadedPlugins.Insert(0, managedPlugin);
|
loadedPlugins.Insert(0, managedPlugin);
|
||||||
@@ -147,28 +149,24 @@ namespace Il2CppInspectorGUI
|
|||||||
managedPlugin.Enabled = savedState.Enabled;
|
managedPlugin.Enabled = savedState.Enabled;
|
||||||
|
|
||||||
// Set options
|
// Set options
|
||||||
if (savedState.Plugin.Options != null)
|
if (savedState.Plugin.Options != null) {
|
||||||
|
var options = new Dictionary<string, object>();
|
||||||
|
|
||||||
foreach (var savedOption in savedState.Plugin.Options)
|
foreach (var savedOption in savedState.Plugin.Options)
|
||||||
if (managedPlugin.Plugin.Options.FirstOrDefault(o => o.Name == savedOption.Name) is IPluginOption option) {
|
if (managedPlugin.Plugin.Options.FirstOrDefault(o => o.Name == savedOption.Name) is IPluginOption option) {
|
||||||
try {
|
if (savedOption.Value == null)
|
||||||
// Ignore validation
|
options.Add(option.Name, null);
|
||||||
var cond = option.If;
|
else
|
||||||
option.If = () => false;
|
options.Add(option.Name, (savedOption.Value, ((JsonElement) savedOption.Value).ValueKind) switch {
|
||||||
if (savedOption.Value == null)
|
(var v, JsonValueKind.String) => v.ToString(),
|
||||||
option.Value = null;
|
(var v, JsonValueKind.Number) => Convert.ChangeType(v.ToString(), option.Value.GetType()),
|
||||||
else
|
(var v, JsonValueKind.True) => true,
|
||||||
option.Value = (savedOption.Value, ((JsonElement) savedOption.Value).ValueKind) switch {
|
(var v, JsonValueKind.False) => false,
|
||||||
(var v, JsonValueKind.String) => v.ToString(),
|
_ => throw new ArgumentException("Unsupported JSON type")
|
||||||
(var v, JsonValueKind.Number) => Convert.ChangeType(v.ToString(), option.Value.GetType()),
|
});
|
||||||
(var v, JsonValueKind.True) => true,
|
|
||||||
(var v, JsonValueKind.False) => false,
|
|
||||||
_ => throw new ArgumentException("Unsupported JSON type")
|
|
||||||
};
|
|
||||||
option.If = cond;
|
|
||||||
}
|
|
||||||
// Ignore invalid values
|
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
|
managedPlugin.SetOptions(options, OptionBehaviour.NoValidation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +184,7 @@ namespace Il2CppInspectorGUI
|
|||||||
|
|
||||||
private Metadata metadata;
|
private Metadata metadata;
|
||||||
|
|
||||||
// True if we extracted from an APK, IPA, zip file etc.
|
// True if we extracted the current workload from an APK, IPA, zip file etc.
|
||||||
private bool isExtractedFromPackage;
|
private bool isExtractedFromPackage;
|
||||||
public bool IsExtractedFromPackage {
|
public bool IsExtractedFromPackage {
|
||||||
get => isExtractedFromPackage;
|
get => isExtractedFromPackage;
|
||||||
@@ -197,10 +195,14 @@ namespace Il2CppInspectorGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load options for the current image
|
||||||
public LoadOptions ImageLoadOptions { get; private set; }
|
public LoadOptions ImageLoadOptions { get; private set; }
|
||||||
|
|
||||||
|
// Application models for the current image
|
||||||
public List<AppModel> AppModels { get; } = new List<AppModel>();
|
public List<AppModel> AppModels { get; } = new List<AppModel>();
|
||||||
|
|
||||||
|
// The last exception thrown
|
||||||
|
// Reading the exception clears it
|
||||||
private Exception _lastException;
|
private Exception _lastException;
|
||||||
public Exception LastException {
|
public Exception LastException {
|
||||||
get {
|
get {
|
||||||
@@ -236,6 +238,7 @@ namespace Il2CppInspectorGUI
|
|||||||
PluginManager.StatusHandler += (s, e) => StatusUpdate(e.Plugin, "[" + e.Plugin.Name + "]\n" + e.Text);
|
PluginManager.StatusHandler += (s, e) => StatusUpdate(e.Plugin, "[" + e.Plugin.Name + "]\n" + e.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset image load options to their defaults
|
||||||
public void ResetLoadOptions() {
|
public void ResetLoadOptions() {
|
||||||
ImageLoadOptions = new LoadOptions {
|
ImageLoadOptions = new LoadOptions {
|
||||||
ImageBase = 0xffffffff_ffffffff,
|
ImageBase = 0xffffffff_ffffffff,
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ namespace Il2CppInspectorGUI
|
|||||||
ValidateAllOptions();
|
ValidateAllOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force each ListBoxItem to set its source property
|
||||||
|
// This will force errors to appear in the dialog box when exceptions are thrown
|
||||||
|
// Only needed when the window first opens or the plugin object changes
|
||||||
private void ValidateAllOptions() {
|
private void ValidateAllOptions() {
|
||||||
// Adapted from https://stackoverflow.com/a/18008545
|
// Adapted from https://stackoverflow.com/a/18008545
|
||||||
foreach (var item in lstOptions.Items) {
|
foreach (var item in lstOptions.Items) {
|
||||||
@@ -145,17 +148,12 @@ namespace Il2CppInspectorGUI
|
|||||||
ManagedPlugin = plugin;
|
ManagedPlugin = plugin;
|
||||||
|
|
||||||
// Copy current options
|
// Copy current options
|
||||||
OriginalOptions = new Dictionary<string, object>(Plugin.Options.ToDictionary(o => o.Name, o => o.Value));
|
OriginalOptions = plugin.GetOptions();
|
||||||
|
|
||||||
// Validate options once they have loaded
|
// Validate options once they have loaded
|
||||||
lstOptions.ItemContainerGenerator.StatusChanged += OptionsListBoxStatusChanged;
|
lstOptions.ItemContainerGenerator.StatusChanged += OptionsListBoxStatusChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void okButton_Click(object sender, RoutedEventArgs e) {
|
|
||||||
// Close dialog box but call OnClosing first to validate all the options
|
|
||||||
DialogResult = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select a file path
|
// Select a file path
|
||||||
private void btnFilePathSelector_Click(object sender, RoutedEventArgs e) {
|
private void btnFilePathSelector_Click(object sender, RoutedEventArgs e) {
|
||||||
|
|
||||||
@@ -217,6 +215,34 @@ namespace Il2CppInspectorGUI
|
|||||||
e.Handled = !Regex.IsMatch(e.Text, @"[A-Fa-f0-9]");
|
e.Handled = !Regex.IsMatch(e.Text, @"[A-Fa-f0-9]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset a plugin's settings
|
||||||
|
private void resetButton_Click(object sender, RoutedEventArgs e) {
|
||||||
|
// Replace plugin object with a new one (updates ManagedPlugin.Plugin)
|
||||||
|
PluginManager.Reset(Plugin);
|
||||||
|
|
||||||
|
// Validate options once they have loaded
|
||||||
|
lstOptions.ItemContainerGenerator.StatusChanged += OptionsListBoxStatusChanged;
|
||||||
|
|
||||||
|
// Replace options in ListBox
|
||||||
|
lstOptions.ItemsSource = Plugin.Options;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close dialog box but call OnClosing first to validate all the options
|
||||||
|
private void okButton_Click(object sender, RoutedEventArgs e) {
|
||||||
|
DialogResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close dialog box, reverting changes
|
||||||
|
private void cancelButton_Click(object sender, RoutedEventArgs e) {
|
||||||
|
// Revert changes
|
||||||
|
ManagedPlugin.SetOptions(OriginalOptions, OptionBehaviour.IgnoreInvalid);
|
||||||
|
|
||||||
|
// Replace options in ListBox
|
||||||
|
lstOptions.ItemsSource = Plugin.Options;
|
||||||
|
|
||||||
|
DialogResult = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check options validity before allowing the dialog to close either by clicking OK or the close icon
|
// Check options validity before allowing the dialog to close either by clicking OK or the close icon
|
||||||
private void Window_Closing(object sender, CancelEventArgs e) {
|
private void Window_Closing(object sender, CancelEventArgs e) {
|
||||||
|
|
||||||
@@ -236,18 +262,6 @@ namespace Il2CppInspectorGUI
|
|||||||
e.Cancel = true;
|
e.Cancel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset a plugin's settings
|
|
||||||
private void resetButton_Click(object sender, RoutedEventArgs e) {
|
|
||||||
// Get new context (updates ManagedPlugin)
|
|
||||||
PluginManager.Reset(Plugin);
|
|
||||||
|
|
||||||
// Validate options once they have loaded
|
|
||||||
lstOptions.ItemContainerGenerator.StatusChanged += OptionsListBoxStatusChanged;
|
|
||||||
|
|
||||||
// Replace options in ListBox
|
|
||||||
lstOptions.ItemsSource = Plugin.Options;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force all the If evaluations on each option to be re-evaluated each time an option is changed
|
// Force all the If evaluations on each option to be re-evaluated each time an option is changed
|
||||||
private void valueControl_Changed(object sender, RoutedEventArgs e) {
|
private void valueControl_Changed(object sender, RoutedEventArgs e) {
|
||||||
// Ignore changes when listbox is first populated
|
// Ignore changes when listbox is first populated
|
||||||
@@ -268,18 +282,5 @@ namespace Il2CppInspectorGUI
|
|||||||
ValidateAllOptions();
|
ValidateAllOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelButton_Click(object sender, RoutedEventArgs e) {
|
|
||||||
|
|
||||||
// Revert changes
|
|
||||||
foreach (var option in OriginalOptions)
|
|
||||||
try {
|
|
||||||
ManagedPlugin[option.Key] = option.Value;
|
|
||||||
} catch { }
|
|
||||||
|
|
||||||
// Replace options in ListBox
|
|
||||||
lstOptions.ItemsSource = Plugin.Options;
|
|
||||||
|
|
||||||
DialogResult = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Window x:Class="Il2CppInspector.GUI.PluginManagerDialog"
|
<Window x:Class="Il2CppInspectorGUI.PluginManagerDialog"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -6,7 +6,8 @@
|
|||||||
xmlns:local="clr-namespace:Il2CppInspector.GUI"
|
xmlns:local="clr-namespace:Il2CppInspector.GUI"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Plugin Manager" Height="450" Width="800"
|
Title="Plugin Manager" Height="450" Width="800"
|
||||||
WindowStartupLocation="CenterOwner">
|
WindowStartupLocation="CenterOwner"
|
||||||
|
Closing="Window_Closing">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<!-- Configure ListBox to display plugins nicely -->
|
<!-- Configure ListBox to display plugins nicely -->
|
||||||
<Style x:Key="ConfigItemStyle" TargetType="{x:Type ListBoxItem}">
|
<Style x:Key="ConfigItemStyle" TargetType="{x:Type ListBoxItem}">
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
using Il2CppInspector;
|
||||||
|
|
||||||
namespace Il2CppInspector.GUI
|
namespace Il2CppInspectorGUI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for PluginManagerDialog.xaml
|
/// Interaction logic for PluginManagerDialog.xaml
|
||||||
@@ -33,10 +34,13 @@ namespace Il2CppInspector.GUI
|
|||||||
lstPlugins_SelectionChanged(null, null);
|
lstPlugins_SelectionChanged(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save options whether the user clicked OK or the close icon
|
||||||
|
private void Window_Closing(object sender, CancelEventArgs e) {
|
||||||
|
((Il2CppInspectorGUI.App) Application.Current).SaveOptions();
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
Reference in New Issue
Block a user