Add XR windowed observation preflight tooling
This commit is contained in:
parent
8cd099c69b
commit
eff75c3cfa
9 changed files with 528 additions and 3 deletions
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"reportVersion": "ht-xr-windowed-live-observation/v1",
|
||||
"generatedAtUtc": "2026-07-02T07:07:08.0713455Z",
|
||||
"packageRoot": "C:\\HyperTwist_worktrees\\phase10validate_packaged_xr_20260702_rebuild",
|
||||
"smokeMaps": [
|
||||
"/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining",
|
||||
"/Game/HyperTwistTraining/Maps/L_HyperTwist_ClassicTraining"
|
||||
],
|
||||
"observationSeconds": 120,
|
||||
"timeoutSeconds": 150,
|
||||
"runtimeLaunchMode": "windowed",
|
||||
"resolution": {
|
||||
"width": 1600,
|
||||
"height": 900
|
||||
},
|
||||
"smokeReports": [
|
||||
{
|
||||
"reportVersion": "ht-xr-package-smoke/v1",
|
||||
"generatedAtUtc": "2026-07-02T07:07:08.1691135Z",
|
||||
"packageRoot": "C:\\HyperTwist_worktrees\\phase10validate_packaged_xr_20260702_rebuild",
|
||||
"executablePath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_xr_20260702_rebuild\\Windows\\UnrealHyperTwist.exe",
|
||||
"mapAssetPath": "/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining",
|
||||
"mapUrl": "/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining?game=/Script/UnrealHyperTwist.HyperTwistXrTrainingGameMode",
|
||||
"runtimeLaunchMode": "windowed",
|
||||
"observationSeconds": 120,
|
||||
"timeoutSeconds": 150,
|
||||
"resolution": {
|
||||
"width": 1600,
|
||||
"height": 900
|
||||
},
|
||||
"keepRunning": false,
|
||||
"runtimeReportPath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_xr_20260702_rebuild\\validation\\windowed-live-probe\\_Game_HyperTwistTraining_Maps_L_HyperTwist_FollowAlongTraining.runtime.json",
|
||||
"preflight": {
|
||||
"currentSessionId": 0,
|
||||
"explorerSessionIds": [
|
||||
1
|
||||
],
|
||||
"isInteractiveDesktopSession": false,
|
||||
"openXrActiveRuntimePath": null,
|
||||
"openXrActiveRuntimePresent": false
|
||||
},
|
||||
"result": "failed",
|
||||
"processId": null,
|
||||
"processStopped": false,
|
||||
"exitCode": null,
|
||||
"runtimeReport": null,
|
||||
"error": "Windowed XR validation must be launched from the interactive Windows desktop session. The current PowerShell session id \u00270\u0027 did not match Explorer desktop session ids \u00271\u0027. Re-run on the logged-in Windows desktop instead of the reverse-SSH/OpenSSH session."
|
||||
}
|
||||
],
|
||||
"preflight": {
|
||||
"currentSessionId": 0,
|
||||
"explorerSessionIds": [
|
||||
1
|
||||
],
|
||||
"isInteractiveDesktopSession": false,
|
||||
"openXrActiveRuntimePath": null,
|
||||
"openXrActiveRuntimePresent": false
|
||||
},
|
||||
"packagedHeadMountedDisplaySessionObserved": false,
|
||||
"packagedControllerInputObserved": false,
|
||||
"remainingGateIds": [
|
||||
|
||||
],
|
||||
"result": "failed",
|
||||
"error": "Windowed XR validation must be launched from the interactive Windows desktop session. The current PowerShell session id \u00270\u0027 did not match Explorer desktop session ids \u00271\u0027. Re-run on the logged-in Windows desktop instead of the reverse-SSH/OpenSSH session."
|
||||
}
|
||||
|
|
@ -229,3 +229,17 @@ widening.
|
|||
live packaged controller-input observation
|
||||
- the broader native XR/controller widening branch therefore remains closed
|
||||
until those two remaining live packaged gates are actually proven
|
||||
- the next same-day probe then fixed the truthful host reading for that final
|
||||
live gate itself:
|
||||
- the repo now carries `scripts\Invoke-HyperTwistXrWindowedObservation.ps1`
|
||||
as the bounded interactive-desktop wrapper for the remaining live proof
|
||||
- checked-in probe
|
||||
`docs/generated/xr/xr_windowed_live_observation_probe_2026-07-02.json`
|
||||
proves the reverse-SSH/OpenSSH launcher is currently Session `0` while the
|
||||
active Explorer desktop remains Session `1`, and that no `OpenXR` active
|
||||
runtime is currently registered on the host
|
||||
- therefore the remaining headset/controller reopen gate is no longer merely
|
||||
“some future windowed proof”; it is specifically:
|
||||
1. activate a real local `OpenXR` runtime on the Windows desktop
|
||||
2. run the first-party windowed observation wrapper from that interactive
|
||||
desktop session rather than through the reverse-SSH/OpenSSH session
|
||||
|
|
|
|||
|
|
@ -734,6 +734,32 @@ Operational rules reinforced by this proof:
|
|||
- when packaged proof is the goal, judge `-SkipBuild` freshness from the
|
||||
packaged-game receipt and binary timestamps against current build inputs, not
|
||||
from artifact existence alone
|
||||
- the repo now also carries `scripts\Invoke-HyperTwistXrWindowedObservation.ps1`
|
||||
as the bounded first-party interactive-desktop wrapper for that remaining
|
||||
live observation gate
|
||||
- the first exact-source probe through that wrapper on `2026-07-02` proved the
|
||||
current reverse-SSH/OpenSSH session itself is not the required windowed lane:
|
||||
- current PowerShell session id: `0`
|
||||
- Explorer desktop session ids: `1`
|
||||
- current `OpenXR` active-runtime registry entry: absent
|
||||
- checked-in aggregate probe:
|
||||
`docs/generated/xr/xr_windowed_live_observation_probe_2026-07-02.json`
|
||||
- operational reading after that probe:
|
||||
- the reverse-SSH lane remains authoritative for editor builds, automation,
|
||||
package/archive work, and headless `nullrhi` XR structural proof
|
||||
- the reverse-SSH lane is **not** the authoritative live windowed XR proof
|
||||
lane while it is entering Session `0` rather than the interactive desktop
|
||||
Session `1`
|
||||
- the remaining headset/controller observation gate must be run locally on
|
||||
the logged-in Windows desktop after an `OpenXR` runtime is actually active
|
||||
- canonical local Windows desktop command for that remaining gate:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File C:\HyperTwist_worktrees\phase10validate\scripts\Invoke-HyperTwistXrWindowedObservation.ps1 -PackageRoot C:\HyperTwist_worktrees\phase10validate_packaged_xr_20260702_rebuild
|
||||
```
|
||||
|
||||
- that local desktop run writes the aggregate live-observation report beneath:
|
||||
`C:\HyperTwist_worktrees\phase10validate_packaged_xr_20260702_rebuild\validation\windowed-live\`
|
||||
|
||||
## Addendum - 2026-06-13 (Phase 9B Unreal-native media-export proof)
|
||||
|
||||
|
|
|
|||
|
|
@ -405,6 +405,12 @@ scripts/run-hypertwist-remote-unreal-automation-sequence.sh \
|
|||
is an acceptable structural launch/ownership validation mode, but it does
|
||||
not satisfy the separate live headset-session or controller-input observation
|
||||
gate
|
||||
- for the remaining live `windowed` packaged XR observation gate, do not treat
|
||||
a reverse-SSH/OpenSSH Session `0` launch as interchangeable with the logged-
|
||||
in Windows desktop Session. The current first-party wrapper
|
||||
`scripts\Invoke-HyperTwistXrWindowedObservation.ps1` exists specifically so
|
||||
that gate can fail fast with preflight evidence when the launcher is not on
|
||||
the interactive desktop or when no `OpenXR` active runtime is present
|
||||
- for reverse-SSH/headless classic-cube replay-export validation, use
|
||||
`-NullRHI` only for the asset-authoring leg and `-RenderOffScreen` for the
|
||||
actual `MovieRenderQueue` render leg; they solve different failure modes
|
||||
|
|
|
|||
|
|
@ -408,6 +408,16 @@ truthfully claim:
|
|||
behavior, because the maintained reverse-SSH session required headless
|
||||
`nullrhi` runtime launch after windowed swapchain creation failed in the
|
||||
unattended host context
|
||||
- a same-day bounded probe then made the remaining live proof context fully
|
||||
explicit instead of leaving it as vague “future windowed validation”:
|
||||
- the repo now carries `scripts\Invoke-HyperTwistXrWindowedObservation.ps1`
|
||||
for the remaining live packaged observation gate
|
||||
- checked-in probe
|
||||
`docs/generated/xr/xr_windowed_live_observation_probe_2026-07-02.json`
|
||||
proves the reverse-SSH/OpenSSH launcher is currently Session `0` while the
|
||||
interactive Explorer desktop is Session `1`
|
||||
- that same probe also keeps the local runtime blocker explicit by recording
|
||||
that no `OpenXR` active runtime is currently registered on the host
|
||||
- the current remaining unproven pieces therefore are:
|
||||
- live packaged headset-session observation on the Windows lane
|
||||
- live packaged controller-input observation on the Windows lane
|
||||
|
|
@ -488,5 +498,7 @@ first clean remaining implementation packet should be:
|
|||
1. live packaged headset-session plus controller-input observation on the
|
||||
Windows Unreal lane, kept explicit above the now-landed bounded runtime-
|
||||
owner plus controller settings/rebinding substrate and above the already-
|
||||
shipped headless `nullrhi` packaged structural proof
|
||||
shipped headless `nullrhi` packaged structural proof, and run from the
|
||||
interactive logged-in Windows desktop session with an active local `OpenXR`
|
||||
runtime rather than from the reverse-SSH/OpenSSH Session `0` lane
|
||||
2. public/product copy update only after that live packaged proof exists
|
||||
|
|
|
|||
|
|
@ -2462,6 +2462,46 @@ Latest same-family responsive public-route expansion follow-up on `2026-06-29`:
|
|||
- the broader native XR/controller widening branch therefore remains closed
|
||||
until those two remaining live packaged gates are actually proven
|
||||
|
||||
## XR interactive windowed-observation preflight continuation (`2026-07-02`)
|
||||
|
||||
- the next same-family continuation then stopped treating the remaining live
|
||||
headset/controller proof as if any generic `windowed` launch context would
|
||||
do
|
||||
- current exact-source truth is now explicitly source-backed through:
|
||||
- `scripts/Launch-HyperTwistXrPackage.ps1`
|
||||
- `scripts/Invoke-HyperTwistXrWindowedObservation.ps1`
|
||||
- checked-in probe:
|
||||
`docs/generated/xr/xr_windowed_live_observation_probe_2026-07-02.json`
|
||||
- the owned package launcher now records windowed preflight truth directly into
|
||||
the smoke report before attempting the actual launch:
|
||||
- current PowerShell session id
|
||||
- Explorer desktop session ids
|
||||
- whether the launcher is already on the interactive desktop session
|
||||
- the current `OpenXR` active-runtime path and presence state
|
||||
- the new dedicated windowed-observation wrapper then aggregates that preflight
|
||||
into one source-controlled report for the remaining live headset/controller
|
||||
gate instead of leaving the operator to assemble the facts manually
|
||||
- the exact-source probe on maintained Windows root then proved:
|
||||
- reverse-SSH/OpenSSH PowerShell session id: `0`
|
||||
- Explorer desktop session id: `1`
|
||||
- current `OpenXR` active runtime: absent
|
||||
- wrapper result: `failed` immediately and truthfully, without wasting the
|
||||
full observation timeout on a doomed Session `0` launch
|
||||
- current truthful reading after this follow-up:
|
||||
- the reverse-SSH lane remains the right lane for editor builds, automation,
|
||||
packaging, and headless `nullrhi` XR structural proof
|
||||
- the reverse-SSH lane is not the current live `windowed` headset/controller
|
||||
proof lane
|
||||
- the remaining live packaged XR gate now has an explicit first-party next
|
||||
action: activate the local `OpenXR` runtime on the logged-in Windows
|
||||
desktop and run `scripts/Invoke-HyperTwistXrWindowedObservation.ps1`
|
||||
there, not through the OpenSSH session
|
||||
- canonical local Windows desktop command for that next action:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File C:\HyperTwist_worktrees\phase10validate\scripts\Invoke-HyperTwistXrWindowedObservation.ps1 -PackageRoot C:\HyperTwist_worktrees\phase10validate_packaged_xr_20260702_rebuild
|
||||
```
|
||||
|
||||
## Latest protected launch-status responsive recovery plus tooling rerun (`2026-06-29`)
|
||||
|
||||
- the next same-family browser pass fixed a real small-screen regression on the
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
245
scripts/Invoke-HyperTwistXrWindowedObservation.ps1
Normal file
245
scripts/Invoke-HyperTwistXrWindowedObservation.ps1
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
param(
|
||||
[string]$PackageRoot = 'C:\HyperTwist\packaged\xr',
|
||||
[string[]]$SmokeMaps = @(
|
||||
'/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining',
|
||||
'/Game/HyperTwistTraining/Maps/L_HyperTwist_ClassicTraining'
|
||||
),
|
||||
[double]$ObservationSeconds = 120.0,
|
||||
[double]$TimeoutSeconds = 150.0,
|
||||
[int]$ResX = 1600,
|
||||
[int]$ResY = 900,
|
||||
[string]$ValidationDirectory = '',
|
||||
[string]$AggregateReportPath = '',
|
||||
[switch]$KeepRunning
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Write-Utf8JsonFile {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Path,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[object]$Value
|
||||
)
|
||||
|
||||
$ParentPath = Split-Path -Parent $Path
|
||||
if (-not [string]::IsNullOrWhiteSpace($ParentPath))
|
||||
{
|
||||
New-Item -ItemType Directory -Force -Path $ParentPath | Out-Null
|
||||
}
|
||||
|
||||
$Json = $Value | ConvertTo-Json -Depth 12
|
||||
$Utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($Path, $Json, $Utf8NoBom)
|
||||
}
|
||||
|
||||
function Read-JsonFile {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json
|
||||
}
|
||||
|
||||
function Convert-PathToken {
|
||||
param(
|
||||
[string]$Value
|
||||
)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Value))
|
||||
{
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
return ($Value -replace '[\\/:*?"<>| ?=&]', '_')
|
||||
}
|
||||
|
||||
function Get-JsonPropertyValue {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[object]$Object,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string[]]$Names,
|
||||
[object]$Default = $null
|
||||
)
|
||||
|
||||
foreach ($Name in $Names)
|
||||
{
|
||||
$Property = $Object.PSObject.Properties[$Name]
|
||||
if ($null -ne $Property)
|
||||
{
|
||||
return $Property.Value
|
||||
}
|
||||
}
|
||||
|
||||
return $Default
|
||||
}
|
||||
|
||||
$ResolvedSmokeMaps =
|
||||
@($SmokeMaps) |
|
||||
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
|
||||
Select-Object -Unique
|
||||
|
||||
if ($ResolvedSmokeMaps.Count -eq 0)
|
||||
{
|
||||
throw 'Provide at least one XR smoke map.'
|
||||
}
|
||||
|
||||
$LaunchScriptPath = Join-Path (Split-Path -Parent $PSCommandPath) 'Launch-HyperTwistXrPackage.ps1'
|
||||
if (-not (Test-Path -LiteralPath $LaunchScriptPath))
|
||||
{
|
||||
throw "Launch script was not found at '$LaunchScriptPath'."
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $PackageRoot))
|
||||
{
|
||||
throw "Package root '$PackageRoot' was not found."
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($ValidationDirectory))
|
||||
{
|
||||
$ValidationDirectory = Join-Path $PackageRoot 'validation\windowed-live'
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($AggregateReportPath))
|
||||
{
|
||||
$AggregateReportPath = Join-Path $ValidationDirectory 'xr-windowed-live-observation-report.json'
|
||||
}
|
||||
|
||||
$AggregateReport = [ordered]@{
|
||||
reportVersion = 'ht-xr-windowed-live-observation/v1'
|
||||
generatedAtUtc = [DateTime]::UtcNow.ToString('o')
|
||||
packageRoot = (Resolve-Path -LiteralPath $PackageRoot).Path
|
||||
smokeMaps = @($ResolvedSmokeMaps)
|
||||
observationSeconds = $ObservationSeconds
|
||||
timeoutSeconds = $TimeoutSeconds
|
||||
runtimeLaunchMode = 'windowed'
|
||||
resolution = [ordered]@{
|
||||
width = $ResX
|
||||
height = $ResY
|
||||
}
|
||||
smokeReports = @()
|
||||
preflight = $null
|
||||
packagedHeadMountedDisplaySessionObserved = $false
|
||||
packagedControllerInputObserved = $false
|
||||
remainingGateIds = @()
|
||||
result = 'failed'
|
||||
error = $null
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
foreach ($SmokeMap in $ResolvedSmokeMaps)
|
||||
{
|
||||
$SmokeReportPath = Join-Path $ValidationDirectory (
|
||||
'{0}.json' -f (Convert-PathToken -Value $SmokeMap)
|
||||
)
|
||||
|
||||
& $LaunchScriptPath `
|
||||
-PackageRoot $PackageRoot `
|
||||
-MapAssetPath $SmokeMap `
|
||||
-ObservationSeconds $ObservationSeconds `
|
||||
-TimeoutSeconds $TimeoutSeconds `
|
||||
-RuntimeLaunchMode 'windowed' `
|
||||
-ResX $ResX `
|
||||
-ResY $ResY `
|
||||
-ReportPath $SmokeReportPath `
|
||||
-KeepRunning:$KeepRunning
|
||||
|
||||
if (-not (Test-Path -LiteralPath $SmokeReportPath))
|
||||
{
|
||||
throw "Windowed XR smoke report '$SmokeReportPath' was not written for '$SmokeMap'."
|
||||
}
|
||||
|
||||
$SmokeReport = Read-JsonFile -Path $SmokeReportPath
|
||||
if ($null -eq $SmokeReport)
|
||||
{
|
||||
throw "Windowed XR smoke report '$SmokeReportPath' could not be parsed."
|
||||
}
|
||||
|
||||
$AggregateReport.smokeReports += $SmokeReport
|
||||
|
||||
if ($null -eq $AggregateReport.preflight)
|
||||
{
|
||||
$AggregateReport.preflight = Get-JsonPropertyValue `
|
||||
-Object $SmokeReport `
|
||||
-Names @('preflight', 'Preflight') `
|
||||
-Default $null
|
||||
}
|
||||
|
||||
$RuntimeReport = Get-JsonPropertyValue `
|
||||
-Object $SmokeReport `
|
||||
-Names @('runtimeReport', 'RuntimeReport') `
|
||||
-Default $null
|
||||
|
||||
if ($null -ne $RuntimeReport)
|
||||
{
|
||||
$AggregateReport.packagedHeadMountedDisplaySessionObserved =
|
||||
$AggregateReport.packagedHeadMountedDisplaySessionObserved -or [bool](Get-JsonPropertyValue `
|
||||
-Object $RuntimeReport `
|
||||
-Names @('bObservedHeadMountedDisplaySession', 'ObservedHeadMountedDisplaySession') `
|
||||
-Default $false)
|
||||
$AggregateReport.packagedControllerInputObserved =
|
||||
$AggregateReport.packagedControllerInputObserved -or [bool](Get-JsonPropertyValue `
|
||||
-Object $RuntimeReport `
|
||||
-Names @('bObservedControllerInputActivity', 'ObservedControllerInputActivity') `
|
||||
-Default $false)
|
||||
|
||||
foreach ($RemainingGateId in @((Get-JsonPropertyValue `
|
||||
-Object $RuntimeReport `
|
||||
-Names @('remainingGateIds', 'RemainingGateIds') `
|
||||
-Default @())))
|
||||
{
|
||||
if (-not [string]::IsNullOrWhiteSpace($RemainingGateId))
|
||||
{
|
||||
$AggregateReport.remainingGateIds += $RemainingGateId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$AggregateReport.remainingGateIds =
|
||||
@($AggregateReport.remainingGateIds | Select-Object -Unique)
|
||||
|
||||
if ($AggregateReport.packagedHeadMountedDisplaySessionObserved `
|
||||
-and $AggregateReport.packagedControllerInputObserved)
|
||||
{
|
||||
$AggregateReport.result = 'passed'
|
||||
}
|
||||
else
|
||||
{
|
||||
$AggregateReport.result = 'pending-live-observation'
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if ($null -ne $SmokeReportPath -and (Test-Path -LiteralPath $SmokeReportPath))
|
||||
{
|
||||
$FailedSmokeReport = Read-JsonFile -Path $SmokeReportPath
|
||||
if ($null -ne $FailedSmokeReport)
|
||||
{
|
||||
$AggregateReport.smokeReports += $FailedSmokeReport
|
||||
if ($null -eq $AggregateReport.preflight)
|
||||
{
|
||||
$AggregateReport.preflight = Get-JsonPropertyValue `
|
||||
-Object $FailedSmokeReport `
|
||||
-Names @('preflight', 'Preflight') `
|
||||
-Default $null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$AggregateReport.error = $_.Exception.Message
|
||||
if ($AggregateReport.remainingGateIds.Count -gt 0)
|
||||
{
|
||||
$AggregateReport.remainingGateIds =
|
||||
@($AggregateReport.remainingGateIds | Select-Object -Unique)
|
||||
}
|
||||
|
||||
Write-Utf8JsonFile -Path $AggregateReportPath -Value $AggregateReport
|
||||
throw
|
||||
}
|
||||
|
||||
Write-Utf8JsonFile -Path $AggregateReportPath -Value $AggregateReport
|
||||
|
|
@ -62,6 +62,107 @@ function Get-JsonPropertyValue {
|
|||
return $Default
|
||||
}
|
||||
|
||||
function Get-CurrentSessionId {
|
||||
$CurrentProcess = Get-Process -Id $PID -ErrorAction Stop
|
||||
return [int]$CurrentProcess.SessionId
|
||||
}
|
||||
|
||||
function Get-ExplorerSessionIds {
|
||||
return @(
|
||||
Get-Process explorer -ErrorAction SilentlyContinue |
|
||||
Select-Object -ExpandProperty SessionId -Unique
|
||||
)
|
||||
}
|
||||
|
||||
function Get-OpenXrActiveRuntimePath {
|
||||
$RegistryPaths = @(
|
||||
'HKLM:\SOFTWARE\Khronos\OpenXR\1',
|
||||
'HKLM:\SOFTWARE\WOW6432Node\Khronos\OpenXR\1'
|
||||
)
|
||||
|
||||
foreach ($RegistryPath in $RegistryPaths)
|
||||
{
|
||||
if (-not (Test-Path -LiteralPath $RegistryPath))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$RegistryItem = Get-ItemProperty -LiteralPath $RegistryPath
|
||||
if (-not [string]::IsNullOrWhiteSpace($RegistryItem.ActiveRuntime))
|
||||
{
|
||||
return [string]$RegistryItem.ActiveRuntime
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Get-XrWindowedPreflight {
|
||||
$CurrentSessionId = Get-CurrentSessionId
|
||||
$ExplorerSessionIds = @(Get-ExplorerSessionIds)
|
||||
$OpenXrActiveRuntimePath = Get-OpenXrActiveRuntimePath
|
||||
$OpenXrActiveRuntimePresent =
|
||||
-not [string]::IsNullOrWhiteSpace($OpenXrActiveRuntimePath) `
|
||||
-and (Test-Path -LiteralPath $OpenXrActiveRuntimePath)
|
||||
|
||||
return [ordered]@{
|
||||
currentSessionId = $CurrentSessionId
|
||||
explorerSessionIds = @($ExplorerSessionIds)
|
||||
isInteractiveDesktopSession = [bool]($ExplorerSessionIds -contains $CurrentSessionId)
|
||||
openXrActiveRuntimePath = $OpenXrActiveRuntimePath
|
||||
openXrActiveRuntimePresent = [bool]$OpenXrActiveRuntimePresent
|
||||
}
|
||||
}
|
||||
|
||||
function Assert-XrWindowedPreflight {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[object]$Preflight
|
||||
)
|
||||
|
||||
if (-not [bool]$Preflight.isInteractiveDesktopSession)
|
||||
{
|
||||
$ExplorerSessionDisplay = if ($null -ne $Preflight.explorerSessionIds `
|
||||
-and $Preflight.explorerSessionIds.Count -gt 0)
|
||||
{
|
||||
($Preflight.explorerSessionIds -join ', ')
|
||||
}
|
||||
else
|
||||
{
|
||||
'none'
|
||||
}
|
||||
|
||||
throw (
|
||||
"Windowed XR validation must be launched from the interactive Windows desktop session. " +
|
||||
"The current PowerShell session id '{0}' did not match Explorer desktop session ids '{1}'. " +
|
||||
"Re-run on the logged-in Windows desktop instead of the reverse-SSH/OpenSSH session."
|
||||
) -f $Preflight.currentSessionId, $ExplorerSessionDisplay
|
||||
}
|
||||
|
||||
if (-not [bool]$Preflight.openXrActiveRuntimePresent)
|
||||
{
|
||||
if ([string]::IsNullOrWhiteSpace([string]$Preflight.openXrActiveRuntimePath))
|
||||
{
|
||||
throw (
|
||||
"Windowed XR validation requires an installed active OpenXR runtime, but no OpenXR ActiveRuntime registry entry was found. " +
|
||||
"Activate SteamVR, Oculus, Windows Mixed Reality, or another local OpenXR runtime on the interactive desktop and rerun."
|
||||
)
|
||||
}
|
||||
|
||||
throw (
|
||||
"Windowed XR validation requires an installed active OpenXR runtime, but the configured ActiveRuntime path '{0}' was not present on disk. " +
|
||||
"Repair or reactivate the local OpenXR runtime on the interactive desktop and rerun."
|
||||
) -f $Preflight.openXrActiveRuntimePath
|
||||
}
|
||||
}
|
||||
|
||||
function Convert-PathToken {
|
||||
param(
|
||||
[string]$Value
|
||||
|
|
@ -115,6 +216,15 @@ if (Test-Path -LiteralPath $RuntimeReportPath)
|
|||
Remove-Item -LiteralPath $RuntimeReportPath -Force
|
||||
}
|
||||
|
||||
$WindowedPreflight = if ($ResolvedRuntimeLaunchMode -eq 'windowed')
|
||||
{
|
||||
Get-XrWindowedPreflight
|
||||
}
|
||||
else
|
||||
{
|
||||
$null
|
||||
}
|
||||
|
||||
$ArgumentList = @(
|
||||
$ResolvedMapUrl,
|
||||
'-log',
|
||||
|
|
@ -144,7 +254,6 @@ switch ($ResolvedRuntimeLaunchMode)
|
|||
}
|
||||
}
|
||||
|
||||
Write-Host "Launching packaged XR validation lane from '$ExecutablePath'..."
|
||||
$Process = $null
|
||||
$Report = [ordered]@{
|
||||
reportVersion = 'ht-xr-package-smoke/v1'
|
||||
|
|
@ -169,6 +278,7 @@ $Report = [ordered]@{
|
|||
}
|
||||
keepRunning = [bool]$KeepRunning
|
||||
runtimeReportPath = $RuntimeReportPath
|
||||
preflight = $WindowedPreflight
|
||||
result = 'failed'
|
||||
processId = $null
|
||||
processStopped = $false
|
||||
|
|
@ -179,6 +289,12 @@ $Report = [ordered]@{
|
|||
|
||||
try
|
||||
{
|
||||
if ($ResolvedRuntimeLaunchMode -eq 'windowed')
|
||||
{
|
||||
Assert-XrWindowedPreflight -Preflight $WindowedPreflight
|
||||
}
|
||||
|
||||
Write-Host "Launching packaged XR validation lane from '$ExecutablePath'..."
|
||||
$Process = Start-Process `
|
||||
-FilePath $ExecutablePath `
|
||||
-ArgumentList $ArgumentList `
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue