NTSC-U and NTSC-J support (#326)

* add ntsc-u and ntsc-j support

Co-authored-by: DarthMDev <mgracer48@yahoo.com>
Co-authored-by: rooklz <rookieb@muzo-works.com>

* hash inc files and require project for shards

* port remaining stale rr us hooks

* drop map report generation

* drop one-off region porters

---------

Co-authored-by: DarthMDev <mgracer48@yahoo.com>
Co-authored-by: rooklz <rookieb@muzo-works.com>
This commit is contained in:
patchzyy
2026-10-21 17:37:44 +02:00
committed by GitHub
parent ad95c5c7da
commit e9f1fdd77c
95 changed files with 64733 additions and 646 deletions
+32 -15
View File
@@ -11,29 +11,30 @@ namespace WiiCompiled.Setup.Linux;
/// </summary>
internal static class DiscTool
{
public static async Task ValidateAndExtractAsync(
string isoPath, ProjectManifest manifest, string assetsDirectory, string workspace,
/// <summary>Validates and extracts the disc, returning the supported release it is.</summary>
public static async Task<ProjectManifest> ValidateAndExtractAsync(
string isoPath, IReadOnlyList<ProjectManifest> releases, string assetsDirectory, string workspace,
string? nodToolBin, IInstallReporter reporter, CancellationToken cancellationToken)
{
if (IsAlreadyExtracted(manifest, assetsDirectory))
{
reporter.Progress(InstallStages.ExtractDisc, "Reusing the verified extracted disc", 6);
return;
}
var nodTool = nodToolBin ?? await NodToolProvider.ResolveAsync(workspace, cancellationToken);
// `nodtool info` only decodes the disc/partition headers (milliseconds); `nodtool extract`
// copies the whole data partition to disk (tens of seconds for a custom-track-heavy MKWii
// ISO). Checking the game ID first, before extracting, means a wrong disc fails fast -
// matching the original dolphin-tool `header` step this replaces.
// ISO). The game ID picks the release, so a wrong disc fails fast and an existing
// extraction is only reused for the same release.
reporter.Progress(InstallStages.ExtractDisc, "Reading the disc header", 2);
var info = NodToolInfoParser.Parse(await RunInfoAsync(nodTool, isoPath, cancellationToken));
if (!string.Equals(info.GameId, manifest.GameId, StringComparison.Ordinal))
var manifest = releases.FirstOrDefault(release =>
string.Equals(info.GameId, release.GameId, StringComparison.Ordinal))
?? throw new InvalidOperationException(
$"This disc is '{info.GameId}', which is not a supported Mario Kart Wii release " +
$"({ProjectManifest.Describe(releases)}). " +
"Only your own legally-owned copy of a supported game/region can be used.");
if (IsAlreadyExtracted(manifest, assetsDirectory))
{
throw new InvalidOperationException(
$"This disc is '{info.GameId}', not the expected '{manifest.GameId}' (Mario Kart Wii, region {manifest.Region}). " +
"Only your own legally-owned copy of that exact game/region can be used.");
reporter.Progress(InstallStages.ExtractDisc, "Reusing the verified extracted disc", 6);
return manifest;
}
// Extracted straight into Assets/DATA (kept, not a scratch dir) - the runtime reads course/
@@ -71,6 +72,22 @@ internal static class DiscTool
File.Copy(relPath, Path.Combine(assetsDirectory, "StaticR.rel"), overwrite: true);
File.WriteAllText(Path.Combine(assetsDirectory, ExtractionMarker), ExtractionRecord(dolSha, dataDir));
reporter.Progress(InstallStages.ExtractDisc, "Disc validated and extracted", 6);
return manifest;
}
/// <summary>The release already extracted into Assets, chosen by its main.dol like local-build.sh.</summary>
public static ProjectManifest SelectExtracted(IReadOnlyList<ProjectManifest> releases, string assetsDirectory)
{
var dolSha = Sha256Of(Path.Combine(assetsDirectory, "main.dol"));
var manifest = releases.FirstOrDefault(release => string.Equals(dolSha, release.DolSha256, StringComparison.Ordinal))
?? throw new InvalidOperationException(
$"Assets/main.dol (sha256 {dolSha}) is not a supported clean Mario Kart Wii release " +
$"({ProjectManifest.Describe(releases)}).");
var relSha = Sha256Of(Path.Combine(assetsDirectory, "StaticR.rel"));
if (!string.Equals(relSha, manifest.RelSha256, StringComparison.Ordinal))
throw new InvalidOperationException(
$"Assets/StaticR.rel does not match the clean {manifest.GameId} release of Assets/main.dol.");
return manifest;
}
private static async Task<string> RunInfoAsync(string nodTool, string isoPath, CancellationToken cancellationToken)
@@ -97,7 +114,7 @@ internal static class DiscTool
private const string ExtractionMarker = ".disc-extracted";
// Only one disc revision is accepted, so a completed, verified extraction is identical to a fresh one.
// Each release has one accepted revision, so a completed, verified extraction is identical to a fresh one.
private static bool IsAlreadyExtracted(ProjectManifest manifest, string assetsDirectory)
{
var marker = Path.Combine(assetsDirectory, ExtractionMarker);