mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 01:00:14 +02:00
Added Support for VR in Launcher Setup
This commit is contained in:
1 parent
d86dcb0aeb
commit
5caec70da9
28 files changed
+397
-157
No files matched your search
+32
-127
@@ -1,160 +1,65 @@
|
|||||||
name: Package installers
|
name: Package WiiCompiled OpenXR VR
|
||||||
|
|
||||||
# Builds the per-platform installer/setup tool (WiiCompiled-Setup.exe /
|
|
||||||
# WiiCompiled-Setup-x86_64.AppImage) via Launcher/Build-Installer.ps1 and
|
|
||||||
# Launcher/build-appimage.sh respectively - the same scripts a maintainer runs by hand today to
|
|
||||||
# produce a GitHub Release asset. This does NOT build the actual translated game executable:
|
|
||||||
# that step requires the end user's own Mario Kart Wii dump (Assets/main.dol, Assets/StaticR.rel),
|
|
||||||
# which is proprietary and not present in this repository or in CI.
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags: ['v*']
|
||||||
- '*'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: package-${{ github.workflow }}-${{ github.ref }}
|
group: package-vr-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
recompilation:
|
recompilation:
|
||||||
name: Recompilation test
|
|
||||||
uses: ./.github/workflows/recomp-test.yml
|
uses: ./.github/workflows/recomp-test.yml
|
||||||
|
windows:
|
||||||
linux-appimage:
|
|
||||||
name: Linux (AppImage, ${{ matrix.arch }})
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- runner: ubuntu-22.04
|
|
||||||
arch: x86_64
|
|
||||||
- runner: ubuntu-22.04-arm
|
|
||||||
arch: aarch64
|
|
||||||
runs-on: ${{ matrix.runner }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v6
|
|
||||||
with:
|
|
||||||
dotnet-version: '8.0.x'
|
|
||||||
|
|
||||||
# appimagetool ships as an AppImage itself and needs to self-mount via FUSE to run directly;
|
|
||||||
# GitHub's ubuntu-latest runners don't have libfuse2 preinstalled.
|
|
||||||
- name: Install dependencies (required by appimagetool and SDL3 build)
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libfuse2 build-essential git make \
|
|
||||||
pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
|
|
||||||
libaudio-dev libfribidi-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
|
|
||||||
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev \
|
|
||||||
libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
|
|
||||||
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev libthai-dev libusb-1.0-0-dev \
|
|
||||||
libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev
|
|
||||||
|
|
||||||
- name: Build AppImage
|
|
||||||
run: bash Launcher/build-appimage.sh
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: WiiCompiled-Setup-linux-${{ matrix.arch }}
|
|
||||||
path: Launcher/dist/WiiCompiled-Setup-${{ matrix.arch }}.AppImage
|
|
||||||
if-no-files-found: error
|
|
||||||
archive: false
|
|
||||||
|
|
||||||
windows-installer:
|
|
||||||
name: Windows (installer exe)
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v6
|
- uses: actions/setup-dotnet@v6
|
||||||
with:
|
with:
|
||||||
dotnet-version: '8.0.x'
|
dotnet-version: '8.0.x'
|
||||||
|
- name: Verify release version
|
||||||
- name: Build installer
|
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: ./Launcher/Build-Installer.ps1
|
env:
|
||||||
|
RELEASE_TAG: ${{ startsWith(github.ref, 'refs/tags/v') && github.ref_name || '' }}
|
||||||
|
run: ./Launcher/Verify-Release.ps1 -Tag $env:RELEASE_TAG
|
||||||
|
- name: Test translator
|
||||||
|
run: dotnet test translator/Translator.sln -c Release
|
||||||
|
- name: Build and audit setup payload
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
./Launcher/Build-Installer.ps1
|
||||||
|
./Launcher/Verify-Release.ps1 -SetupPath (Resolve-Path Launcher/dist/WiiCompiled-Setup.exe)
|
||||||
|
./Launcher/dist/WiiCompiled-Setup.exe --self-test
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw 'Setup self-tests failed.' }
|
||||||
|
$hash = (Get-FileHash Launcher/dist/WiiCompiled-Setup.exe -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||||
|
"$hash WiiCompiled-Setup.exe" | Set-Content Launcher/dist/SHA256SUMS.txt
|
||||||
- uses: actions/upload-artifact@v7
|
- uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: WiiCompiled-Setup-windows-x64
|
name: WiiCompiled-OpenXR-VR-windows-x64
|
||||||
path: Launcher/dist/WiiCompiled-Setup.exe
|
path: |
|
||||||
|
Launcher/dist/WiiCompiled-Setup.exe
|
||||||
|
Launcher/dist/SHA256SUMS.txt
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
archive: false
|
|
||||||
|
|
||||||
# Publishes the packaged installers as a GitHub Release whenever a v* tag is pushed. Wheel Wizard
|
|
||||||
# discovers updates from these releases, so the contract it relies on is enforced here: a full
|
|
||||||
# (non-prerelease) release whose tag is v<semver>, carrying an asset named exactly
|
|
||||||
# WiiCompiled-Setup.exe, produced by a setup host that reports that same version.
|
|
||||||
release:
|
release:
|
||||||
name: Publish GitHub Release
|
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
needs: [linux-appimage, windows-installer, recompilation]
|
needs: [windows, recompilation]
|
||||||
runs-on: ubuntu-latest
|
runs-on: windows-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
# Wheel Wizard runs the downloaded setup with --version and refuses it when the reported
|
|
||||||
# version differs from the release tag, so a tag that was pushed without bumping every pinned
|
|
||||||
# version would ship an update nobody can install. Catch that before anything is published.
|
|
||||||
- name: Verify the tag matches the pinned setup version
|
|
||||||
env:
|
|
||||||
TAG: ${{ github.ref_name }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
version="${TAG#v}"
|
|
||||||
status=0
|
|
||||||
check() {
|
|
||||||
if ! grep -Fq "$2" "$1"; then
|
|
||||||
echo "::error file=$1::expected '$2' for tag $TAG"
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
check Launcher/WiiCompiled.Setup.Windows/Program.cs "public const string Version = \"$version\";"
|
|
||||||
check Launcher/WiiCompiled.Setup.Windows/WiiCompiled.Setup.Windows.csproj "<Version>$version</Version>"
|
|
||||||
check Launcher/Build-Installer.ps1 "ProductVersion = '$version'"
|
|
||||||
exit $status
|
|
||||||
|
|
||||||
# The build jobs upload with `archive: false`, which stores each installer as a raw file
|
|
||||||
# rather than a zip (and names the artifact after the file). Only download-artifact v8 and
|
|
||||||
# later understand such direct uploads; v7 tries to unzip everything and fails on them.
|
|
||||||
- uses: actions/download-artifact@v8
|
- uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
|
name: WiiCompiled-OpenXR-VR-windows-x64
|
||||||
path: artifacts
|
path: artifacts
|
||||||
merge-multiple: true
|
- name: Publish Windows setup
|
||||||
|
shell: pwsh
|
||||||
- name: Publish release
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.ref_name }}
|
TAG: ${{ github.ref_name }}
|
||||||
|
REPOSITORY: ${{ github.repository }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
gh release create $env:TAG artifacts/WiiCompiled-Setup.exe artifacts/SHA256SUMS.txt --repo $env:REPOSITORY --verify-tag --title "WiiCompiled OpenXR VR $env:TAG (beta)" --notes "Windows x64 OpenXR beta. Install through WheelWizard VR. Requires your own clean PAL RMCP01 disc image; game code and assets are compiled locally."
|
||||||
ls -lR artifacts
|
if ($LASTEXITCODE -ne 0) { throw 'Release publication failed.' }
|
||||||
assets=()
|
|
||||||
for name in WiiCompiled-Setup.exe WiiCompiled-Setup-x86_64.AppImage WiiCompiled-Setup-aarch64.AppImage; do
|
|
||||||
found="$(find artifacts -type f -name "$name" | head -n 1)"
|
|
||||||
[ -n "$found" ] && [ -s "$found" ] || { echo "::error::missing release asset $name"; exit 1; }
|
|
||||||
assets+=("$found")
|
|
||||||
done
|
|
||||||
# A re-run of a tag whose release already exists only refreshes the assets.
|
|
||||||
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
|
||||||
gh release upload "$TAG" "${assets[@]}" --repo "$GITHUB_REPOSITORY" --clobber
|
|
||||||
else
|
|
||||||
gh release create "$TAG" "${assets[@]}" \
|
|
||||||
--repo "$GITHUB_REPOSITORY" \
|
|
||||||
--title "$TAG" \
|
|
||||||
--verify-tag \
|
|
||||||
--generate-notes
|
|
||||||
fi
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Windows VR distribution
|
||||||
|
|
||||||
|
Distribute only `WiiCompiled-Setup.exe` and its checksum from
|
||||||
|
[iChris4/Wiicompiled_VR](https://github.com/iChris4/Wiicompiled_VR/releases), and
|
||||||
|
`WheelWizardVRWindows.exe` from [iChris4/WheelWizard_VR](https://github.com/iChris4/WheelWizard_VR/releases).
|
||||||
|
Installation requires the user's clean PAL RMCP01 image. Neither release includes a disc image,
|
||||||
|
extracted game assets, translated game code, compiled game executables, saves, or ghosts.
|
||||||
|
|
||||||
|
The backend version is declared once in `Launcher/Directory.Build.props`. Before choosing a new
|
||||||
|
patch version, compare source pins, published releases, and tags in the VR fork. Tags use `vX.Y.Z`.
|
||||||
|
The Windows workflow checks the tag, executable, and payload contract and runs the translator,
|
||||||
|
synthetic runtime, setup self-tests, pinned dependency preparation, payload boundary audit, and
|
||||||
|
native dependency audit. OpenXR uses the pinned SDK sources and static loader; license notices
|
||||||
|
are included in the installer.
|
||||||
|
|
||||||
|
Build from the repository root on Windows:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
./Launcher/Build-Installer.ps1 -OutputDirectory Launcher/dist-vr
|
||||||
|
./Launcher/Verify-Release.ps1 -Tag v0.2.32 -SetupPath (Resolve-Path Launcher/dist-vr/WiiCompiled-Setup.exe)
|
||||||
|
./Launcher/dist-vr/WiiCompiled-Setup.exe --self-test
|
||||||
|
./Launcher/Test-Recompilation.ps1 -StageDirectory build/vr-synthetic-validation
|
||||||
|
dotnet test translator/Translator.sln -c Release
|
||||||
|
```
|
||||||
|
|
||||||
|
`--version` still prints a plain version. `--info-json` additionally reports `productId` as
|
||||||
|
`wiicompiled-openxr-vr`, `version`, and `openxrD3D12: true`. VR refuses installation, repair,
|
||||||
|
launch, or uninstall of a normal or unidentified installation. Nonportable VR installations use
|
||||||
|
`WiiCompiledOpenXRVR` application data and a distinct uninstall registration and shortcut.
|
||||||
|
|
||||||
|
WheelWizard VR keeps its own `config-vr.json`, importing `config.json` only on first use. Its
|
||||||
|
`Recomp` and `RecompVR` roots own their setup caches, toolkits, build workspaces, extracted assets,
|
||||||
|
binaries, configuration, runtime caches, and logs. Only the normal NAND and canonical Retro Rewind
|
||||||
|
content are shared. Controller mappings are seeded from normal once when available. Uninstall
|
||||||
|
removes the selected `Install` and `Cache` directories and retains `UserData` and imported NAND.
|
||||||
|
|
||||||
|
A shared file lease covers supported launcher operations through mod preparation, reconciliation,
|
||||||
|
and game exit, including shared-data edits and uninstall. Installation locks and running processes
|
||||||
|
are also checked. Arbitrary direct launches of older game binaries do not participate in this
|
||||||
|
guarantee. Close games before using another launcher or editing shared data externally.
|
||||||
|
|
||||||
|
Retro Rewind remains supplied by WheelWizard's existing distribution service. The chosen backend
|
||||||
|
builds both products with its own toolkit. Asset-only changes do not require compilation; changes
|
||||||
|
to Code.pul, translation inputs, or Retro-WFC payloads are reconciled before Retro Rewind launches.
|
||||||
|
The inactive backend is checked on its next selection. Base launches use `--launch-base`.
|
||||||
|
|
||||||
|
WheelWizard VR prepares Retro Rewind updates and reinstalls in a sibling staging tree. Only a
|
||||||
|
completed update is published. The journal supports recovery after interrupted directory swaps;
|
||||||
|
existing ghosts, saves, XML save directories, and local patches survive package replacement.
|
||||||
|
|
||||||
|
Before publishing, validate both artifacts and install beside an existing normal installation.
|
||||||
|
Check all four backend/game combinations, saves and Miis across switches and reinstall/uninstall,
|
||||||
|
Retro Rewind ghosts and content updates, cancellation, interrupted downloads, rollback, and
|
||||||
|
overlapping processes. Headset acceptance also requires menus, races, headset absence, and runtime
|
||||||
|
loss for both VR products. Record unperformed checks explicitly. Publish the backend first; the
|
||||||
|
launcher release workflow requires a published VR backend before releasing the launcher.
|
||||||
@@ -15,6 +15,7 @@ Set-StrictMode -Version 3.0
|
|||||||
. (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1')
|
. (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1')
|
||||||
|
|
||||||
$repoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
|
$repoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
|
||||||
|
$releaseVersion = ([xml](Get-Content -LiteralPath (Join-Path $PSScriptRoot 'Directory.Build.props') -Raw)).Project.PropertyGroup.Version
|
||||||
$outputRoot = [IO.Path]::GetFullPath((Join-Path $repoRoot $OutputDirectory))
|
$outputRoot = [IO.Path]::GetFullPath((Join-Path $repoRoot $OutputDirectory))
|
||||||
$portableTools = [IO.Path]::GetFullPath((Join-Path $repoRoot $PortableToolsDirectory))
|
$portableTools = [IO.Path]::GetFullPath((Join-Path $repoRoot $PortableToolsDirectory))
|
||||||
$dependencySources = [IO.Path]::GetFullPath((Join-Path $repoRoot $DependencySourceDirectory))
|
$dependencySources = [IO.Path]::GetFullPath((Join-Path $repoRoot $DependencySourceDirectory))
|
||||||
@@ -282,7 +283,8 @@ foreach ($required in @('ToolkitFingerprint','TranslationFingerprint','NativeToo
|
|||||||
|
|
||||||
$manifest = [ordered]@{
|
$manifest = [ordered]@{
|
||||||
SchemaVersion = 2
|
SchemaVersion = 2
|
||||||
ProductVersion = '0.2.31'
|
ProductVersion = $releaseVersion
|
||||||
|
ProductId = 'wiicompiled-openxr-vr'
|
||||||
ExpectedGameId = $pins.GameId
|
ExpectedGameId = $pins.GameId
|
||||||
ExpectedDolSha256 = $pins.DolSha256
|
ExpectedDolSha256 = $pins.DolSha256
|
||||||
ExpectedRelSha256 = $pins.RelSha256
|
ExpectedRelSha256 = $pins.RelSha256
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<Version>0.2.32</Version>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -390,7 +390,7 @@ try {
|
|||||||
-SourceDirectory (Join-Path $Workspace 'runtime') -BuildDirectory $build `
|
-SourceDirectory (Join-Path $Workspace 'runtime') -BuildDirectory $build `
|
||||||
-Ninja $ninja -CCompiler $cc -CxxCompiler $cxx -ResourceCompiler $windres `
|
-Ninja $ninja -CCompiler $cc -CxxCompiler $cxx -ResourceCompiler $windres `
|
||||||
-DependenciesDirectory $dependencies -NativePrebuiltDirectory $nativePrebuilt `
|
-DependenciesDirectory $dependencies -NativePrebuiltDirectory $nativePrebuilt `
|
||||||
-AdditionalArguments @("-DMKW_TRANSLATED_COMPILE_JOBS=$translatedJobs")
|
-AdditionalArguments @("-DMKW_TRANSLATED_COMPILE_JOBS=$translatedJobs", '-DMKW_ENABLE_OPENXR=ON')
|
||||||
Invoke-Checked $cmake $configure 'Configuring the bundled native toolchain' -StepId 'configure-native'
|
Invoke-Checked $cmake $configure 'Configuring the bundled native toolchain' -StepId 'configure-native'
|
||||||
if (-not [string]::IsNullOrWhiteSpace($NativeToolchainFingerprint)) {
|
if (-not [string]::IsNullOrWhiteSpace($NativeToolchainFingerprint)) {
|
||||||
[ordered]@{ SchemaVersion = 1; NativeToolchainFingerprint = $NativeToolchainFingerprint } |
|
[ordered]@{ SchemaVersion = 1; NativeToolchainFingerprint = $NativeToolchainFingerprint } |
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ $forbiddenNames = @(
|
|||||||
'WiiCompiled.exe', 'RetroRewind.exe', 'mkw_recompiled.exe',
|
'WiiCompiled.exe', 'RetroRewind.exe', 'mkw_recompiled.exe',
|
||||||
'main.dol', 'StaticR.rel', 'Code.pul', 'base_translation_sources.bin',
|
'main.dol', 'StaticR.rel', 'Code.pul', 'base_translation_sources.bin',
|
||||||
'data_sections_init.cpp', 'data_sections_init_blobs.S', 'mkwii_base_manifest.json',
|
'data_sections_init.cpp', 'data_sections_init_blobs.S', 'mkwii_base_manifest.json',
|
||||||
'generated_func_aliases.cpp', 'translated_function_decls.h'
|
'generated_func_aliases.cpp', 'translated_function_decls.h',
|
||||||
|
'rksys.dat', 'RFL_DB.dat', 'Config.toml', 'config-vr.json', 'install-state.json'
|
||||||
)
|
)
|
||||||
$forbiddenExtensions = @('.iso', '.gcm', '.gcz', '.ciso', '.wbfs', '.wia', '.rvz', '.dol', '.rel', '.pul')
|
$forbiddenExtensions = @('.iso', '.gcm', '.gcz', '.ciso', '.wbfs', '.wia', '.rvz', '.dol', '.rel', '.pul',
|
||||||
|
'.szs', '.brres', '.thp', '.brsar', '.rkg')
|
||||||
$forbiddenSegments = @(
|
$forbiddenSegments = @(
|
||||||
'\BuildWorkspace\generated\', '\BuildWorkspace\runtime\build\', '\GameAssets\', '\BuildWorkspace\Assets\',
|
'\BuildWorkspace\generated\', '\BuildWorkspace\runtime\build\', '\GameAssets\', '\BuildWorkspace\Assets\',
|
||||||
'\BuildWorkspace\PulsarPacks\', '\BuildWorkspace\build\base\', '\BuildWorkspace\build\mods\'
|
'\BuildWorkspace\PulsarPacks\', '\BuildWorkspace\build\base\', '\BuildWorkspace\build\mods\'
|
||||||
|
|||||||
@@ -45,13 +45,14 @@ foreach ($relative in $sourceFiles | Sort-Object -Unique) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# One synthetic text section: li r3,40; addi r3,r3,2; nop; blr.
|
# One synthetic text section: li r3,40; addi r3,r3,2; nop; blr.
|
||||||
# Native HLE wrappers also call these eight guest symbols directly. Give each
|
# Native HLE and VR wrappers also call these guest symbols directly. Give each
|
||||||
# its own generated blr function so the real product can link without game code.
|
# its own generated blr function so the real product can link without game code.
|
||||||
# Keep this list explicit: a new unresolved guest dependency must fail the test.
|
# Keep this list explicit: a new unresolved guest dependency must fail the test.
|
||||||
[uint32]$entry = 0x80001000L
|
[uint32]$entry = 0x80001000L
|
||||||
[uint32[]]$guestCallbacks = @(
|
[uint32[]]$guestCallbacks = @(
|
||||||
0x8012B830L, 0x801A0620L, 0x801A1ED8L, 0x801A961CL,
|
0x8012B830L, 0x801A0620L, 0x801A1ED8L, 0x801A961CL,
|
||||||
0x801AADE0L, 0x801D8D30L, 0x801D9E94L, 0x8055531CL
|
0x801AADE0L, 0x801D8D30L, 0x801D9E94L, 0x8055531CL,
|
||||||
|
0x8056A470L, 0x8056A580L, 0x805A6C58L
|
||||||
)
|
)
|
||||||
$textSize = [int]($guestCallbacks[-1] - $entry + 4)
|
$textSize = [int]($guestCallbacks[-1] - $entry + 4)
|
||||||
$dataOffset = 0x100 + $textSize
|
$dataOffset = 0x100 + $textSize
|
||||||
@@ -135,7 +136,7 @@ try {
|
|||||||
-Ninja $ninja -CCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang.exe') `
|
-Ninja $ninja -CCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang.exe') `
|
||||||
-CxxCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang++.exe') `
|
-CxxCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang++.exe') `
|
||||||
-ResourceCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-windres.exe') `
|
-ResourceCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-windres.exe') `
|
||||||
-DependenciesDirectory $dependencies -AdditionalArguments @('-DMKW_BUILD_PRODUCTS=ON')
|
-DependenciesDirectory $dependencies -AdditionalArguments @('-DMKW_BUILD_PRODUCTS=ON', '-DMKW_ENABLE_OPENXR=ON')
|
||||||
Invoke-Checked $cmake $configure 'Configuring the production Windows runtime' `
|
Invoke-Checked $cmake $configure 'Configuring the production Windows runtime' `
|
||||||
-WaitForProcessTree $false
|
-WaitForProcessTree $false
|
||||||
Invoke-Checked $cmake @('--build', $nativeBuild, '--target', 'WiiCompiled', '--parallel', "$Parallel") `
|
Invoke-Checked $cmake @('--build', $nativeBuild, '--target', 'WiiCompiled', '--parallel', "$Parallel") `
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param([string]$Tag, [string]$SetupPath)
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$version = ([xml](Get-Content -LiteralPath (Join-Path $PSScriptRoot 'Directory.Build.props') -Raw)).Project.PropertyGroup.Version
|
||||||
|
if ($Tag -and $Tag -cne "v$version") { throw "Release tag must be v$version, got $Tag" }
|
||||||
|
if ($SetupPath) {
|
||||||
|
$reported = (& $SetupPath --version | Out-String).Trim()
|
||||||
|
if ($LASTEXITCODE -ne 0 -or $reported -cne $version) { throw 'Setup executable version mismatch.' }
|
||||||
|
$info = (& $SetupPath --info-json | Out-String) | ConvertFrom-Json
|
||||||
|
if ($LASTEXITCODE -ne 0 -or $info.productId -cne 'wiicompiled-openxr-vr' -or
|
||||||
|
$info.version -cne $version -or $info.openxrD3D12 -ne $true) { throw 'Setup VR identity mismatch.' }
|
||||||
|
# Inspect the appended payload as well: a correctly versioned host can still wrap stale tools.
|
||||||
|
Add-Type -AssemblyName System.IO.Compression
|
||||||
|
$stream = [IO.File]::OpenRead((Resolve-Path -LiteralPath $SetupPath))
|
||||||
|
$payload = [IO.MemoryStream]::new()
|
||||||
|
try {
|
||||||
|
if ($stream.Length -lt 24) { throw 'Missing payload footer.' }
|
||||||
|
$stream.Position = $stream.Length - 24
|
||||||
|
$reader = [IO.BinaryReader]::new($stream, [Text.Encoding]::ASCII, $true)
|
||||||
|
try {
|
||||||
|
$magic = [Text.Encoding]::ASCII.GetString($reader.ReadBytes(8))
|
||||||
|
$offset = $reader.ReadInt64()
|
||||||
|
$length = $reader.ReadInt64()
|
||||||
|
} finally { $reader.Dispose() }
|
||||||
|
if ($magic -cne 'MKWCPAY1' -or $offset -lt 0 -or $length -le 0 -or $offset + $length -ne $stream.Length - 24) {
|
||||||
|
throw 'Invalid payload footer.'
|
||||||
|
}
|
||||||
|
$stream.Position = $offset
|
||||||
|
$buffer = [byte[]]::new(1048576)
|
||||||
|
while ($length -gt 0) {
|
||||||
|
$count = $stream.Read($buffer, 0, [int][Math]::Min($length, $buffer.Length))
|
||||||
|
if ($count -eq 0) { throw 'Truncated payload.' }
|
||||||
|
$payload.Write($buffer, 0, $count)
|
||||||
|
$length -= $count
|
||||||
|
}
|
||||||
|
$payload.Position = 0
|
||||||
|
$zip = [IO.Compression.ZipArchive]::new($payload, [IO.Compression.ZipArchiveMode]::Read, $true)
|
||||||
|
try {
|
||||||
|
$entry = $zip.GetEntry('payload-manifest.json')
|
||||||
|
if (-not $entry) { throw 'Missing payload manifest.' }
|
||||||
|
$textReader = [IO.StreamReader]::new($entry.Open())
|
||||||
|
try { $manifest = $textReader.ReadToEnd() | ConvertFrom-Json } finally { $textReader.Dispose() }
|
||||||
|
if ($manifest.ProductId -cne $info.productId -or $manifest.ProductVersion -cne $version) {
|
||||||
|
throw 'Payload identity/version does not match the executable.'
|
||||||
|
}
|
||||||
|
} finally { $zip.Dispose() }
|
||||||
|
} finally { $payload.Dispose(); $stream.Dispose() }
|
||||||
|
}
|
||||||
|
Write-Output "Verified WiiCompiled OpenXR VR $version"
|
||||||
@@ -26,7 +26,7 @@ public static class RuntimeConfiguration
|
|||||||
/// <summary>The per-user configuration an ordinary (non-portable) installation shares.</summary>
|
/// <summary>The per-user configuration an ordinary (non-portable) installation shares.</summary>
|
||||||
public static string ApplicationDataConfigPath => Path.Combine(
|
public static string ApplicationDataConfigPath => Path.Combine(
|
||||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||||
"WiiCompiled", ConfigFileName);
|
OperatingSystem.IsWindows() ? "WiiCompiledOpenXRVR" : "WiiCompiled", ConfigFileName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The configuration file that governs <paramref name="installDirectory"/>. This mirrors
|
/// The configuration file that governs <paramref name="installDirectory"/>. This mirrors
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ internal enum AppMode
|
|||||||
CheckProducts,
|
CheckProducts,
|
||||||
RepairProducts,
|
RepairProducts,
|
||||||
Version,
|
Version,
|
||||||
|
InfoJson,
|
||||||
EmitPayloadIdentities
|
EmitPayloadIdentities
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +59,7 @@ internal sealed class CommandLine
|
|||||||
switch (args[i].ToLowerInvariant())
|
switch (args[i].ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "--version": result.Mode = AppMode.Version; break;
|
case "--version": result.Mode = AppMode.Version; break;
|
||||||
|
case "--info-json": result.Mode = AppMode.InfoJson; break;
|
||||||
case "--silent": result.Mode = AppMode.SilentInstall; break;
|
case "--silent": result.Mode = AppMode.SilentInstall; break;
|
||||||
case "--verify-inputs": result.Mode = AppMode.VerifyInputs; break;
|
case "--verify-inputs": result.Mode = AppMode.VerifyInputs; break;
|
||||||
case "--uninstall": result.Mode = AppMode.Uninstall; break;
|
case "--uninstall": result.Mode = AppMode.Uninstall; break;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ internal static class ConsoleCommands
|
|||||||
Console.Out.WriteLine(" --launch-retro | --launch-base");
|
Console.Out.WriteLine(" --launch-retro | --launch-base");
|
||||||
Console.Out.WriteLine(" --uninstall --install-dir <dir>");
|
Console.Out.WriteLine(" --uninstall --install-dir <dir>");
|
||||||
Console.Out.WriteLine(" --version");
|
Console.Out.WriteLine(" --version");
|
||||||
|
Console.Out.WriteLine(" --info-json");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +29,15 @@ internal static class ConsoleCommands
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int InfoJson()
|
||||||
|
{
|
||||||
|
Console.Out.WriteLine(JsonSerializer.Serialize(new
|
||||||
|
{
|
||||||
|
productId = ProductInfo.Id, version = ProductInfo.Version, openxrD3D12 = true
|
||||||
|
}));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static int EmitPayloadIdentities(CommandLine command)
|
public static int EmitPayloadIdentities(CommandLine command)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ internal static class GameLaunchService
|
|||||||
public static Task<int> LaunchAsync(BuildProfile profile)
|
public static Task<int> LaunchAsync(BuildProfile profile)
|
||||||
{
|
{
|
||||||
var installation = new Installation(AppContext.BaseDirectory);
|
var installation = new Installation(AppContext.BaseDirectory);
|
||||||
|
ProductOwnership.Ensure(installation.Root);
|
||||||
using var operation = InstallOperationLock.Acquire(installation.Root);
|
using var operation = InstallOperationLock.Acquire(installation.Root);
|
||||||
// A portable installation the user moved is reconciled before anything is read from its
|
// A portable installation the user moved is reconciled before anything is read from its
|
||||||
// recorded location. Launch never needs the discarded native build tree.
|
// recorded location. Launch never needs the discarded native build tree.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ internal sealed class InstallerEngine
|
|||||||
{
|
{
|
||||||
var installDirectory = Path.GetFullPath(options.InstallDirectory);
|
var installDirectory = Path.GetFullPath(options.InstallDirectory);
|
||||||
ValidateInstallDirectory(installDirectory);
|
ValidateInstallDirectory(installDirectory);
|
||||||
|
ProductOwnership.Ensure(installDirectory, allowEmpty: true);
|
||||||
|
|
||||||
InputValidation.ValidateExtension(options.GamePath);
|
InputValidation.ValidateExtension(options.GamePath);
|
||||||
var parent = Directory.GetParent(installDirectory)?.FullName
|
var parent = Directory.GetParent(installDirectory)?.FullName
|
||||||
@@ -37,6 +38,8 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
using var payload = PayloadArchive.OpenCurrent();
|
using var payload = PayloadArchive.OpenCurrent();
|
||||||
var manifest = payload.ReadManifest();
|
var manifest = payload.ReadManifest();
|
||||||
|
if (manifest.ProductId != ProductInfo.Id || manifest.ProductVersion != ProductInfo.Version)
|
||||||
|
throw new InvalidDataException("This setup payload does not match WiiCompiled OpenXR VR and its version.");
|
||||||
var toolkit = InstalledLayout.Toolkit(staging);
|
var toolkit = InstalledLayout.Toolkit(staging);
|
||||||
var workspace = InstalledLayout.Workspace(staging);
|
var workspace = InstalledLayout.Workspace(staging);
|
||||||
|
|
||||||
@@ -366,6 +369,7 @@ internal sealed class InstallerEngine
|
|||||||
ProductVersion = manifest.ProductVersion,
|
ProductVersion = manifest.ProductVersion,
|
||||||
InstallDir = installDirectory,
|
InstallDir = installDirectory,
|
||||||
InstalledUtc = previousState?.InstalledUtc ?? DateTime.UtcNow,
|
InstalledUtc = previousState?.InstalledUtc ?? DateTime.UtcNow,
|
||||||
|
ProductId = ProductInfo.Id,
|
||||||
RetroRewindInstalled = previousState?.RetroRewindInstalled ?? false,
|
RetroRewindInstalled = previousState?.RetroRewindInstalled ?? false,
|
||||||
ToolkitReleaseTag = manifest.ToolkitReleaseTag,
|
ToolkitReleaseTag = manifest.ToolkitReleaseTag,
|
||||||
DolSha256 = manifest.ExpectedDolSha256,
|
DolSha256 = manifest.ExpectedDolSha256,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ internal sealed class InstallOptions
|
|||||||
|
|
||||||
internal sealed class PayloadManifest
|
internal sealed class PayloadManifest
|
||||||
{
|
{
|
||||||
|
public string ProductId { get; set; } = "";
|
||||||
public int SchemaVersion { get; set; }
|
public int SchemaVersion { get; set; }
|
||||||
public string ProductVersion { get; set; } = "";
|
public string ProductVersion { get; set; } = "";
|
||||||
public string ExpectedGameId { get; set; } = "RMCP01";
|
public string ExpectedGameId { get; set; } = "RMCP01";
|
||||||
@@ -72,6 +73,7 @@ internal sealed class DiscHeader
|
|||||||
|
|
||||||
internal sealed class InstallState
|
internal sealed class InstallState
|
||||||
{
|
{
|
||||||
|
public string ProductId { get; set; } = "";
|
||||||
[JsonRequired]
|
[JsonRequired]
|
||||||
public int SchemaVersion { get; set; } = 1;
|
public int SchemaVersion { get; set; } = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace WiiCompiled.Setup.Windows;
|
||||||
|
|
||||||
|
internal static class ProductOwnership
|
||||||
|
{
|
||||||
|
public static void Ensure(string directory, bool allowEmpty = false)
|
||||||
|
{
|
||||||
|
for (var current = new DirectoryInfo(Path.GetFullPath(directory)); current is not null; current = current.Parent)
|
||||||
|
if (current.Exists && (current.Attributes & FileAttributes.ReparsePoint) != 0)
|
||||||
|
throw new InvalidDataException("Use a VR installation directory without junctions or symbolic links.");
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
if (allowEmpty) return;
|
||||||
|
throw new InvalidDataException("WiiCompiled OpenXR VR is not installed in this directory.");
|
||||||
|
}
|
||||||
|
// A junction must not let an apparently separate VR destination overwrite another install.
|
||||||
|
if (allowEmpty && !Directory.EnumerateFileSystemEntries(directory).Any()) return;
|
||||||
|
var statePath = Path.Combine(directory, InstalledLayout.InstallStateFileName);
|
||||||
|
if (File.Exists(statePath))
|
||||||
|
{
|
||||||
|
using var state = JsonDocument.Parse(File.ReadAllText(statePath));
|
||||||
|
if (state.RootElement.TryGetProperty("ProductId", out var id) && id.GetString() == ProductInfo.Id)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new InvalidDataException("This folder belongs to a normal or unidentified WiiCompiled installation. " +
|
||||||
|
"Choose a separate empty folder for OpenXR VR; existing files have not been changed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -77,6 +77,7 @@ internal sealed class ProductRepairService
|
|||||||
RetroWfcPayloadMode requestedPayloadMode, ReconcileOptions options,
|
RetroWfcPayloadMode requestedPayloadMode, ReconcileOptions options,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
ProductOwnership.Ensure(_installation.Root);
|
||||||
if (!_installation.IsPresent)
|
if (!_installation.IsPresent)
|
||||||
throw new InvalidOperationException("WiiCompiled is not installed here.");
|
throw new InvalidOperationException("WiiCompiled is not installed here.");
|
||||||
if (!_installation.HasToolkit)
|
if (!_installation.HasToolkit)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ internal static class Program
|
|||||||
{
|
{
|
||||||
Console.Out.WriteLine(
|
Console.Out.WriteLine(
|
||||||
"Mario Kart WiiCompiled is installed through Wheel Wizard - download it from " +
|
"Mario Kart WiiCompiled is installed through Wheel Wizard - download it from " +
|
||||||
"https://github.com/TeamWheelWizard/WheelWizard");
|
"https://github.com/iChris4/WheelWizard_VR");
|
||||||
Console.ReadKey(intercept: true);
|
Console.ReadKey(intercept: true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -37,6 +37,8 @@ internal static class Program
|
|||||||
|
|
||||||
if (command.Mode == AppMode.Version)
|
if (command.Mode == AppMode.Version)
|
||||||
return ConsoleCommands.Version();
|
return ConsoleCommands.Version();
|
||||||
|
if (command.Mode == AppMode.InfoJson)
|
||||||
|
return ConsoleCommands.InfoJson();
|
||||||
|
|
||||||
if (command.Mode == AppMode.Help)
|
if (command.Mode == AppMode.Help)
|
||||||
return ConsoleCommands.Help();
|
return ConsoleCommands.Help();
|
||||||
@@ -120,8 +122,9 @@ internal static class PlatformChecks
|
|||||||
|
|
||||||
internal static class ProductInfo
|
internal static class ProductInfo
|
||||||
{
|
{
|
||||||
public const string Name = "WiiCompiled";
|
public const string Name = "WiiCompiled OpenXR VR";
|
||||||
public const string Version = "0.2.31";
|
public const string Id = "wiicompiled-openxr-vr";
|
||||||
|
public static string Version => typeof(ProductInfo).Assembly.GetName().Version!.ToString(3);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The setup executable is copied into the installation under this name. It is the launcher and
|
/// The setup executable is copied into the installation under this name. It is the launcher and
|
||||||
@@ -129,8 +132,8 @@ internal static class ProductInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string SetupCopyName = "WiiCompiled-Setup.exe";
|
public const string SetupCopyName = "WiiCompiled-Setup.exe";
|
||||||
|
|
||||||
public const string UninstallKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall\WiiCompiled";
|
public const string UninstallKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall\WiiCompiledOpenXRVR";
|
||||||
public static string DefaultInstallDirectory =>
|
public static string DefaultInstallDirectory =>
|
||||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||||
"Programs", "WiiCompiled");
|
"Programs", "WiiCompiledOpenXRVR");
|
||||||
}
|
}
|
||||||
@@ -6,9 +6,36 @@ namespace WiiCompiled.Setup.Windows;
|
|||||||
|
|
||||||
internal static class SelfTests
|
internal static class SelfTests
|
||||||
{
|
{
|
||||||
|
private static void TestVrOwnership()
|
||||||
|
{
|
||||||
|
var root = Path.Combine(Path.GetTempPath(), "WiiCompiled-VR-ownership-" + Guid.NewGuid().ToString("N"));
|
||||||
|
Directory.CreateDirectory(root);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProductOwnership.Ensure(root, allowEmpty: true);
|
||||||
|
var statePath = Path.Combine(root, InstalledLayout.InstallStateFileName);
|
||||||
|
File.WriteAllText(statePath, "{\"SetupVersion\":\"0.2.32\"}");
|
||||||
|
var original = File.ReadAllText(statePath);
|
||||||
|
try { ProductOwnership.Ensure(root, allowEmpty: true); throw new Exception("Accepted an unidentified install."); }
|
||||||
|
catch (InvalidDataException) { }
|
||||||
|
if (File.ReadAllText(statePath) != original) throw new Exception("Normal state was changed by rejection.");
|
||||||
|
File.WriteAllText(statePath, "{\"ProductId\":\"wiicompiled\"}");
|
||||||
|
try { ProductOwnership.Ensure(root); throw new Exception("Accepted a normal install."); }
|
||||||
|
catch (InvalidDataException) { }
|
||||||
|
JsonState.Write(statePath, new InstallState { ProductId = ProductInfo.Id, InstallDir = root });
|
||||||
|
ProductOwnership.Ensure(root);
|
||||||
|
if (RuntimeConfiguration.ApplicationDataConfigPath.Contains("WiiCompiled\\Config.toml", StringComparison.Ordinal))
|
||||||
|
throw new Exception("The VR setup still uses normal application data.");
|
||||||
|
if (!ProductInfo.UninstallKey.EndsWith("WiiCompiledOpenXRVR", StringComparison.Ordinal))
|
||||||
|
throw new Exception("The VR uninstall identity is not isolated.");
|
||||||
|
}
|
||||||
|
finally { Directory.Delete(root, recursive: true); }
|
||||||
|
}
|
||||||
|
|
||||||
public static int Run()
|
public static int Run()
|
||||||
{
|
{
|
||||||
var failures = new List<string>();
|
var failures = new List<string>();
|
||||||
|
Test("VR installation ownership", TestVrOwnership, failures);
|
||||||
Test("ISO extension", () => TestAcceptedExtension(".iso"), failures);
|
Test("ISO extension", () => TestAcceptedExtension(".iso"), failures);
|
||||||
Test("GCM extension", () => TestAcceptedExtension(".gcm"), failures);
|
Test("GCM extension", () => TestAcceptedExtension(".gcm"), failures);
|
||||||
Test("GCZ extension", () => TestAcceptedExtension(".gcz"), failures);
|
Test("GCZ extension", () => TestAcceptedExtension(".gcz"), failures);
|
||||||
@@ -1291,7 +1318,7 @@ internal static class SelfTests
|
|||||||
RetroWfcPayloadMode = "skipped" });
|
RetroWfcPayloadMode = "skipped" });
|
||||||
JsonState.Write(installation.InstallStatePath, new InstallState
|
JsonState.Write(installation.InstallStatePath, new InstallState
|
||||||
{
|
{
|
||||||
InstallDir = root, RetroRewindInstalled = true,
|
ProductId = ProductInfo.Id, InstallDir = root, RetroRewindInstalled = true,
|
||||||
DolSha256 = dolSha, RelSha256 = relSha,
|
DolSha256 = dolSha, RelSha256 = relSha,
|
||||||
RetroRewindCodePulSha256 = inputsA.CodePulSha256,
|
RetroRewindCodePulSha256 = inputsA.CodePulSha256,
|
||||||
RetroRewindCompileInputsSha256 = inputsA.CompileInputsSha256,
|
RetroRewindCompileInputsSha256 = inputsA.CompileInputsSha256,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace WiiCompiled.Setup.Windows;
|
|||||||
|
|
||||||
internal static class ShellIntegration
|
internal static class ShellIntegration
|
||||||
{
|
{
|
||||||
private const string ShortcutFileName = "wiicompiled (base) (beta).lnk";
|
private const string ShortcutFileName = "WiiCompiled OpenXR VR (base) (beta).lnk";
|
||||||
|
|
||||||
public static void RegisterUninstaller(string installDirectory, bool retroInstalled)
|
public static void RegisterUninstaller(string installDirectory, bool retroInstalled)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ internal static class UninstallService
|
|||||||
public static int RunWorker(string installDirectory, bool quiet)
|
public static int RunWorker(string installDirectory, bool quiet)
|
||||||
{
|
{
|
||||||
installDirectory = Path.GetFullPath(installDirectory);
|
installDirectory = Path.GetFullPath(installDirectory);
|
||||||
|
ProductOwnership.Ensure(installDirectory);
|
||||||
|
using var operation = InstallOperationLock.Acquire(installDirectory);
|
||||||
|
RunningProductGuard.EnsureProductsNotRunning(installDirectory);
|
||||||
Thread.Sleep(750);
|
Thread.Sleep(750);
|
||||||
TryCleanup("remove shortcuts", quiet, ShellIntegration.RemoveShortcuts);
|
TryCleanup("remove shortcuts", quiet, ShellIntegration.RemoveShortcuts);
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,8 @@
|
|||||||
<AssemblyName>WiiCompiled.Setup</AssemblyName>
|
<AssemblyName>WiiCompiled.Setup</AssemblyName>
|
||||||
<RootNamespace>WiiCompiled.Setup.Windows</RootNamespace>
|
<RootNamespace>WiiCompiled.Setup.Windows</RootNamespace>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
<Version>0.2.31</Version>
|
|
||||||
<Authors>patchzy</Authors>
|
<Authors>patchzy</Authors>
|
||||||
<Product>WiiCompiled</Product>
|
<Product>WiiCompiled OpenXR VR</Product>
|
||||||
<Description>Command-line installer and launcher for WiiCompiled</Description>
|
<Description>Command-line installer and launcher for WiiCompiled</Description>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
64fdd492f6ce71fd223b49f493e0809d9a7f9ed45ebaa3605f626eb77282dbe4 WiiCompiled-Setup.exe
|
||||||
|
b319b86d46bea6ebfa52965c65706976d6004abc01914ff82a2b73c71de84def WheelWizardVRWindows.exe
|
||||||
@@ -15,8 +15,14 @@ This is an experimental renderer, not yet a release-ready VR mode.
|
|||||||
- A build made with `MKW_ENABLE_OPENXR=ON`, which defaults on for Windows and off elsewhere while
|
- A build made with `MKW_ENABLE_OPENXR=ON`, which defaults on for Windows and off elsewhere while
|
||||||
the Vulkan bridge remains capability-gated.
|
the Vulkan bridge remains capability-gated.
|
||||||
|
|
||||||
OpenXR remains disabled until requested in `Config.toml`. The file is next to the installed game
|
For managed installation, use [WheelWizard VR](https://github.com/iChris4/WheelWizard_VR/releases/latest)
|
||||||
configuration and is created with the following defaults:
|
and enable **Settings → Other → WiiCompiled (beta) → Enable WiiCompiled OpenXR VR (beta)**.
|
||||||
|
The launcher sets `vr.enabled=true`, `vr.required=false`, and `video.graphics_api="d3d12"` before
|
||||||
|
each VR launch, preserving other preferences. Its portable configuration lives at
|
||||||
|
`RecompVR/UserData/Config.toml` beneath WheelWizard's data folder. Normal graphics settings remain
|
||||||
|
in `Recomp/UserData/Config.toml`. Both backends use the normal installation's effective NAND.
|
||||||
|
|
||||||
|
Standalone launches remain opt-in. `Config.toml` is created with the following defaults:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[vr]
|
[vr]
|
||||||
@@ -46,7 +52,8 @@ at launch. The in-game F10 settings bar also exposes the enable switch, but a re
|
|||||||
required.
|
required.
|
||||||
|
|
||||||
`required = false` is the safe default: an absent runtime, disconnected headset, unsupported GPU,
|
`required = false` is the safe default: an absent runtime, disconnected headset, unsupported GPU,
|
||||||
or graphics-binding failure is logged and the game continues in ordinary desktop mode. Set it to
|
or graphics-binding failure is logged and the game continues in ordinary desktop mode. A temporary
|
||||||
|
notification explains the failure; the message remains available under **F10 → VR**. Set it to
|
||||||
`true` only when a failed VR startup should stop the game with an error.
|
`true` only when a failed VR startup should stop the game with an error.
|
||||||
|
|
||||||
`mirror_view` chooses what the desktop window shows while the headset is running: `"normal"`
|
`mirror_view` chooses what the desktop window shows while the headset is running: `"normal"`
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
# WiiCompiled
|
# WiiCompiled OpenXR VR
|
||||||
|
|
||||||
A native PC port of Mario Kart Wii, made with static recompilation.
|
A native PC port of Mario Kart Wii, made with static recompilation.
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ anywhere at runtime.
|
|||||||
> toolchain, the translation runs on your machine against your disc image, and nothing ever gets
|
> toolchain, the translation runs on your machine against your disc image, and nothing ever gets
|
||||||
> uploaded.
|
> uploaded.
|
||||||
|
|
||||||
[What is a github, I just want to play](https://github.com/TeamWheelWizard/WheelWizard/releases/latest)
|
[Download WheelWizard VR](https://github.com/iChris4/WheelWizard_VR/releases/latest)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -96,8 +96,7 @@ Known limitations of the Wii Remote path:
|
|||||||
- GPU: GTX 1650 / RX 6400 / Arc A310 or higher
|
- GPU: GTX 1650 / RX 6400 / Arc A310 or higher
|
||||||
- CPU: Intel Core i5-8400 / AMD Ryzen 5 2600 (4c/6c, ~3.5GHz+) or higher
|
- CPU: Intel Core i5-8400 / AMD Ryzen 5 2600 (4c/6c, ~3.5GHz+) or higher
|
||||||
- About 20 GB of free disk space during installation (Final game size ~5 GB)
|
- About 20 GB of free disk space during installation (Final game size ~5 GB)
|
||||||
- macOS 14 (Sonoma) or later on Apple Silicon
|
- This fork's packaged release supports Windows x64. Other platforms are not release targets.
|
||||||
- On macOS, Apple Xcode Command Line Tools (Setup opens Apple's installer when they are missing)
|
|
||||||
- A clean, unmodified **PAL `RMCP01`** disc image of Mario Kart Wii, dumped by you. ISO, GCM,
|
- A clean, unmodified **PAL `RMCP01`** disc image of Mario Kart Wii, dumped by you. ISO, GCM,
|
||||||
GCZ, CISO, WBFS, WIA and RVZ are accepted.
|
GCZ, CISO, WBFS, WIA and RVZ are accepted.
|
||||||
|
|
||||||
@@ -113,15 +112,26 @@ regions, patched executables) is rejected outright.
|
|||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
For an easy experience, use [Wheel Wizard](https://github.com/TeamWheelWizard/WheelWizard). Pick your clean PAL `RMCP01`
|
Use [WheelWizard VR](https://github.com/iChris4/WheelWizard_VR/releases/latest). Select your clean PAL
|
||||||
image under Settings, turn on **WiiCompiled (beta)**, and hit install from the Home page.
|
`RMCP01` image in Settings, then open **Settings → Other → WiiCompiled (beta)** and enable
|
||||||
Wheel Wizard downloads the setup tool from this repo and walks you through install, updates and
|
**Enable WiiCompiled OpenXR VR (beta)**. Press Install on Home. Installation builds both Base game
|
||||||
launching. The backend itself is deliberately command-line only, Wheel Wizard is a wrapper around it.
|
and Retro Rewind locally using the bundled toolchain; a developer toolchain is not required.
|
||||||
|
|
||||||
|
Home lets you choose **Base game** or **Retro Rewind**. The normal WiiCompiled switch selects the
|
||||||
|
original backend; turning both switches off selects Dolphin. Only one recompilation switch can
|
||||||
|
be enabled at a time. VR uses a separate `RecompVR` installation beside the normal `Recomp` folder.
|
||||||
|
Saves and Miis use the normal installation's effective NAND; Retro Rewind retains its separate
|
||||||
|
XML-directed saves and ghosts. Graphics, VR preferences, caches, and compiled binaries stay separate.
|
||||||
|
Uninstalling either backend in WheelWizard VR preserves configuration and shared progress.
|
||||||
|
|
||||||
|
Managed VR launches enable OpenXR with D3D12. If the runtime or headset is unavailable, the game
|
||||||
|
continues on the desktop and displays the failure briefly; **F10 → VR** retains the explanation.
|
||||||
|
See [OpenXR configuration](OPENXR.md) and [distribution and validation](DISTRIBUTION.md).
|
||||||
|
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> Only take builds from this repository's
|
> Only take builds from this repository's
|
||||||
> [Releases](https://github.com/patchzyy/Wiicompiled/releases) page. If someone's sharing an
|
> [Releases](https://github.com/iChris4/Wiicompiled_VR/releases) page. If someone's sharing an
|
||||||
> installer through Discord or some random download site, don't touch it!!
|
> installer through Discord or some random download site, don't touch it!!
|
||||||
|
|
||||||
## A note on related projects
|
## A note on related projects
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# WheelWizard VR integration validation
|
||||||
|
|
||||||
|
Validated locally on Windows x64 on 2026-09-09. These are release candidates; public release
|
||||||
|
acceptance is not complete.
|
||||||
|
|
||||||
|
## Candidates
|
||||||
|
|
||||||
|
| Product | Version | Local artifact | SHA-256 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| WiiCompiled OpenXR VR setup | 0.2.32 | `Launcher/dist-vr/WiiCompiled-Setup.exe` | `64fdd492f6ce71fd223b49f493e0809d9a7f9ed45ebaa3605f626eb77282dbe4` |
|
||||||
|
| WheelWizard VR | 2.5.5 | `Launcher/dist-vr/WheelWizardVRWindows.exe` | `b319b86d46bea6ebfa52965c65706976d6004abc01914ff82a2b73c71de84def` |
|
||||||
|
|
||||||
|
The launcher artifact is also in the launcher checkout at `artifacts/WheelWizardVRWindows.exe`.
|
||||||
|
`Launcher/dist-vr/SHA256SUMS.txt` contains both checksums. Only these executables and their checksums
|
||||||
|
are intended for distribution. The setup contains the toolkit and source payload, not a compiled
|
||||||
|
game. All extracted assets, normal installation copies, compiled games, and test NANDs remain in
|
||||||
|
ignored local validation directories.
|
||||||
|
|
||||||
|
The existing local setup in `Launcher/dist` is the user's 0.2.31 rebuild. Its SHA-256 matches the
|
||||||
|
setup asset published under the VR fork's `0.2` tag. The backend fork also has tag `0.1`; the
|
||||||
|
launcher fork has no published release. These were checked through the GitHub API before finalizing
|
||||||
|
the candidates. The next source patch versions are 0.2.32 and 2.5.5. New release tags use `vX.Y.Z`
|
||||||
|
and must agree with the single version source in each product's `Directory.Build.props`.
|
||||||
|
|
||||||
|
## Passed
|
||||||
|
|
||||||
|
- WheelWizard suite: **255 tests**, including backend selection/migration, configuration isolation,
|
||||||
|
all four backend/game launch command paths, same-version wrong-product rejection, separate
|
||||||
|
release routing, exact self-update asset selection, shared NAND configuration, Mii edit blocking,
|
||||||
|
and uninstall preservation of both backends' configuration, NAND, and ghosts.
|
||||||
|
- Retro Rewind transaction tests: staged replacement, cancellation, preservation of saves/ghosts
|
||||||
|
and XML save directories, current distribution ZIP layout, archive path validation, interrupted
|
||||||
|
publication recovery, and a real Windows locked-file failure after one directory was published.
|
||||||
|
- Translator suite: **576 tests**.
|
||||||
|
- Packaged setup self-tests, including product ownership, configuration, portable move healing,
|
||||||
|
install transaction rollback, interrupted-install recovery, Retro-WFC snapshot/retry behavior,
|
||||||
|
compile-input fingerprints, and product report contracts.
|
||||||
|
- Full synthetic PowerPC translation and native OpenXR runtime link. The synthetic fixture now
|
||||||
|
includes the three callbacks used by the VR camera; no game translation is used for this test.
|
||||||
|
- Pinned-fact audit and setup payload boundary audit. Native dependency audit inspected **524
|
||||||
|
binaries and 5,277 imports**. The pinned OpenXR SDK and static loader were built; licenses remain
|
||||||
|
included. A configured bundled SDK takes precedence over a developer machine's OpenXR package.
|
||||||
|
- Executable identity/version and embedded setup payload identity/version agree. Both Windows
|
||||||
|
release workflows use existing GitHub Actions versions and have no Linux/macOS release jobs.
|
||||||
|
- Final packaged setup installed both VR products from the owned clean PAL image into an isolated
|
||||||
|
portable installation. Updating that installation with the final package succeeded, and both
|
||||||
|
products reported `current` afterward.
|
||||||
|
- Real product checks after modifying isolated Retro Rewind content: an asset-only change kept
|
||||||
|
both products current; a Code.pul change reported `code-pul-changed` for Retro Rewind and left
|
||||||
|
Base current; restoring the content returned both products to current.
|
||||||
|
- Normal Base, normal Retro Rewind, VR Base, and VR Retro Rewind each stayed running during a
|
||||||
|
20-second startup observation through their installed setup host and closed with setup exit 0.
|
||||||
|
Normal tests used an isolated copy of the existing normal installation. Test configurations
|
||||||
|
pointed to the same isolated NAND and isolated Retro Rewind content.
|
||||||
|
- Both VR runs used a child-process-only missing OpenXR runtime override. Logs confirmed
|
||||||
|
`vr.enabled=true`, `vr.required=false`, D3D12, and desktop fallback. System OpenXR registration
|
||||||
|
was not changed.
|
||||||
|
- The final single-file launcher started using an isolated portable configuration, displayed
|
||||||
|
`WheelWizard VR` as its window title, and closed with exit 0. Its startup log contained no
|
||||||
|
application-start or unhandled-exception errors. Publishing succeeded with existing Windows
|
||||||
|
registry platform-analyzer warnings.
|
||||||
|
- Source synchronization checked destination hashes before replacing files and retained backups.
|
||||||
|
Both repositories pass `git diff --check`. Source changes are local and have not been committed
|
||||||
|
or pushed as part of this validation.
|
||||||
|
|
||||||
|
## Still required for release acceptance
|
||||||
|
|
||||||
|
- Interactive Home/settings verification and complete install/launch flows for all four selections.
|
||||||
|
Command-level tests and isolated startup observations do not establish menu or race correctness.
|
||||||
|
- Headset menus and races for Base and Retro Rewind, physical headset absence, runtime loss during
|
||||||
|
a session, and visual confirmation of the nonblocking fallback notification.
|
||||||
|
- Real player progress/Miis/ghosts exercised across gameplay, updates, reinstall, and uninstall.
|
||||||
|
Automated preservation tests passed; live player data was deliberately excluded from smoke tests.
|
||||||
|
- Fresh installation on a clean Windows machine without developer toolchains. The tested package
|
||||||
|
used its bundled tools on this workstation; a pristine-machine run has not been performed.
|
||||||
|
- Live network-interruption/download tests and interactive overlapping-launcher scenarios.
|
||||||
|
File leases, content cancellation, interrupted publication, and setup rollback have automated
|
||||||
|
coverage, but the complete manual matrix remains outstanding.
|
||||||
|
|
||||||
|
After acceptance, publish the VR backend first, then the launcher. The launcher release workflow
|
||||||
|
downloads the published backend and checks its VR identity, capability, and tag/version agreement
|
||||||
|
before publishing. Until that backend release exists, a fresh launcher install cannot resolve this
|
||||||
|
local 0.2.32 candidate from GitHub automatically.
|
||||||
|
|
||||||
|
Detailed local logs and isolated installations are under `.scratch/` (excluded from distribution).
|
||||||
@@ -254,7 +254,10 @@ if(MKW_ENABLE_OPENXR)
|
|||||||
message(WARNING "OpenXR is not wired for this platform; disabling MKW_ENABLE_OPENXR")
|
message(WARNING "OpenXR is not wired for this platform; disabling MKW_ENABLE_OPENXR")
|
||||||
set(MKW_ENABLE_OPENXR OFF)
|
set(MKW_ENABLE_OPENXR OFF)
|
||||||
else()
|
else()
|
||||||
find_package(OpenXR CONFIG QUIET)
|
# An installer-supplied SDK must win over any developer machine package.
|
||||||
|
if(NOT MKW_OPENXR_SDK_DIR AND NOT FETCHCONTENT_SOURCE_DIR_OPENXR)
|
||||||
|
find_package(OpenXR CONFIG QUIET)
|
||||||
|
endif()
|
||||||
if(NOT TARGET OpenXR::openxr_loader AND NOT TARGET openxr_loader)
|
if(NOT TARGET OpenXR::openxr_loader AND NOT TARGET openxr_loader)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
set(BUILD_API_LAYERS OFF CACHE BOOL "" FORCE)
|
set(BUILD_API_LAYERS OFF CACHE BOOL "" FORCE)
|
||||||
|
|||||||
@@ -130,7 +130,11 @@ inline std::filesystem::path PathFromUtf8(std::string_view text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr const char* kConfigFileName = "Config.toml";
|
inline constexpr const char* kConfigFileName = "Config.toml";
|
||||||
|
#ifdef _WIN32
|
||||||
|
inline constexpr const char* kApplicationDirectoryName = "WiiCompiledOpenXRVR";
|
||||||
|
#else
|
||||||
inline constexpr const char* kApplicationDirectoryName = "WiiCompiled";
|
inline constexpr const char* kApplicationDirectoryName = "WiiCompiled";
|
||||||
|
#endif
|
||||||
|
|
||||||
// Portable layout. A directory holding kPortableMarkerFileName is a portable root; every piece of
|
// Portable layout. A directory holding kPortableMarkerFileName is a portable root; every piece of
|
||||||
// runtime user state (Config.toml, NAND, Cache, Logs) lives in <root>/UserData instead of
|
// runtime user state (Config.toml, NAND, Cache, Logs) lives in <root>/UserData instead of
|
||||||
|
|||||||
@@ -907,6 +907,11 @@ void DrawGraphicsSettings() {
|
|||||||
// group, and keeping them out of Graphics stops that menu from running off the
|
// group, and keeping them out of Graphics stops that menu from running off the
|
||||||
// bottom of the screen.
|
// bottom of the screen.
|
||||||
void DrawVrSettings() {
|
void DrawVrSettings() {
|
||||||
|
const auto xrError = mkw::vr::OpenXRLastError();
|
||||||
|
if (!xrError.empty()) {
|
||||||
|
ImGui::TextWrapped("OpenXR unavailable: %s", xrError.c_str());
|
||||||
|
ImGui::TextWrapped("Playing on the desktop. Check your headset and active OpenXR runtime, then restart.");
|
||||||
|
}
|
||||||
if (ImGui::Checkbox("Enable OpenXR VR", &g_vrEnabled)) {
|
if (ImGui::Checkbox("Enable OpenXR VR", &g_vrEnabled)) {
|
||||||
RuntimeConfigFile::SetVrEnabled(g_vrEnabled);
|
RuntimeConfigFile::SetVrEnabled(g_vrEnabled);
|
||||||
}
|
}
|
||||||
@@ -1420,6 +1425,29 @@ void Draw() noexcept {
|
|||||||
// Wait for the frame worker's DONE phase: it has replayed the previous frame's ImGui draw lists
|
// Wait for the frame worker's DONE phase: it has replayed the previous frame's ImGui draw lists
|
||||||
// and started the next ImGui frame, so all overlay callers can now safely issue ImGui commands.
|
// and started the next ImGui frame, so all overlay callers can now safely issue ImGui commands.
|
||||||
aurora_wait_for_frame_worker();
|
aurora_wait_for_frame_worker();
|
||||||
|
// Explain fallback without interrupting gameplay or capturing input.
|
||||||
|
static std::string shownXrError;
|
||||||
|
static double xrNoticeUntil = 0.0;
|
||||||
|
const auto xrError = mkw::vr::OpenXRLastError();
|
||||||
|
if (!xrError.empty() && xrError != shownXrError) {
|
||||||
|
shownXrError = xrError;
|
||||||
|
xrNoticeUntil = ImGui::GetTime() + 15.0;
|
||||||
|
}
|
||||||
|
if (!shownXrError.empty() && ImGui::GetTime() < xrNoticeUntil) {
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(16.0f, 60.0f), ImGuiCond_Always);
|
||||||
|
ImGui::SetNextWindowBgAlpha(0.9f);
|
||||||
|
if (ImGui::Begin("OpenXR desktop fallback", nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize |
|
||||||
|
ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoFocusOnAppearing)) {
|
||||||
|
ImGui::PushTextWrapPos(440.0f);
|
||||||
|
ImGui::TextUnformatted("OpenXR unavailable - playing on the desktop.");
|
||||||
|
ImGui::TextUnformatted(shownXrError.c_str());
|
||||||
|
ImGui::TextUnformatted("Check your headset and active OpenXR runtime, then restart. Details: F10 > VR.");
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
// Also drive the Wii Remote rescan from here: PADRead runs it too, but this
|
// Also drive the Wii Remote rescan from here: PADRead runs it too, but this
|
||||||
// runs once per presented frame whatever the game is doing (e.g. sitting in
|
// runs once per presented frame whatever the game is doing (e.g. sitting in
|
||||||
// its "communications interrupted" prompt without polling pads). Same guest
|
// its "communications interrupted" prompt without polling pads). Same guest
|
||||||
|
|||||||
Reference in new issue
Block a user