hypertwist/scripts/Invoke-HyperTwistHigherDimensionalMapAuthoring.ps1
2026-06-18 10:25:35 +00:00

180 lines
8 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_higher_dimensional_training_maps.py'
}
$UProjectPath = Join-Path $ProjectRoot 'UnrealHyperTwist\UnrealHyperTwist.uproject'
$Magic120CellMapPath = Join-Path $ProjectRoot 'UnrealHyperTwist\Content\HyperTwistTraining\Maps\L_HyperTwist_Magic120CellTraining.umap'
$MagicCube5DMapPath = Join-Path $ProjectRoot 'UnrealHyperTwist\Content\HyperTwistTraining\Maps\L_HyperTwist_MagicCube5DTraining.umap'
$ClassicMapPath = Join-Path $ProjectRoot 'UnrealHyperTwist\Content\HyperTwistTraining\Maps\L_HyperTwist_ClassicTraining.umap'
$ManifestPath = Join-Path $ProjectRoot 'docs\generated\higher_dimensional_training_maps\phase6c_dedicated_family_map_manifest.json'
if (-not (Test-Path $UnrealEditorCmdPath))
{
throw "UnrealEditor-Cmd.exe was not found at '$UnrealEditorCmdPath'."
}
if (-not (Test-Path $UProjectPath))
{
throw "UnrealHyperTwist project file was not found at '$UProjectPath'."
}
if (-not (Test-Path $PythonScriptPath))
{
throw "Higher-dimensional map authoring script was not found at '$PythonScriptPath'."
}
$NormalizedPythonScriptPath = $PythonScriptPath -replace '\\', '/'
$AuthoredTargets = @(
@{
Label = 'magic120cell'
ExpectedMapPath = $Magic120CellMapPath
},
@{
Label = 'magiccube5d'
ExpectedMapPath = $MagicCube5DMapPath
}
)
foreach ($Target in $AuthoredTargets)
{
$env:HYPERTWIST_HIGHER_DIMENSIONAL_MAP_KIND = $Target.Label
$AuthoringStartedAtUtc = [DateTime]::UtcNow
Write-Host "Authoring HyperTwist higher-dimensional training map target '$($Target.Label)' through UnrealEditor-Cmd..."
& $UnrealEditorCmdPath `
$UProjectPath `
"-ExecutePythonScript=$NormalizedPythonScriptPath" `
-unattended `
-nop4 `
-nullrhi `
-nosound `
-nosplash `
-stdout `
-FullStdOutLogOutput `
-log
if ($LASTEXITCODE -ne 0)
{
$FreshMapExists = $false
if (Test-Path $Target.ExpectedMapPath)
{
$FreshMapExists = (Get-Item $Target.ExpectedMapPath).LastWriteTimeUtc -ge $AuthoringStartedAtUtc.AddSeconds(-2)
}
if ($FreshMapExists)
{
Write-Warning "UnrealEditor-Cmd exited with code $LASTEXITCODE after freshly writing '$($Target.ExpectedMapPath)'. Continuing because this host may still crash during post-save shutdown on the headless authoring lane."
}
else
{
Remove-Item Env:\HYPERTWIST_HIGHER_DIMENSIONAL_MAP_KIND -ErrorAction SilentlyContinue
throw "Higher-dimensional map authoring failed with exit code $LASTEXITCODE."
}
}
if (-not (Test-Path $Target.ExpectedMapPath))
{
Remove-Item Env:\HYPERTWIST_HIGHER_DIMENSIONAL_MAP_KIND -ErrorAction SilentlyContinue
throw "Expected authored map was not found at '$($Target.ExpectedMapPath)'."
}
}
Remove-Item Env:\HYPERTWIST_HIGHER_DIMENSIONAL_MAP_KIND -ErrorAction SilentlyContinue
foreach ($ExpectedMapPath in @($Magic120CellMapPath, $MagicCube5DMapPath))
{
if (-not (Test-Path $ExpectedMapPath))
{
throw "Expected authored map was not found at '$ExpectedMapPath'."
}
}
if (-not (Test-Path $ClassicMapPath))
{
throw "Classic reference map was not found at '$ClassicMapPath'."
}
New-Item -ItemType Directory -Force -Path ([System.IO.Path]::GetDirectoryName($ManifestPath)) | Out-Null
$ClassicReferenceHashMd5 = (Get-FileHash $ClassicMapPath -Algorithm MD5).Hash.ToLowerInvariant()
$ManifestEntries = @(
[ordered]@{
mapKind = 'magic120cell'
familyKey = 'magic120cell'
mapAssetPath = '/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining'
mapFileRelativePath = 'UnrealHyperTwist/Content/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining.umap'
mapHashMd5 = (Get-FileHash $Magic120CellMapPath -Algorithm MD5).Hash.ToLowerInvariant()
trainingShellId = 'phase6c/magic120cell/dedicated-training-shell'
activationProfileId = 'magic120cell-cleanroom-runtime-activation'
hostSurfaceId = 'phase6c/magic120cell/runtime-host-surface'
launchSurfaceId = 'phase6c/magic120cell/dedicated-training-launch-surface'
viewContextSurfaceId = 'phase6c/magic120cell/dedicated-training-view-context-surface'
sessionSurfaceId = 'phase6c/magic120cell/dedicated-training-session-surface'
interactiveSceneSurfaceId = 'phase6c/magic120cell/interactive-scene-surface'
sceneContextId = 'phase6c/magic120cell/interactive-scene-context'
puzzleId = 'polychoron/magic120cell'
runtimeModeId = 'magic120cell-full-color-runtime-v1'
projectionProfileId = 'magic120cell-4d-projection-distance-v1'
primaryPersistenceBoundaryId = 'magic120cell-persistence-boundary'
authorTag = 'HyperTwistHigherDimensionalTrainingShell'
authoringManifestRelativePath = 'docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_map_manifest.json'
authoredViaGameModeClassPath = '/Script/UnrealHyperTwist.HyperTwistCoachDashboardGameMode'
trainingShellTags = @(
'phase6c',
'family:magic120cell',
'host:dedicated-family-map',
'projection:magic120cell-4d-projection-distance-v1',
'persistence:magic120cell-persistence-boundary'
)
},
[ordered]@{
mapKind = 'magiccube5d'
familyKey = 'magiccube5d'
mapAssetPath = '/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining'
mapFileRelativePath = 'UnrealHyperTwist/Content/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining.umap'
mapHashMd5 = (Get-FileHash $MagicCube5DMapPath -Algorithm MD5).Hash.ToLowerInvariant()
trainingShellId = 'phase6c/magiccube5d/dedicated-training-shell'
activationProfileId = 'magiccube5d-cleanroom-runtime-activation'
hostSurfaceId = 'phase6c/magiccube5d/runtime-host-surface'
launchSurfaceId = 'phase6c/magiccube5d/dedicated-training-launch-surface'
viewContextSurfaceId = 'phase6c/magiccube5d/dedicated-training-view-context-surface'
sessionSurfaceId = 'phase6c/magiccube5d/dedicated-training-session-surface'
interactiveSceneSurfaceId = 'phase6c/magiccube5d/interactive-scene-surface'
sceneContextId = 'phase6c/magiccube5d/interactive-scene-context'
puzzleId = 'hypercube/magiccube5d/order3'
runtimeModeId = 'magiccube5d-order3-runtime-v1'
projectionProfileId = 'magiccube5d-5d-projection-distance-v1'
primaryPersistenceBoundaryId = 'magiccube5d-persistence-boundary'
authorTag = 'HyperTwistHigherDimensionalTrainingShell'
authoringManifestRelativePath = 'docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_map_manifest.json'
authoredViaGameModeClassPath = '/Script/UnrealHyperTwist.HyperTwistCoachDashboardGameMode'
trainingShellTags = @(
'phase6c',
'family:magiccube5d',
'host:dedicated-family-map',
'projection:magiccube5d-5d-projection-distance-v1',
'persistence:magiccube5d-persistence-boundary'
)
}
)
$Manifest = [ordered]@{
manifestId = 'phase6c/dedicated-family-training-map-authoring'
manifestVersion = '2026.06.18'
authorTag = 'HyperTwistHigherDimensionalTrainingShell'
authoringScriptRelativePath = 'scripts/hypertwist_author_higher_dimensional_training_maps.py'
authoredThroughGameModeClassPath = '/Script/UnrealHyperTwist.HyperTwistCoachDashboardGameMode'
classicReferenceMapHashMd5 = $ClassicReferenceHashMd5
entries = $ManifestEntries
}
$Manifest | ConvertTo-Json -Depth 6 | Set-Content -Path $ManifestPath -Encoding UTF8
Write-Host 'Higher-dimensional authored maps verified.'