mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 09:00:28 +02:00
The Steam Frame runs Android apps through Lepton with SteamVR's OpenXR runtime. A third headset flavour, steamFrame, targets it: - -mcpu=cortex-x4+nosve for the Snapdragon 8 Gen 3 (its firmware does not expose SVE, which clang otherwise auto-vectorises with), from one flavour-to-CPU map that the kit export now reads instead of guessing from the variant name. - MKW_ANDROID_HEADSET=steam_frame defines MKW_HEADSET_STEAM_FRAME for the runtime's own targets, for Frame-specific defaults. - A manifest without the Horizon OS entries, and FrameEntryActivity as the single real MAIN/LAUNCHER activity with the Khronos and Oculus VR categories, which Lepton needs to start an app in VR. It opens the setup panel and, when the selected game can start, the game on top. - XR_VALVE_frame_controller_interaction: the Frame controller profile with its left D-pad (new dpad_* actions, the Wii Remote's D-pad or the gamepad's), View as menu and the left shoulder as the panel button. Also requested on Windows for SteamVR streaming to a Frame. - Build-Quest.ps1, Build-QuestGame.ps1 and Run-Quest.ps1 take -Headset frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3
144 lines
7.3 KiB
PowerShell
144 lines
7.3 KiB
PowerShell
# Builds the standalone Meta Quest APK on a Windows host.
|
|
#
|
|
# powershell -ExecutionPolicy Bypass -File android/Build-Quest.ps1 [-Generated <dir>]
|
|
# [-Headset modern|quest1|frame] [-Configuration debug|release] [-Install]
|
|
#
|
|
# -Headset frame builds the Steam Frame flavour (steamFrame), which runs under Lepton, SteamOS's
|
|
# Android layer, with SteamVR's OpenXR runtime (docs/quest-port.md, "Steam Frame").
|
|
#
|
|
# One app offers both games: the APK carries a kit for the base game, and for Retro Rewind too
|
|
# when -Generated holds a translation that includes the mod.
|
|
#
|
|
# -Generated names the translator output for the disc you own: the directory
|
|
# holding data_sections_init.cpp, RuntimeConfig.h and build_shards/shards.cmake.
|
|
# It defaults to the installer's build workspace next to this checkout. The
|
|
# Windows-generated tree is used as-is; runtime/cmake/PublicProducts.cmake
|
|
# rewrites its blob assembly for ELF at configure time.
|
|
#
|
|
# Prerequisites (see docs/quest-port.md): JDK 17, the Android SDK with NDK
|
|
# 29.0.14206865 and CMake 3.22.1, and android/Prepare-QuestDependencies.ps1
|
|
# having staged the SDL3 AAR.
|
|
#
|
|
# Dawn is built from source with Aurora's patches (android/Build-QuestDawn.ps1:
|
|
# fragment density maps for foveated rendering) and cached under
|
|
# .scratch/quest-dawn; the first build takes a while. -StockDawn links the
|
|
# stock prebuilt package instead, which leaves foveated rendering unavailable.
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$Generated = '',
|
|
[string]$Dependencies = '',
|
|
[string]$CMakeDir = '',
|
|
[ValidateSet('modern', 'quest1', 'frame')] [string]$Headset = 'modern',
|
|
[ValidateSet('debug', 'release')] [string]$Configuration = 'debug',
|
|
[switch]$Install,
|
|
[switch]$StockDawn
|
|
)
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$repo = (Resolve-Path (Join-Path $root '..')).Path
|
|
|
|
if (-not $Generated) {
|
|
$Generated = Join-Path $repo '.scratch\vr-build-workspace\BuildWorkspace\generated'
|
|
}
|
|
if (-not (Test-Path (Join-Path $Generated 'build_shards\shards.cmake'))) {
|
|
throw "No translated graph at $Generated (expected build_shards\shards.cmake). Run the translator first; see docs/quest-port.md."
|
|
}
|
|
if (-not (Test-Path (Join-Path $root 'app\libs\SDL3-3.4.4.aar'))) {
|
|
throw 'SDL3 AAR missing; run android/Prepare-QuestDependencies.ps1 first.'
|
|
}
|
|
|
|
$javaHome = if ($env:JAVA_HOME) { $env:JAVA_HOME } else { 'C:\Program Files\Java\jdk-17' }
|
|
$sdkRoot = if ($env:ANDROID_HOME) { $env:ANDROID_HOME } elseif ($env:ANDROID_SDK_ROOT) { $env:ANDROID_SDK_ROOT } else { Join-Path $env:LOCALAPPDATA 'Android\Sdk' }
|
|
if (-not (Test-Path (Join-Path $javaHome 'bin\java.exe'))) { throw "JDK 17 not found at $javaHome (set JAVA_HOME)" }
|
|
if (-not (Test-Path $sdkRoot)) { throw "Android SDK not found at $sdkRoot (set ANDROID_HOME)" }
|
|
|
|
$env:JAVA_HOME = $javaHome
|
|
$env:ANDROID_HOME = $sdkRoot
|
|
$env:ANDROID_SDK_ROOT = $sdkRoot
|
|
|
|
# aurora-main requires CMake 3.25+, newer than the SDK's bundled 3.22.1. Point
|
|
# the Android Gradle plugin at a system CMake through local.properties and put
|
|
# the SDK's Ninja on PATH, which a non-bundled CMake needs.
|
|
if (-not $CMakeDir) {
|
|
$cmakeExe = Get-Command cmake.exe -ErrorAction SilentlyContinue
|
|
if ($cmakeExe) { $CMakeDir = Split-Path -Parent (Split-Path -Parent $cmakeExe.Source) }
|
|
}
|
|
if (-not $CMakeDir -or -not (Test-Path (Join-Path $CMakeDir 'bin\cmake.exe'))) {
|
|
throw 'No CMake 3.25+ found; install one or pass -CMakeDir <install root>'
|
|
}
|
|
$sdkCMake = Get-ChildItem -Path (Join-Path $sdkRoot 'cmake') -Directory | Sort-Object Name -Descending | Select-Object -First 1
|
|
if ($sdkCMake) { $env:PATH = (Join-Path $sdkCMake.FullName 'bin') + ';' + $env:PATH }
|
|
# Parenthesised: PowerShell's comma binds tighter than +, which would join both
|
|
# properties into a single line.
|
|
$localProperties = @(
|
|
('sdk.dir=' + $sdkRoot.Replace('\', '\\')),
|
|
('cmake.dir=' + $CMakeDir.Replace('\', '\\'))
|
|
)
|
|
Set-Content -Path (Join-Path $root 'local.properties') -Value $localProperties -Encoding ascii
|
|
|
|
if (-not $Dependencies) {
|
|
$candidate = Join-Path $repo '.scratch\vr-build-workspace\BuildWorkspace\Dependencies'
|
|
if (Test-Path $candidate) { $Dependencies = $candidate }
|
|
}
|
|
|
|
$variant = (Get-Culture).TextInfo.ToTitleCase($Configuration)
|
|
# The Gradle flavour and the -mcpu target its kit must record (headsetCpus in app/build.gradle.kts).
|
|
$flavourDir, $expectedCpu = switch ($Headset) {
|
|
'quest1' { 'quest1', 'kryo' }
|
|
'frame' { 'steamFrame', 'cortex-x4+nosve' }
|
|
default { 'modernQuest', 'cortex-a77' }
|
|
}
|
|
$flavour = $flavourDir.Substring(0, 1).ToUpperInvariant() + $flavourDir.Substring(1)
|
|
$task = "app:assemble$flavour$variant"
|
|
$gradleArgs = @(
|
|
'--project-dir', $root,
|
|
"-PmkwGeneratedDir=$Generated"
|
|
)
|
|
if ($Dependencies) { $gradleArgs += "-PmkwDependenciesDir=$Dependencies" }
|
|
if (-not $StockDawn) {
|
|
$dawnWork = Join-Path $repo '.scratch\quest-dawn'
|
|
& (Join-Path $root 'Build-QuestDawn.ps1') -WorkDirectory $dawnWork
|
|
$gradleArgs += "-PmkwQuestDawnDir=$(Join-Path $dawnWork 'package')"
|
|
}
|
|
$gradleArgs += $task
|
|
Write-Host "gradlew $($gradleArgs -join ' ')"
|
|
& (Join-Path $root 'gradlew.bat') @gradleArgs
|
|
if ($LASTEXITCODE -ne 0) { throw "Gradle failed ($LASTEXITCODE)" }
|
|
|
|
$apkDir = Join-Path $root "app\build\outputs\apk\$flavourDir\$Configuration"
|
|
$apk = Get-ChildItem -Path $apkDir -Filter '*.apk' | Select-Object -First 1
|
|
if (-not $apk) { throw "No APK under $apkDir" }
|
|
Write-Host "APK: $($apk.FullName)"
|
|
|
|
# The APK must be distributable: no translated game inside, only the game kit and the toolchain
|
|
# that builds one on the headset.
|
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
$archive = [IO.Compression.ZipFile]::OpenRead($apk.FullName)
|
|
try {
|
|
$gameLibraries = @($archive.Entries | Where-Object { $_.FullName -match '^lib/[^/]+/libmain[^/]*\.so$' })
|
|
$kitEntry = @($archive.Entries | Where-Object { $_.FullName -eq 'assets/game_kit/kit.json' }) | Select-Object -First 1
|
|
$kitCpu = if ($kitEntry) {
|
|
$reader = New-Object IO.StreamReader($kitEntry.Open())
|
|
try { ($reader.ReadToEnd() | ConvertFrom-Json).androidCpu } finally { $reader.Dispose() }
|
|
} else { '' }
|
|
$hasToolchain = @($archive.Entries | Where-Object { $_.FullName -eq 'assets/quest_toolchain/files.zip' }).Count -gt 0
|
|
} finally { $archive.Dispose() }
|
|
if ($gameLibraries.Count -gt 0) { throw "The APK contains a translated game library: $($gameLibraries.FullName -join ', ')" }
|
|
if (-not $kitEntry) { throw 'The APK has no game kit (assets/game_kit/kit.json)' }
|
|
if ($kitCpu -ne $expectedCpu) { throw "The $Headset APK contains a game kit for CPU '$kitCpu', expected '$expectedCpu'" }
|
|
if (-not $hasToolchain) { throw 'The APK has no build toolchain (assets/quest_toolchain/files.zip)' }
|
|
|
|
if ($Install) {
|
|
$adb = Join-Path $sdkRoot 'platform-tools\adb.exe'
|
|
& $adb install -r $apk.FullName
|
|
if ($LASTEXITCODE -ne 0) { throw "adb install failed ($LASTEXITCODE)" }
|
|
if ($Headset -eq 'quest1') {
|
|
Write-Host 'Installed. Use WiiCompiled Settings for setup, then launch WiiCompiled VR directly from the library.'
|
|
} elseif ($Headset -eq 'frame') {
|
|
Write-Host 'Installed. Build a game on this PC with android/Build-QuestGame.ps1 -Headset frame -Install, then start WiiCompiled VR from the Steam library.'
|
|
} else {
|
|
Write-Host 'Installed. Build a game with Build on this Quest in the launcher, or on this PC with android/Build-QuestGame.ps1 -Install.'
|
|
}
|
|
}
|