Plugins: Add LoadPipelineStarting / LoadPipelineEnding, rename IsHandled to FullyProcessed

This commit is contained in:
Katy Coe
2020-12-25 22:29:31 +01:00
parent db4432061c
commit e929d8d97e
7 changed files with 66 additions and 29 deletions

View File

@@ -572,6 +572,15 @@ namespace Il2CppInspector
}
// Multi-image binaries may contain more than one Il2Cpp image
var inspectors = LoadFromStream(stream, metadata, statusCallback);
Console.SetOut(stdout);
return inspectors;
}
public static List<Il2CppInspector> LoadFromStream(IFileFormatStream stream, Metadata metadata, EventHandler<string> statusCallback = null) {
var processors = new List<Il2CppInspector>();
foreach (var image in stream.Images) {
Console.WriteLine("Container format: " + image.Format);
@@ -598,7 +607,9 @@ namespace Il2CppInspector
}
}
Console.SetOut(stdout);
// Plugin hook LoadPipelineEnding
PluginHooks.LoadPipelineEnding(processors);
return processors;
}

View File

@@ -54,6 +54,10 @@ namespace Il2CppInspector
// Initialize metadata object from a stream
public static Metadata FromStream(MemoryStream stream, EventHandler<string> statusCallback = null) {
// TODO: This should really be placed before the Metadata object is created,
// but for now this ensures it is called regardless of which client is in use
PluginHooks.LoadPipelineStarting();
var metadata = new Metadata(statusCallback);
stream.Position = 0;
stream.CopyTo(metadata);
@@ -173,7 +177,7 @@ namespace Il2CppInspector
// Get all metadata strings
var pluginGetStringsResult = PluginHooks.GetStrings(this);
if (pluginGetStringsResult.IsHandled)
if (pluginGetStringsResult.FullyProcessed && !pluginGetStringsResult.IsInvalid)
Strings = pluginGetStringsResult.Strings;
else {
@@ -243,7 +247,7 @@ namespace Il2CppInspector
// Get all string literals
var pluginGetStringLiteralsResult = PluginHooks.GetStringLiterals(this);
if (pluginGetStringLiteralsResult.IsHandled)
if (pluginGetStringLiteralsResult.FullyProcessed)
StringLiterals = pluginGetStringLiteralsResult.StringLiterals.ToArray();
else {

View File

@@ -6,6 +6,7 @@
using NoisyCowStudios.Bin2Object;
using Il2CppInspector.Reflection;
using System.Collections.Generic;
namespace Il2CppInspector.PluginAPI.V100
{
@@ -16,6 +17,11 @@ namespace Il2CppInspector.PluginAPI.V100
/// </summary>
public interface ILoadPipeline
{
/// <summary>
/// A new load task is about to start. Perform per-load initialization here
/// </summary>
void LoadPipelineStarting(PluginLoadPipelineStartingEventInfo info) { }
/// <summary>
/// Process global-metadata.dat when it is first opened as a sequence of bytes
/// Seek cursor will be at the start of the file
@@ -42,6 +48,13 @@ namespace Il2CppInspector.PluginAPI.V100
/// </summary>
void PostProcessPackage(Il2CppInspector package, PluginPostProcessPackageEventInfo data) { }
/// <summary>
/// The current load task has finished. Perform per-load teardown code here
/// One Il2CppInspector per sub-image in the binary is supplied
/// We have closed all open files but the .NET type model has not been created yet
/// </summary>
void LoadPipelineEnding(List<Il2CppInspector> packages, PluginLoadPipelineEndingEventInfo info) { }
/// <summary>
/// Post-process the .NET type model to make changes after it has been fully created
/// </summary>

View File

@@ -12,7 +12,7 @@ namespace Il2CppInspector.PluginAPI.V100
{
/// <summary>
/// Object which allows plugins to report on what has happened during a call
/// Changes made to this object propagate to the next plugin in the call chain until IsHandled is set to true
/// Changes made to this object propagate to the next plugin in the call chain until FullyProcessed is set to true
/// </summary>
public class PluginEventInfo
{
@@ -21,25 +21,25 @@ namespace Il2CppInspector.PluginAPI.V100
/// Generally, this will prevent other plugins from processing the data
/// Note that this should be set even if the processed data was invalid (<seealso cref="IsInvalid"/>)
/// If this is not set, the same event will be raised on the next available plugin
/// Note that you can still do processing but set IsHandled to false to allow additional processing from other plugins
/// Note that you can still do processing but set FullyProcessed to false to allow additional processing from other plugins
/// </summary>
public bool IsHandled { get; set; } = false;
public bool FullyProcessed { get; set; } = false;
/// <summary>
/// A plugin should set this when IsHandled = true but the data it processed was invalid, for example if the processing gave an unexpected result
/// A plugin should set this when the data it processed was invalid, for example if the processing gave an unexpected result
/// </summary>
public bool IsInvalid { get; set; } = false;
/// <summary>
/// A plugin should set this when it has directly modified the provided data structure (object)
/// This can be set even if IsHandled = false to indicate that changes have been made but more plugins can still be called
/// This can be set even if FullyProcessed = false to indicate that changes have been made but more plugins can still be called
/// Should be set to false if you have only queried (performed reads) on the data without changing it
/// </summary>
public bool IsDataModified { get; set; } = false;
/// <summary>
/// A plugin should set this when it has directly modified the supplied or underlying stream for the metadata or binary
/// This can be set even if IsHandled = false to indicate that changes have been made but more plugins can still be called
/// This can be set even if FullyProcessed = false to indicate that changes have been made but more plugins can still be called
/// Should be set to false if you have only queried (performed reads) on the stream without changing it
/// </summary>
public bool IsStreamModified { get; set; } = false;
@@ -50,6 +50,11 @@ namespace Il2CppInspector.PluginAPI.V100
public PluginErrorEventArgs Error { get; set; } = null;
}
/// <summary>
/// Event info for LoadPipelineStarting
/// </summary>
public class PluginLoadPipelineStartingEventInfo : PluginEventInfo { }
/// <summary>
/// Event info for PreProcessMetadata
/// </summary>
@@ -102,4 +107,9 @@ namespace Il2CppInspector.PluginAPI.V100
/// Event info for PostProcessTypeModel
/// </summary>
public class PluginPostProcessTypeModelEventInfo : PluginEventInfo { }
/// <summary>
/// Event info for LoadPipelineEnding
/// </summary>
public class PluginLoadPipelineEndingEventInfo : PluginEventInfo { }
}

View File

@@ -4,6 +4,7 @@
All rights reserved.
*/
using System.Collections.Generic;
using Il2CppInspector.Reflection;
using NoisyCowStudios.Bin2Object;
@@ -16,6 +17,9 @@ namespace Il2CppInspector
// Does not include hooks that should be called individually, eg. OptionsChanged
internal static class PluginHooks
{
public static PluginLoadPipelineStartingEventInfo LoadPipelineStarting()
=> PluginManager.Try<ILoadPipeline, PluginLoadPipelineStartingEventInfo>((p, e) => p.LoadPipelineStarting(e));
public static PluginPreProcessMetadataEventInfo PreProcessMetadata(BinaryObjectStream stream)
=> PluginManager.Try<ILoadPipeline, PluginPreProcessMetadataEventInfo>((p, e) => {
stream.Position = 0;
@@ -34,8 +38,10 @@ namespace Il2CppInspector
public static PluginPostProcessPackageEventInfo PostProcessPackage(Il2CppInspector package)
=> PluginManager.Try<ILoadPipeline, PluginPostProcessPackageEventInfo>((p, e) => p.PostProcessPackage(package, e));
public static PluginLoadPipelineEndingEventInfo LoadPipelineEnding(List<Il2CppInspector> packages)
=> PluginManager.Try<ILoadPipeline, PluginLoadPipelineEndingEventInfo>((p, e) => p.LoadPipelineEnding(packages, e));
public static PluginPostProcessTypeModelEventInfo PostProcessTypeModel(TypeModel typeModel)
=> PluginManager.Try<ILoadPipeline, PluginPostProcessTypeModelEventInfo>((p, e) => p.PostProcessTypeModel(typeModel, e));
}
}

View File

@@ -258,7 +258,7 @@ namespace Il2CppInspector
try {
action(p, eventInfo);
if (eventInfo.IsHandled)
if (eventInfo.FullyProcessed)
break;
}
catch (Exception ex) {

View File

@@ -88,7 +88,7 @@ namespace Il2CppInspectorGUI
MessageBox.Show("Could not update plugin options. " + e.Error.Exception.Message, "Plugin error");
else
MessageBox.Show($"The plugin {e.Error.Plugin.Name} encountered an error while executing {e.Error.Operation}: {e.Error.Exception.Message}."
+ Environment.NewLine + Environment.NewLine + "The application will continue but may not behave as expected.", "Plugin error");
+ Environment.NewLine + Environment.NewLine + "Plugin has been disabled.", "Plugin error");
};
PluginManager.StatusHandler += (s, e) => StatusUpdate(e.Plugin, "[" + e.Plugin.Name + "]\n" + e.Text);
@@ -163,26 +163,19 @@ namespace Il2CppInspectorGUI
throw new InvalidOperationException("Could not find any binary images in the file");
}
// Multi-image binaries may contain more than one Il2Cpp image
// Get an Il2CppInspector for each image
var inspectors = Inspector.LoadFromStream(stream, metadata, StatusUpdate);
AppModels.Clear();
foreach (var image in stream.Images) {
// Architecture-agnostic load attempt
try {
// If we can't load the IL2CPP data here, it's probably packed or obfuscated; ignore it
if (Il2CppBinary.Load(image, metadata, StatusUpdate) is Il2CppBinary binary) {
var inspector = new Inspector(binary, metadata);
// Build type model
OnStatusUpdate?.Invoke(this, $"Building .NET type model for {image.Format}/{image.Arch} image");
var typeModel = new TypeModel(inspector);
foreach (var inspector in inspectors) {
// Build type model
OnStatusUpdate?.Invoke(this, $"Building .NET type model for {inspector.BinaryImage.Format}/{inspector.BinaryImage.Arch} image");
var typeModel = new TypeModel(inspector);
// Initialize (but don't build) application model
// We will build the model after the user confirms the Unity version and target compiler
AppModels.Add(new AppModel(typeModel, makeDefaultBuild: false));
}
}
// Unsupported architecture; ignore it
catch (NotImplementedException) { }
// Initialize (but don't build) application model
// We will build the model after the user confirms the Unity version and target compiler
AppModels.Add(new AppModel(typeModel, makeDefaultBuild: false));
}
if (!AppModels.Any()) {
throw new InvalidOperationException("Could not auto-detect any IL2CPP binary images in the file. This may mean the binary file is packed, encrypted or obfuscated, that the file is not an IL2CPP image or that Il2CppInspector was not able to automatically find the required data. Please check the binary file in a disassembler to ensure that it is an unencrypted IL2CPP binary before submitting a bug report!");