hypertwist/scripts/Invoke-HyperTwistVirtual4DMapAuthoring.ps1
2026-07-23 17:23:24 +00:00

134 lines
5 KiB
PowerShell

param(
[string]$ProjectRoot = 'C:\HyperTwist',
[string]$UnrealEditorCmdPath = 'C:\Program Files\Epic Games\UE_5.7\Engine\Binaries\Win64\UnrealEditor-Cmd.exe',
[string]$PythonScriptPath
)
$ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($PythonScriptPath))
{
$PythonScriptPath = Join-Path $ProjectRoot 'scripts\hypertwist_author_virtual_4d_training_maps.py'
}
$UProjectPath = Join-Path $ProjectRoot 'UnrealHyperTwist\UnrealHyperTwist.uproject'
$ReceiptDirectory = Join-Path $ProjectRoot 'UnrealHyperTwist\Saved\HyperTwistMapAuthoring'
$ManifestPath = Join-Path $ProjectRoot 'docs\generated\virtual_4d_training_maps\virtual_4d_dedicated_map_manifest.json'
$Orders = @(2, 3, 4, 5, 6)
if (-not (Test-Path -LiteralPath $UnrealEditorCmdPath -PathType Leaf))
{
throw "UnrealEditor-Cmd.exe was not found at '$UnrealEditorCmdPath'."
}
if (-not (Test-Path -LiteralPath $UProjectPath -PathType Leaf))
{
throw "UnrealHyperTwist project file was not found at '$UProjectPath'."
}
if (-not (Test-Path -LiteralPath $PythonScriptPath -PathType Leaf))
{
throw "Virtual 4D map authoring script was not found at '$PythonScriptPath'."
}
$NormalizedPythonScriptPath = $PythonScriptPath -replace '\\', '/'
foreach ($Order in $Orders)
{
$MapName = "L_HyperTwist_MagicCube4D_${Order}x${Order}x${Order}x${Order}Training"
$MapPath = Join-Path $ProjectRoot "UnrealHyperTwist\Content\HyperTwistTraining\Maps\$MapName.umap"
$ReceiptPath = Join-Path $ReceiptDirectory "virtual_4d_${Order}x_complete.json"
$ExpectedGameMode = if ($Order -eq 2)
{
'/Script/UnrealHyperTwist.HyperTwistMelindaProjectionGameMode'
}
else
{
"/Script/UnrealHyperTwist.HyperTwistVirtual${Order}${Order}${Order}${Order}ProjectionGameMode"
}
Remove-Item -LiteralPath $ReceiptPath -Force -ErrorAction SilentlyContinue
$AuthoringStartedAtUtc = [DateTime]::UtcNow
$env:HYPERTWIST_VIRTUAL_4D_ORDER = [string]$Order
Write-Host "Authoring exact ${Order}x${Order}x${Order}x${Order} HyperTwist training map..."
& $UnrealEditorCmdPath `
$UProjectPath `
"-ExecutePythonScript=$NormalizedPythonScriptPath" `
-unattended `
-nop4 `
-nullrhi `
-nosound `
-nosplash `
-stdout `
-FullStdOutLogOutput `
-log
$AuthoringExitCode = $LASTEXITCODE
$Receipt = $null
if (Test-Path -LiteralPath $ReceiptPath -PathType Leaf)
{
$Receipt = Get-Content -LiteralPath $ReceiptPath -Raw | ConvertFrom-Json
}
$MapHash = if (Test-Path -LiteralPath $MapPath -PathType Leaf)
{
(Get-FileHash -LiteralPath $MapPath -Algorithm MD5).Hash.ToLowerInvariant()
}
else
{
''
}
$ReceiptIsFresh = $Receipt -and `
(Get-Item -LiteralPath $ReceiptPath).LastWriteTimeUtc -ge $AuthoringStartedAtUtc.AddSeconds(-2)
$ReceiptIsValid = $ReceiptIsFresh -and `
$Receipt.authoringComplete -eq $true -and `
$Receipt.order -eq $Order -and `
$Receipt.gameModeClassPath -eq $ExpectedGameMode -and `
$Receipt.mapHashMd5 -eq $MapHash
if (-not $ReceiptIsValid)
{
Remove-Item Env:\HYPERTWIST_VIRTUAL_4D_ORDER -ErrorAction SilentlyContinue
if ($AuthoringExitCode -ne 0)
{
throw "Virtual 4D map authoring failed with exit code $AuthoringExitCode before a valid receipt was written for order $Order."
}
throw "Virtual 4D map authoring exited without a fresh hash-bound receipt for order $Order."
}
if ($AuthoringExitCode -ne 0)
{
Write-Warning "UnrealEditor-Cmd exited with code $AuthoringExitCode after order $Order completed and wrote a valid receipt. Accepting the known post-completion headless shutdown failure."
}
}
Remove-Item Env:\HYPERTWIST_VIRTUAL_4D_ORDER -ErrorAction SilentlyContinue
if (-not (Test-Path -LiteralPath $ManifestPath -PathType Leaf))
{
throw "Virtual 4D map manifest was not generated at '$ManifestPath'."
}
$Manifest = Get-Content -LiteralPath $ManifestPath -Raw | ConvertFrom-Json
$ManifestEntries = @($Manifest.entries)
if ($Manifest.schemaVersion -ne 'hypertwist/virtual-4d-dedicated-map-manifest/v1' `
-or $ManifestEntries.Count -ne $Orders.Count)
{
throw "Virtual 4D map manifest does not contain the complete 2x through 6x route set."
}
foreach ($Order in $Orders)
{
$Entry = @($ManifestEntries | Where-Object { $_.order -eq $Order })
if ($Entry.Count -ne 1)
{
throw "Virtual 4D map manifest does not contain exactly one entry for order $Order."
}
$MapPath = Join-Path $ProjectRoot $Entry[0].mapFileRelativePath
if (-not (Test-Path -LiteralPath $MapPath -PathType Leaf))
{
throw "Authored virtual 4D map is missing at '$MapPath'."
}
$MapHash = (Get-FileHash -LiteralPath $MapPath -Algorithm MD5).Hash.ToLowerInvariant()
if ($Entry[0].mapHashMd5 -ne $MapHash)
{
throw "Virtual 4D map manifest hash does not match order $Order."
}
}
Write-Host 'Exact 2x through 6x virtual 4D maps and manifest verified.'