allow specifying imagebase in redux CLI

This commit is contained in:
LukeFZ
2026-01-14 17:11:17 +01:00
parent 12887c99df
commit 9fe77fdb1e
8 changed files with 68 additions and 34 deletions

View File

@@ -61,6 +61,11 @@ public class CliClient : IDisposable
public async ValueTask<string> GetInspectorVersion(CancellationToken cancellationToken = default)
=> await _connection.InvokeAsync<string>(nameof(Il2CppHub.GetInspectorVersion), cancellationToken);
public async ValueTask SetSettings(InspectorSettings settings, CancellationToken cancellationToken = default)
{
await _connection.InvokeAsync(nameof(Il2CppHub.SetSettings), settings, cancellationToken);
}
public async ValueTask WaitForLoadingToFinishAsync(CancellationToken cancellationToken = default)
{
var currentLoadingCount = _finishedLoadingCount;

View File

@@ -1,14 +1,13 @@
using Microsoft.AspNetCore.SignalR.Client;
using Spectre.Console;
using Spectre.Console;
using Spectre.Console.Cli;
namespace Il2CppInspector.Redux.CLI.Commands;
internal class InteractiveCommand(PortProvider portProvider) : BaseCommand<InteractiveCommand.Options>(portProvider)
internal sealed class InteractiveCommand(PortProvider portProvider) : BaseCommand<InteractiveCommand.Settings>(portProvider)
{
public class Options : CommandSettings;
public sealed class Settings : CommandSettings;
protected override async Task<int> ExecuteAsync(CliClient client, Options settings)
protected override async Task<int> ExecuteAsync(CliClient client, Settings settings)
{
await Task.Delay(1000);
await AnsiConsole.AskAsync<string>("meow?");

View File

@@ -3,7 +3,7 @@ using Spectre.Console.Cli;
namespace Il2CppInspector.Redux.CLI.Commands;
internal abstract class ManualCommand<T>(PortProvider portProvider) : BaseCommand<T>(portProvider) where T : ManualCommandOptions
internal abstract class ManualCommand<T>(PortProvider portProvider) : BaseCommand<T>(portProvider) where T : ManualCommandSettings
{
public override ValidationResult Validate(CommandContext context, T settings)
{

View File

@@ -3,7 +3,7 @@ using Spectre.Console.Cli;
namespace Il2CppInspector.Redux.CLI.Commands;
internal class ManualCommandOptions : CommandSettings
internal class ManualCommandSettings : CommandSettings
{
[CommandArgument(0, "<InputPath>")]
[Description("Paths to the input files. Will be subsequently loaded until binary and metadata were found.")]

View File

@@ -1,16 +1,18 @@
using Il2CppInspector.Cpp;
using System.Globalization;
using Il2CppInspector.Cpp;
using Il2CppInspector.Redux.FrontendCore;
using Il2CppInspector.Redux.FrontendCore.Outputs;
using Spectre.Console;
using Spectre.Console.Cli;
namespace Il2CppInspector.Redux.CLI.Commands;
internal class ProcessCommand(PortProvider portProvider) : ManualCommand<ProcessCommand.Option>(portProvider)
internal sealed class ProcessCommand(PortProvider portProvider) : ManualCommand<ProcessCommand.Settings>(portProvider)
{
// NOTE: There might be a better option than replicating all available flags here (and in the TS UI).
// Investigate this in the future.
public class Option : ManualCommandOptions
public sealed class Settings : ManualCommandSettings
{
// C++ Scaffolding
[CommandOption("--output-cpp-scaffolding")]
@@ -67,13 +69,27 @@ internal class ProcessCommand(PortProvider portProvider) : ManualCommand<Process
[CommandOption("--extract-il2cpp-files")]
public string? ExtractIl2CppFilesPath { get; init; }
[CommandOption("--image-base")]
public string? ImageBase { get; init; }
}
protected override async Task<int> ExecuteAsync(CliClient client, Option settings)
protected override async Task<int> ExecuteAsync(CliClient client, Settings settings)
{
var inspectorVersion = await client.GetInspectorVersion();
AnsiConsole.MarkupLineInterpolated($"Using inspector [gray]{inspectorVersion}[/]");
if (settings.ImageBase != null)
{
var imageBase = ulong.Parse(settings.ImageBase,
settings.ImageBase.StartsWith("0x")
? NumberStyles.HexNumber
: NumberStyles.Integer);
AnsiConsole.MarkupLineInterpolated($"Setting image base to [white]0x{imageBase:x}[/]");
await client.SetSettings(new InspectorSettings(imageBase));
}
await client.SubmitInputFiles(settings.InputPaths.ToList());
await client.WaitForLoadingToFinishAsync();
if (!client.ImportCompleted)
@@ -148,7 +164,7 @@ internal class ProcessCommand(PortProvider portProvider) : ManualCommand<Process
return 0;
}
public override ValidationResult Validate(CommandContext context, Option settings)
public override ValidationResult Validate(CommandContext context, Settings settings)
{
if (settings.UnityPath != null && !Path.Exists(settings.UnityPath))
return ValidationResult.Error($"Provided Unity path {settings.UnityPath} does not exist.");

View File

@@ -24,35 +24,40 @@ public class Il2CppHub : Hub
public async Task OnUiLaunched()
{
await State.Initialize(Client);
await State.InitializeAsync(Client);
}
public async Task SubmitInputFiles(List<string> inputFiles)
{
await State.LoadInputFiles(Client, inputFiles);
await State.LoadInputFilesAsync(Client, inputFiles);
}
public async Task QueueExport(string exportTypeId, string outputDirectory, Dictionary<string, string> settings)
{
await State.QueueExport(Client, exportTypeId, outputDirectory, settings);
await State.QueueExportAsync(Client, exportTypeId, outputDirectory, settings);
}
public async Task StartExport()
{
await State.StartExport(Client);
await State.StartExportAsync(Client);
}
public async Task<IEnumerable<string>> GetPotentialUnityVersions()
{
return await State.GetPotentialUnityVersions();
return await State.GetPotentialUnityVersionsAsync();
}
public async Task ExportIl2CppFiles(string outputDirectory)
{
await State.ExportIl2CppFiles(Client, outputDirectory);
await State.ExportIl2CppFilesAsync(Client, outputDirectory);
}
public async Task<string> GetInspectorVersion()
{
return await UiContext.GetInspectorVersion();
return await UiContext.GetInspectorVersionAsync();
}
public async Task SetSettings(InspectorSettings settings)
{
await State.SetSettingsAsync(Client, settings);
}
}

View File

@@ -0,0 +1,3 @@
namespace Il2CppInspector.Redux.FrontendCore;
public sealed record InspectorSettings(ulong ImageBase);

View File

@@ -26,7 +26,7 @@ public class UiContext
private readonly List<(string FormatId, string OutputDirectory, Dictionary<string, string> Settings)> _queuedExports = [];
private async Task<bool> TryLoadMetadataFromStream(UiClient client, MemoryStream stream)
private async Task<bool> TryLoadMetadataFromStreamAsync(UiClient client, MemoryStream stream)
{
try
{
@@ -41,7 +41,7 @@ public class UiContext
return false;
}
private async Task<bool> TryLoadBinaryFromStream(UiClient client, MemoryStream stream)
private async Task<bool> TryLoadBinaryFromStreamAsync(UiClient client, MemoryStream stream)
{
await client.ShowLogMessage("Processing binary");
@@ -64,7 +64,7 @@ public class UiContext
return false;
}
private async Task<bool> TryInitializeInspector(UiClient client)
private async Task<bool> TryInitializeInspectorAsync(UiClient client)
{
Debug.Assert(_binary != null);
Debug.Assert(_metadata != null);
@@ -117,12 +117,12 @@ public class UiContext
return true;
}
public async Task Initialize(UiClient client, CancellationToken cancellationToken = default)
public async Task InitializeAsync(UiClient client, CancellationToken cancellationToken = default)
{
await client.ShowSuccessToast("SignalR initialized!", cancellationToken);
}
public async Task LoadInputFiles(UiClient client, List<string> inputFiles,
public async Task LoadInputFilesAsync(UiClient client, List<string> inputFiles,
CancellationToken cancellationToken = default)
{
await using (await LoadingSession.Start(client))
@@ -132,10 +132,10 @@ public class UiContext
{
// The input files contained a package that provides the metadata and binary.
// Use these instead of parsing all files individually.
if (!await TryLoadMetadataFromStream(client, streams.Value.Metadata))
if (!await TryLoadMetadataFromStreamAsync(client, streams.Value.Metadata))
return;
if (!await TryLoadBinaryFromStream(client, streams.Value.Binary))
if (!await TryLoadBinaryFromStreamAsync(client, streams.Value.Binary))
return;
}
else
@@ -152,7 +152,7 @@ public class UiContext
if ( _metadata == null && PathHeuristics.IsMetadataPath(inputFile))
{
if (await TryLoadMetadataFromStream(client, stream))
if (await TryLoadMetadataFromStreamAsync(client, stream))
{
await client.ShowSuccessToast($"Loaded metadata (v{_metadata!.Version}) from {inputFile}", cancellationToken);
}
@@ -162,7 +162,7 @@ public class UiContext
stream.Position = 0;
_loadOptions.BinaryFilePath = inputFile;
if (await TryLoadBinaryFromStream(client, stream))
if (await TryLoadBinaryFromStreamAsync(client, stream))
{
await client.ShowSuccessToast($"Loaded binary from {inputFile}", cancellationToken);
}
@@ -172,7 +172,7 @@ public class UiContext
if (_metadata != null && _binary != null)
{
if (await TryInitializeInspector(client))
if (await TryInitializeInspectorAsync(client))
{
await client.ShowSuccessToast($"Successfully loaded IL2CPP (v{_appModels[0].Package.Version}) data!", cancellationToken);
await client.OnImportCompleted(cancellationToken);
@@ -181,14 +181,14 @@ public class UiContext
}
}
public Task QueueExport(UiClient client, string exportFormatId, string outputDirectory,
public Task QueueExportAsync(UiClient client, string exportFormatId, string outputDirectory,
Dictionary<string, string> settings, CancellationToken cancellationToken = default)
{
_queuedExports.Add((exportFormatId, outputDirectory, settings));
return Task.CompletedTask;
}
public async Task StartExport(UiClient client, CancellationToken cancellationToken = default)
public async Task StartExportAsync(UiClient client, CancellationToken cancellationToken = default)
{
// todo: support different app model selection (when loading packages)
Debug.Assert(_appModels.Count > 0);
@@ -217,12 +217,12 @@ public class UiContext
await client.ShowSuccessToast("Export finished", cancellationToken);
}
public Task<List<string>> GetPotentialUnityVersions()
public Task<List<string>> GetPotentialUnityVersionsAsync()
{
return Task.FromResult(_potentialUnityVersions.Select(x => x.VersionRange.Min.ToString()).ToList());
}
public async Task ExportIl2CppFiles(UiClient client, string outputDirectory, CancellationToken cancellationToken = default)
public async Task ExportIl2CppFilesAsync(UiClient client, string outputDirectory, CancellationToken cancellationToken = default)
{
Debug.Assert(_appModels.Count > 0);
var pkg = _appModels[0].Package;
@@ -244,8 +244,14 @@ public class UiContext
}
}
public static Task<string> GetInspectorVersion()
public static Task<string> GetInspectorVersionAsync()
{
return Task.FromResult(typeof(UiContext).Assembly.GetAssemblyVersion() ?? "<unknown>");
}
public Task SetSettingsAsync(UiClient client, InspectorSettings settings)
{
_loadOptions.ImageBase = settings.ImageBase;
return Task.CompletedTask;
}
}