Plugins: Implement ReentrantAttribute
This commit is contained in:
13
Il2CppInspector.Common/Plugins/API/ReentrantAttribute.cs
Normal file
13
Il2CppInspector.Common/Plugins/API/ReentrantAttribute.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.PluginAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Setting this attribute on an interface method will allow the method to be called again
|
||||||
|
/// while it is already running, ie. it enables recursion. Disabled by default.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
public class ReentrantAttribute : Attribute { }
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
// Internal helpers to call the same hook on every plugin
|
// Internal helpers to call the same hook on every plugin
|
||||||
// Does not include hooks that should be called individually, eg. OptionsChanged
|
// Does not include hooks that should be called individually, eg. OptionsChanged
|
||||||
|
// NOTE: The method names must be identical to the interface method names for stack tracing to work
|
||||||
internal static class PluginHooks
|
internal static class PluginHooks
|
||||||
{
|
{
|
||||||
public static PluginLoadPipelineStartingEventInfo LoadPipelineStarting()
|
public static PluginLoadPipelineStartingEventInfo LoadPipelineStarting()
|
||||||
@@ -11,7 +11,9 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using McMaster.NETCore.Plugins;
|
using McMaster.NETCore.Plugins;
|
||||||
|
using Il2CppInspector.PluginAPI;
|
||||||
|
|
||||||
// This is the ONLY line to update when the API version changes
|
// This is the ONLY line to update when the API version changes
|
||||||
using Il2CppInspector.PluginAPI.V100;
|
using Il2CppInspector.PluginAPI.V100;
|
||||||
@@ -35,6 +37,9 @@ namespace Il2CppInspector
|
|||||||
get => Plugin.Options.Single(o => o.Name == s).Value;
|
get => Plugin.Options.Single(o => o.Name == s).Value;
|
||||||
set => Plugin.Options.Single(o => o.Name == s).Value = value;
|
set => Plugin.Options.Single(o => o.Name == s).Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The current stack trace of the plugin
|
||||||
|
internal Stack<string> StackTrace = new Stack<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event arguments for error handler
|
// Event arguments for error handler
|
||||||
@@ -46,7 +51,7 @@ namespace Il2CppInspector
|
|||||||
// The exception thrown
|
// The exception thrown
|
||||||
public Exception Exception { get; set; }
|
public Exception Exception { get; set; }
|
||||||
|
|
||||||
// The name of the operation that was being performed
|
// The name of the method that was being executed
|
||||||
public string Operation { get; set; }
|
public string Operation { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,24 +279,34 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Try to cast each enabled plugin to a specific interface type, and for those supporting the interface, execute the supplied delegate
|
// Try to cast each enabled plugin to a specific interface type, and for those supporting the interface, execute the supplied delegate
|
||||||
// Errors will be forwarded to the error handler
|
// Errors will be forwarded to the error handler
|
||||||
internal static E Try<I, E>(Action<I, E> action) where E : PluginEventInfo, new()
|
internal static E Try<I, E>(Action<I, E> action, [CallerMemberName] string hookName = null) where E : PluginEventInfo, new()
|
||||||
{
|
{
|
||||||
var eventInfo = new E();
|
var eventInfo = new E();
|
||||||
|
var enabledPlugins = AsInstance.ManagedPlugins.Where(p => p.Enabled);
|
||||||
|
|
||||||
foreach (var plugin in EnabledPlugins)
|
foreach (var plugin in enabledPlugins)
|
||||||
if (plugin is I p)
|
if (plugin.Plugin is I p)
|
||||||
try {
|
try {
|
||||||
|
// Silently disallow recursion unless [Reentrant] is set on the method
|
||||||
|
if (plugin.StackTrace.Contains(hookName)) {
|
||||||
|
var allowRecursion = p.GetType().GetMethod(hookName).GetCustomAttribute(typeof(ReentrantAttribute)) != null;
|
||||||
|
if (!allowRecursion)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.StackTrace.Push(hookName);
|
||||||
action(p, eventInfo);
|
action(p, eventInfo);
|
||||||
|
plugin.StackTrace.Pop();
|
||||||
|
|
||||||
if (eventInfo.FullyProcessed)
|
if (eventInfo.FullyProcessed)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
// Disable failing plugin
|
// Disable failing plugin
|
||||||
Plugins[plugin.Id].Enabled = false;
|
plugin.Enabled = false;
|
||||||
|
|
||||||
// Forward error to error handler
|
// Forward error to error handler
|
||||||
eventInfo.Error = new PluginErrorEventArgs { Plugin = plugin, Exception = ex, Operation = typeof(I).Name };
|
eventInfo.Error = new PluginErrorEventArgs { Plugin = plugin.Plugin, Exception = ex, Operation = hookName };
|
||||||
ErrorHandler?.Invoke(AsInstance, eventInfo);
|
ErrorHandler?.Invoke(AsInstance, eventInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ namespace Il2CppInspectorGUI
|
|||||||
MessageBox.Show($"One or more plugin options for {e.Error.Plugin.Name} are invalid: {e.Error.Exception.Message}", "Plugin error");
|
MessageBox.Show($"One or more plugin options for {e.Error.Plugin.Name} are invalid: {e.Error.Exception.Message}", "Plugin error");
|
||||||
else
|
else
|
||||||
MessageBox.Show($"The plugin {e.Error.Plugin.Name} encountered an error while executing {e.Error.Operation}: {e.Error.Exception.Message}."
|
MessageBox.Show($"The plugin {e.Error.Plugin.Name} encountered an error while executing {e.Error.Operation}: {e.Error.Exception.Message}."
|
||||||
+ Environment.NewLine + Environment.NewLine + "Plugin has been disabled.", "Plugin error");
|
+ Environment.NewLine + Environment.NewLine + "Plugin has been disabled for this session.", "Plugin error");
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
Reference in New Issue
Block a user