180 lines
6.6 KiB
C#
180 lines
6.6 KiB
C#
using gregExtractor.Models;
|
|
using gregExtractor.Services;
|
|
using gregExtractor.Utils;
|
|
|
|
namespace gregExtractor.Commands;
|
|
|
|
public sealed class SyncCommand : AsyncCommand<SyncCommand.Settings>
|
|
{
|
|
public sealed class Settings : CommandSettings
|
|
{
|
|
[CommandOption("--source <FRAMEWORK_SOURCE_DIR>")]
|
|
public string Source { get; init; } = string.Empty;
|
|
|
|
[CommandOption("--dry-run")]
|
|
public bool DryRun { get; init; }
|
|
|
|
[CommandOption("--git")]
|
|
public bool UseGitDiff { get; init; }
|
|
|
|
[CommandOption("--force")]
|
|
public bool Force { get; init; }
|
|
|
|
public override ValidationResult Validate()
|
|
{
|
|
return string.IsNullOrWhiteSpace(Source)
|
|
? ValidationResult.Error("--source ist erforderlich.")
|
|
: ValidationResult.Success();
|
|
}
|
|
}
|
|
|
|
public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
|
|
{
|
|
AnsiConsole.Write(new FigletText("Sync").Color(Color.Yellow));
|
|
|
|
if (!settings.DryRun && !settings.Force)
|
|
{
|
|
bool confirmed = AnsiConsole.Confirm(
|
|
"⚠️ Dies schreibt direkt in deinen Framework-Quellcode!\nBackups werden angelegt. Fortfahren?",
|
|
false);
|
|
|
|
if (!confirmed)
|
|
{
|
|
AnsiConsole.MarkupLine("[yellow]Abgebrochen.[/]");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
string workingDirectory = Directory.GetCurrentDirectory();
|
|
string hooksPath = Path.Combine(workingDirectory, "game_hooks.json");
|
|
string groupsPath = Path.Combine(workingDirectory, "hook_groups.json");
|
|
|
|
if (!File.Exists(hooksPath))
|
|
{
|
|
AnsiConsole.MarkupLine($"[red]Vorheriger Zustand fehlt:[/] {Markup.Escape(hooksPath)}");
|
|
return -1;
|
|
}
|
|
|
|
HookDefinition[] oldHooks = JsonSerializer.Deserialize<HookDefinition[]>(await File.ReadAllTextAsync(hooksPath).ConfigureAwait(false))
|
|
?? Array.Empty<HookDefinition>();
|
|
|
|
HookClassifier classifier = HookClassifier.LoadFromFile(groupsPath, new Progress<string>(_ => { }));
|
|
|
|
string? il2CppPath = SteamLocator.FindIl2CppAssembliesPath();
|
|
if (string.IsNullOrWhiteSpace(il2CppPath) || !Directory.Exists(il2CppPath))
|
|
{
|
|
AnsiConsole.MarkupLine("[yellow]IL2CPP-Pfad konnte nicht automatisch gefunden werden.[/]");
|
|
il2CppPath = AnsiConsole.Ask<string>("Pfad zu Il2CppAssemblies:");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(il2CppPath) || !Directory.Exists(il2CppPath))
|
|
{
|
|
AnsiConsole.MarkupLine("[red]Ungültiger IL2CPP-Pfad.[/]");
|
|
return -1;
|
|
}
|
|
|
|
var extractor = new ExtractorService();
|
|
var diffService = new DiffService();
|
|
var syncService = new FrameworkSyncService();
|
|
|
|
var logLines = new List<string>();
|
|
var progress = new Progress<string>(line => logLines.Add(line));
|
|
|
|
IReadOnlyList<HookDefinition> newHooks = Array.Empty<HookDefinition>();
|
|
HookDiff diff = new(Array.Empty<HookDefinition>(), Array.Empty<HookDefinition>(), Array.Empty<HookDefinition>());
|
|
|
|
await AnsiConsole.Status()
|
|
.Spinner(Spinner.Known.Dots)
|
|
.StartAsync("Berechne Assembly-Diff...", async _ =>
|
|
{
|
|
newHooks = await extractor.ExtractAsync(il2CppPath, classifier, progress, CancellationToken.None).ConfigureAwait(false);
|
|
diff = diffService.Diff(oldHooks.ToList(), newHooks.ToList());
|
|
})
|
|
.ConfigureAwait(false);
|
|
|
|
var summary = new Table().RoundedBorder();
|
|
summary.Title = new TableTitle("Assembly Diff");
|
|
summary.AddColumn("Typ");
|
|
summary.AddColumn("Anzahl");
|
|
summary.AddRow("+ Neue Methoden", diff.Added.Count.ToString());
|
|
summary.AddRow("~ Signaturen geändert", diff.Changed.Count.ToString());
|
|
summary.AddRow("- Methoden entfernt", diff.Removed.Count.ToString());
|
|
AnsiConsole.Write(summary);
|
|
|
|
SyncResult result = syncService.Sync(new SyncOptions(
|
|
FrameworkSourceDir: settings.Source,
|
|
Diff: diff,
|
|
AllHooks: newHooks.ToList(),
|
|
DryRun: settings.DryRun,
|
|
Progress: progress));
|
|
|
|
foreach (string line in logLines)
|
|
AnsiConsole.MarkupLine($"[grey]{Markup.Escape(line)}[/]");
|
|
|
|
foreach (string file in result.FilesWritten)
|
|
AnsiConsole.MarkupLine($"[green]✓[/] {Markup.Escape(Path.GetFileName(file))}");
|
|
|
|
foreach (string warning in result.Warnings)
|
|
AnsiConsole.MarkupLine($"[yellow]{Markup.Escape(warning)}[/]");
|
|
|
|
if (!settings.DryRun)
|
|
{
|
|
await File.WriteAllTextAsync(
|
|
hooksPath,
|
|
JsonSerializer.Serialize(newHooks, new JsonSerializerOptions { WriteIndented = true }),
|
|
CancellationToken.None)
|
|
.ConfigureAwait(false);
|
|
}
|
|
|
|
if (settings.UseGitDiff)
|
|
{
|
|
try
|
|
{
|
|
string gitOutput = await RunGitDiffStatAsync(settings.Source).ConfigureAwait(false);
|
|
if (!string.IsNullOrWhiteSpace(gitOutput))
|
|
{
|
|
AnsiConsole.MarkupLine("[cyan]git diff --stat[/]");
|
|
AnsiConsole.WriteLine(gitOutput);
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
AnsiConsole.MarkupLine($"[yellow]Git-Diff konnte nicht gelesen werden:[/] {Markup.Escape(exception.Message)}");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static async Task<string> RunGitDiffStatAsync(string frameworkSourceDir)
|
|
{
|
|
string workingDirectory = Directory.Exists(frameworkSourceDir)
|
|
? frameworkSourceDir
|
|
: Directory.GetCurrentDirectory();
|
|
|
|
var process = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = "git",
|
|
Arguments = "diff --stat",
|
|
WorkingDirectory = workingDirectory,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
},
|
|
};
|
|
|
|
process.Start();
|
|
string output = await process.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
|
|
string error = await process.StandardError.ReadToEndAsync().ConfigureAwait(false);
|
|
await process.WaitForExitAsync().ConfigureAwait(false);
|
|
|
|
if (process.ExitCode != 0)
|
|
return string.IsNullOrWhiteSpace(error) ? output : error;
|
|
|
|
return output;
|
|
}
|
|
}
|