diff --git a/.gitattributes b/.gitattributes index 903e5cd..6344b3b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,4 @@ # Patch files must stay LF: git apply matches context bytes against LF upstream sources *.patch -text +translator/tests/Translator.Tests/TestAssets/**/*.bin binary diff --git a/Launcher/Test-PinnedFacts.ps1 b/Launcher/Test-PinnedFacts.ps1 index bd65c84..d7b14bd 100644 --- a/Launcher/Test-PinnedFacts.ps1 +++ b/Launcher/Test-PinnedFacts.ps1 @@ -1,6 +1,6 @@ # Fails the release build when a fact duplicated across the repo stops agreeing with the copy # that owns it (recomp.yml). Scripts read pinned facts through Get-MkwProjectPins, but three -# consumers can't read YAML (the C++ runtime header, the C# constants, hand-written lists on +# consumers can't read YAML (the C++ runtime header, the C# constants, shell scripts, and hand-written lists on # both sides of the C#/PowerShell boundary), so those are checked here instead. [CmdletBinding()] param([string]$RepositoryRoot) @@ -58,6 +58,12 @@ $hostUri = Get-CapturedValue $retroWfcPayload 'CurrentRetroWfcPayloadUri\s*=\s*" if ($hostUri -cne $pins.RetroWfcPayloadUri) { Add-Failure "InputValidation.CurrentRetroWfcPayloadUri is '$hostUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'." } +$macosSetup = Read-SourceFile (Join-Path $launcher 'macos\setup.command') 'macOS setup.command' +$macosUri = Get-CapturedValue $macosSetup "'([^']*/api/wfc/payload\?g=RMCPD00)'" ` + 'The macOS Retro-WFC endpoint' +if ($macosUri -cne $pins.RetroWfcPayloadUri) { + Add-Failure "macOS setup.command downloads '$macosUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'." +} # --- The game identity: the manifest carries it, but the host also compiles a fallback for a # --- manifest that predates the field, and that fallback decides which disc is accepted. diff --git a/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs b/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs index 22d1c23..258fb85 100644 --- a/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs +++ b/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs @@ -24,7 +24,7 @@ public static class RetroWfcPayload private static readonly TimeSpan RetroWfcDownloadTimeout = TimeSpan.FromSeconds(30); private static readonly TimeSpan RetroWfcRetryDelay = TimeSpan.FromSeconds(1); - public const string CurrentRetroWfcPayloadUri = "http://nas.play.rwfc.net/payload?g=RMCPD00"; + public const string CurrentRetroWfcPayloadUri = "https://rwfc.net/api/wfc/payload?g=RMCPD00"; private static readonly string RetroWfcOfflinePayloadFile = Path.Combine("binary", "payload.RMCPD00.bin"); diff --git a/Launcher/macos/setup.command b/Launcher/macos/setup.command index 8676e7a..09c2915 100755 --- a/Launcher/macos/setup.command +++ b/Launcher/macos/setup.command @@ -90,7 +90,7 @@ if [[ -n "$retro_dir" ]]; then trap 'rm -rf "$payload_stage"' EXIT /usr/bin/curl --fail --silent --show-error --connect-timeout 10 --max-time 30 \ --retry 1 --output "$temporary_payload" \ - 'http://nas.play.rwfc.net/payload?g=RMCPD00' || fail 'could not download the Retro-WFC payload needed for online play' + 'https://rwfc.net/api/wfc/payload?g=RMCPD00' || fail 'could not download the Retro-WFC payload needed for online play' "$translator" validate-retro-wfc-payload --directory "$payload_stage" || \ fail 'downloaded Retro-WFC payload failed signature validation' mkdir -p "$retro_wfc_dir/binary" diff --git a/projects/mkwii/recomp.yml b/projects/mkwii/recomp.yml index bd8f727..20056ad 100644 --- a/projects/mkwii/recomp.yml +++ b/projects/mkwii/recomp.yml @@ -58,7 +58,7 @@ profiles: module_link_base: 0x803992E0 output: build/mods/retro_rewind_full_cpp enable_retro_wfc: true - retro_wfc_payload: http://nas.play.rwfc.net/payload?g=RMCPD00 + retro_wfc_payload: https://rwfc.net/api/wfc/payload?g=RMCPD00 retro_wfc_legacy_bootstrap_hook: 0x800ED6E8 riivolution: xml: xml/RetroRewind6.xml diff --git a/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs b/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs index 4a11b0d..e5fe310 100644 --- a/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs +++ b/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs @@ -35,6 +35,39 @@ public class RetroWfcPayloadLoweringTests Assert.Equal("moduleFunction", pointer.TargetKind); } + [Fact] + public void ProductionPayloadValidatesAndTranslatesEverySupportedPatch() + { + var payloadRoot = Path.Combine( + AppContext.BaseDirectory, + "TestAssets", + "RetroWfcPayload"); + WiiCompiled.Setup.Common.RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(payloadRoot); + var payloadPath = Path.Combine( + payloadRoot, + "binary", + "payload.RMCPD00.bin"); + var payload = File.ReadAllBytes(payloadPath); + + var result = RetroWfcPayload.Parse( + payload, + ProductionPayloadManifest(), + 0x81800000u, + 0x00200000u, + "TestAssets/RetroWfcPayload/binary/payload.RMCPD00.bin"); + + Assert.Equal("RMCPD00", result.Summary.Game); + Assert.Equal(payload.Length, result.Summary.PayloadImageSize); + Assert.True(result.LoweringPlan.IsPlannable); + Assert.Empty(result.LoweringPlan.Issues); + Assert.NotEmpty(result.LoweringPlan.StaticBytePatches); + Assert.NotEmpty(result.LoweringPlan.ExecutableHooks); + Assert.NotEmpty(result.LoweringPlan.StaticPointers); + Assert.All(result.LoweringPlan.ExecutableHooks, hook => Assert.NotNull(hook.TargetAddress)); + Assert.All(result.LoweringPlan.StaticPointers, pointer => Assert.NotNull(pointer.TargetAddress)); + Assert.NotEmpty(result.Summary.InitializationCallbacks); + } + private static BaseManifest TestManifest() => new( "test", @@ -52,6 +85,51 @@ public class RetroWfcPayloadLoweringTests ], "ranges.json"); + // The payload parser needs the base image's address classes and containing + // function ranges to prove every patch can be lowered. A single synthetic + // executable and writable ranges are sufficient here: the assertions above + // test the real production payload without checking proprietary game bytes + // into CI. The split also proves pointer patches lower as data writes. + private static BaseManifest ProductionPayloadManifest() => + new( + "test", + 1, + "RMCP01", + "P", + "", + 0, + [ + new BaseSectionMetadata( + ".synthetic-text", + "synthetic.dol", + 0x80000000u, + 0x80800000u, + true, + false, + "synthetic_text.bin", + 0), + new BaseSectionMetadata( + ".synthetic-data", + "synthetic.dol", + 0x80800000u, + 0x81000000u, + false, + true, + "synthetic_data.bin", + 0) + ], + [ + new BaseFunctionRangeMetadata( + 0x80000000u, + 0x80800000u, + "synthetic_base", + ".synthetic-text", + 0, + "test", + ["Executable"]) + ], + "ranges.json"); + private static byte[] BuildSharedPayloadFixture() { var payload = new byte[0x240]; diff --git a/translator/tests/Translator.Tests/TestAssets/RetroWfcPayload/binary/payload.RMCPD00.bin b/translator/tests/Translator.Tests/TestAssets/RetroWfcPayload/binary/payload.RMCPD00.bin new file mode 100644 index 0000000..fd7ecd8 Binary files /dev/null and b/translator/tests/Translator.Tests/TestAssets/RetroWfcPayload/binary/payload.RMCPD00.bin differ diff --git a/translator/tests/Translator.Tests/Translator.Tests.csproj b/translator/tests/Translator.Tests/Translator.Tests.csproj index 4e37ccd..dccdafe 100644 --- a/translator/tests/Translator.Tests/Translator.Tests.csproj +++ b/translator/tests/Translator.Tests/Translator.Tests.csproj @@ -26,6 +26,11 @@ + + + + +