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 @@
+
+
+
+
+