mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-09-13 01:55:57 -04:00
switch to standalone nod tool rather than dolphin-tool
This commit is contained in:
@@ -63,8 +63,8 @@ internal static class ConsoleCommands
|
||||
{
|
||||
using var payload = PayloadArchive.OpenCurrent();
|
||||
var manifest = payload.ReadManifest();
|
||||
var tool = Path.Combine(temp, "DolphinTool.exe");
|
||||
payload.ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "DolphinTool.exe", tool);
|
||||
var tool = Path.Combine(temp, "nodtool.exe");
|
||||
payload.ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "nodtool.exe", tool);
|
||||
payload.ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", temp);
|
||||
reporter?.Progress(InstallStages.Validate, "Checking the Wii disc image...", 10);
|
||||
var header = InputValidation.ReadDiscHeaderAsync(tool, command.GamePath!).GetAwaiter().GetResult();
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using WiiCompiled.NodTool;
|
||||
|
||||
namespace WiiCompiled.Setup;
|
||||
|
||||
@@ -47,23 +48,37 @@ internal static class InputValidation
|
||||
"Select a complete Wii disc image in ISO, GCM, GCZ, CISO, WBFS, WIA, or RVZ format.");
|
||||
}
|
||||
|
||||
public static async Task<DiscHeader> ReadDiscHeaderAsync(string dolphinTool, string gamePath,
|
||||
public static async Task<DiscHeader> ReadDiscHeaderAsync(string nodTool, string gamePath,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateExtension(gamePath);
|
||||
var result = await ProcessRunner.RunAsync(dolphinTool,
|
||||
["header", "-i", Path.GetFullPath(gamePath), "-j"], null, cancellationToken);
|
||||
var result = await ProcessRunner.RunAsync(nodTool,
|
||||
["info", Path.GetFullPath(gamePath)], null, cancellationToken);
|
||||
if (result.ExitCode != 0)
|
||||
throw new InvalidDataException("DolphinTool could not read this disc image. " + result.CombinedOutput.Trim());
|
||||
throw new InvalidDataException("nodtool could not read this disc image. " + result.CombinedOutput.Trim());
|
||||
|
||||
var json = result.StandardOutput.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)
|
||||
.FirstOrDefault(line => line.TrimStart().StartsWith('{'));
|
||||
if (json is null)
|
||||
throw new InvalidDataException("DolphinTool did not return disc metadata.");
|
||||
return JsonSerializer.Deserialize<DiscHeader>(json)
|
||||
?? throw new InvalidDataException("DolphinTool returned invalid disc metadata.");
|
||||
var info = NodToolInfoParser.Parse(result.StandardOutput);
|
||||
return new DiscHeader
|
||||
{
|
||||
GameId = info.GameId,
|
||||
InternalName = info.Title,
|
||||
Region = RegionFromGameId(info.GameId),
|
||||
Revision = info.Revision,
|
||||
};
|
||||
}
|
||||
|
||||
private static string RegionFromGameId(string gameId) => gameId.Length >= 4
|
||||
? gameId[3] switch
|
||||
{
|
||||
'P' => "PAL",
|
||||
'E' => "NTSC-U",
|
||||
'J' => "NTSC-J",
|
||||
'K' => "Korea",
|
||||
'W' => "Taiwan",
|
||||
_ => gameId[3].ToString(),
|
||||
}
|
||||
: "Unknown";
|
||||
|
||||
public static void EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest)
|
||||
{
|
||||
if (!header.GameId.Equals(manifest.ExpectedGameId, StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -57,9 +57,9 @@ internal sealed class InstallerEngine
|
||||
|
||||
var runtimeAssetsCurrent = sameToolkit && RuntimeAssetsAreCurrent(existing,
|
||||
candidateRuntimeAssetsFingerprint, cancellationToken);
|
||||
var installedDolphinTool = Path.Combine(existing.ToolkitDirectory, "DolphinTool.exe");
|
||||
var installedNodTool = Path.Combine(existing.ToolkitDirectory, "nodtool.exe");
|
||||
var extractToolkit = MustRefreshToolkit(sameToolkit, samePackageContent,
|
||||
File.Exists(installedDolphinTool));
|
||||
File.Exists(installedNodTool));
|
||||
var extractWorkspace = !sameToolkit || !runtimeAssetsCurrent;
|
||||
|
||||
_reporter.Progress(InstallStages.ExtractToolkit,
|
||||
@@ -77,9 +77,9 @@ internal sealed class InstallerEngine
|
||||
payload.ExtractEntry(InstalledLayout.PayloadManifestFileName,
|
||||
Path.Combine(staging, InstalledLayout.PayloadManifestFileName));
|
||||
|
||||
var dolphinTool = extractToolkit ? Path.Combine(toolkit, "DolphinTool.exe") : installedDolphinTool;
|
||||
var nodTool = extractToolkit ? Path.Combine(toolkit, "nodtool.exe") : installedNodTool;
|
||||
_reporter.Progress(InstallStages.Validate, "Checking the Wii disc image...", 2);
|
||||
var header = await InputValidation.ReadDiscHeaderAsync(dolphinTool, options.GamePath,
|
||||
var header = await InputValidation.ReadDiscHeaderAsync(nodTool, options.GamePath,
|
||||
cancellationToken);
|
||||
InputValidation.EnsureCompatibleDisc(header, manifest);
|
||||
var canonicalRetroRoot = options.RetroDirectoryPath is null
|
||||
@@ -153,7 +153,7 @@ internal sealed class InstallerEngine
|
||||
|
||||
if (reusableGameAssets is null)
|
||||
{
|
||||
await ExtractGameAssetsAsync(dolphinTool, options.GamePath,
|
||||
await ExtractGameAssetsAsync(nodTool, options.GamePath,
|
||||
Path.Combine(staging, "GameAssets"), manifest, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -164,8 +164,8 @@ internal sealed class InstallerEngine
|
||||
|
||||
|
||||
internal static bool MustRefreshToolkit(bool sameToolkit, bool samePackageContent,
|
||||
bool dolphinToolPresent) =>
|
||||
!sameToolkit || !samePackageContent || !dolphinToolPresent;
|
||||
bool nodToolPresent) =>
|
||||
!sameToolkit || !samePackageContent || !nodToolPresent;
|
||||
|
||||
private static void AddComponent(List<InstallTransactionEntry> entries, string staging,
|
||||
string installDirectory, string name) =>
|
||||
@@ -469,18 +469,23 @@ internal sealed class InstallerEngine
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExtractGameAssetsAsync(string dolphinTool, string gamePath, string destination,
|
||||
private async Task ExtractGameAssetsAsync(string nodTool, string gamePath, string destination,
|
||||
PayloadManifest manifest, CancellationToken cancellationToken)
|
||||
{
|
||||
_reporter.Progress(InstallStages.ExtractDisc,
|
||||
"Extracting the game disc. This is the longest preparation step...", 6);
|
||||
var extraction = await ProcessRunner.RunAsync(dolphinTool,
|
||||
["extract", "-i", Path.GetFullPath(gamePath), "-o", destination, "-g", "-q"],
|
||||
// Extracted straight into a "DATA" subfolder so the on-disk layout matches what
|
||||
// Installation.GameDataDirectory and every other reader of it already expect - nodtool
|
||||
// itself has no such wrapper (it extracts sys/+files/ directly to whatever <outdir> is
|
||||
// given), so this is purely destination-side, not a nodtool convention.
|
||||
var dataRoot = Path.Combine(destination, "DATA");
|
||||
var extraction = await ProcessRunner.RunAsync(nodTool,
|
||||
["extract", Path.GetFullPath(gamePath), dataRoot, "-q"],
|
||||
line => { if (!string.IsNullOrWhiteSpace(line)) _reporter.Diagnostic(line); },
|
||||
cancellationToken);
|
||||
if (extraction.ExitCode != 0)
|
||||
throw new InvalidDataException("Game extraction failed. " + extraction.CombinedOutput.Trim());
|
||||
ValidateExtractedGame(Path.Combine(destination, "DATA"), manifest);
|
||||
ValidateExtractedGame(dataRoot, manifest);
|
||||
}
|
||||
|
||||
private static void ValidateExtractedGame(string dataRoot, PayloadManifest manifest)
|
||||
|
||||
@@ -143,17 +143,17 @@ internal static class SelfTests
|
||||
private static void TestToolkitRefreshDecision()
|
||||
{
|
||||
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: false, samePackageContent: true,
|
||||
dolphinToolPresent: true))
|
||||
nodToolPresent: true))
|
||||
throw new Exception("A republished workspace kept the installed toolkit; the shipped " +
|
||||
"translator and project file could come from different releases.");
|
||||
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: false,
|
||||
dolphinToolPresent: true))
|
||||
nodToolPresent: true))
|
||||
throw new Exception("Changed toolkit package content was not extracted.");
|
||||
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: true,
|
||||
dolphinToolPresent: false))
|
||||
throw new Exception("A missing DolphinTool.exe did not force toolkit extraction.");
|
||||
nodToolPresent: false))
|
||||
throw new Exception("A missing nodtool.exe did not force toolkit extraction.");
|
||||
if (InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: true,
|
||||
dolphinToolPresent: true))
|
||||
nodToolPresent: true))
|
||||
throw new Exception("An unchanged toolkit was needlessly re-extracted.");
|
||||
}
|
||||
|
||||
@@ -1010,7 +1010,7 @@ internal static class SelfTests
|
||||
throw new Exception("The toolkit fingerprint is not stable.");
|
||||
|
||||
// A file that has nothing to do with generated code must not invalidate every install.
|
||||
File.WriteAllText(Path.Combine(root, "Toolkit", "DolphinTool.exe"), "irrelevant");
|
||||
File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "irrelevant");
|
||||
if (ToolkitFingerprint.Compute(root) != first)
|
||||
throw new Exception("An unrelated toolkit file changed the fingerprint.");
|
||||
|
||||
@@ -1177,7 +1177,7 @@ internal static class SelfTests
|
||||
"x86_64-w64-mingw32-clang++.exe", "x86_64-w64-mingw32-windres.exe"
|
||||
})
|
||||
File.WriteAllText(Path.Combine(root, "Toolkit", "llvm-mingw", "bin", executable), executable);
|
||||
File.WriteAllText(Path.Combine(root, "Toolkit", "DolphinTool.exe"), "tool");
|
||||
File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "tool");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "LocalBuild.ps1"), "# build");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "NativeBuildFlags.ps1"), "# flags");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", "mkwii", "recomp.yml"), "profiles: {}");
|
||||
|
||||
@@ -78,12 +78,12 @@ internal static class ToolkitFingerprint
|
||||
var workspace = InstalledLayout.Workspace(root);
|
||||
var entries = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
|
||||
// DolphinTool validates/extracts the user disc but does not influence generated products.
|
||||
// nodtool validates/extracts the user disc but does not influence generated products.
|
||||
// Everything else in Toolkit can affect translation, compilation, linking, or copied
|
||||
// runtime support and therefore belongs to the compile identity.
|
||||
AddDirectory(entries, root, toolkit, null,
|
||||
cancellationToken,
|
||||
file => !Path.GetFileName(file).Equals("DolphinTool.exe", StringComparison.OrdinalIgnoreCase));
|
||||
file => !Path.GetFileName(file).Equals("nodtool.exe", StringComparison.OrdinalIgnoreCase));
|
||||
AddFile(entries, root, Path.Combine(workspace, "LocalBuild.ps1"), cancellationToken);
|
||||
AddFile(entries, root, Path.Combine(workspace, "NativeBuildFlags.ps1"), cancellationToken);
|
||||
AddDirectory(entries, root, Path.Combine(workspace, "projects"), null, cancellationToken);
|
||||
|
||||
@@ -14,4 +14,7 @@
|
||||
<DebugType>embedded</DebugType>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WiiCompiled.NodTool\WiiCompiled.NodTool.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user