211 lines
9.9 KiB
PowerShell
211 lines
9.9 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'
|
|
$ReceiptDirectory = Join-Path $ProjectRoot 'UnrealHyperTwist\Saved\HyperTwistMapAuthoring'
|
|
|
|
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
|
|
ReceiptPath = Join-Path $ReceiptDirectory 'phase6c_magic120cell_complete.json'
|
|
},
|
|
@{
|
|
Label = 'magiccube5d'
|
|
ExpectedMapPath = $MagicCube5DMapPath
|
|
ReceiptPath = Join-Path $ReceiptDirectory 'phase6c_magiccube5d_complete.json'
|
|
}
|
|
)
|
|
|
|
foreach ($Target in $AuthoredTargets)
|
|
{
|
|
$env:HYPERTWIST_HIGHER_DIMENSIONAL_MAP_KIND = $Target.Label
|
|
$AuthoringStartedAtUtc = [DateTime]::UtcNow
|
|
Remove-Item -LiteralPath $Target.ReceiptPath -Force -ErrorAction SilentlyContinue
|
|
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
|
|
|
|
$AuthoringExitCode = $LASTEXITCODE
|
|
$Receipt = $null
|
|
if (Test-Path -LiteralPath $Target.ReceiptPath -PathType Leaf)
|
|
{
|
|
$Receipt = Get-Content -LiteralPath $Target.ReceiptPath -Raw | ConvertFrom-Json
|
|
}
|
|
|
|
$ExpectedMapHash = if (Test-Path -LiteralPath $Target.ExpectedMapPath -PathType Leaf)
|
|
{
|
|
(Get-FileHash -LiteralPath $Target.ExpectedMapPath -Algorithm MD5).Hash.ToLowerInvariant()
|
|
}
|
|
else
|
|
{
|
|
''
|
|
}
|
|
$ReceiptIsFresh = $Receipt -and `
|
|
(Get-Item -LiteralPath $Target.ReceiptPath).LastWriteTimeUtc -ge $AuthoringStartedAtUtc.AddSeconds(-2)
|
|
$ReceiptIsValid = $ReceiptIsFresh -and `
|
|
$Receipt.authoringComplete -eq $true -and `
|
|
$Receipt.mapKind -eq $Target.Label -and `
|
|
$Receipt.gameModeClassPath -eq '/Script/UnrealHyperTwist.HyperTwistHigherDimensionalTrainingGameMode' -and `
|
|
$Receipt.presentationEnvironmentOwnership -eq 'runtime-game-mode-and-shell-components' -and `
|
|
$Receipt.mapHashMd5 -eq $ExpectedMapHash -and `
|
|
@($Receipt.validatedActorLabels).Count -eq 1
|
|
|
|
if (-not $ReceiptIsValid)
|
|
{
|
|
Remove-Item Env:\HYPERTWIST_HIGHER_DIMENSIONAL_MAP_KIND -ErrorAction SilentlyContinue
|
|
if ($AuthoringExitCode -ne 0)
|
|
{
|
|
throw "Higher-dimensional map authoring failed with exit code $AuthoringExitCode before a valid completion receipt was written for '$($Target.Label)'."
|
|
}
|
|
throw "Higher-dimensional map authoring exited without a valid hash-bound completion receipt for '$($Target.Label)'."
|
|
}
|
|
|
|
if ($AuthoringExitCode -ne 0)
|
|
{
|
|
Write-Warning "UnrealEditor-Cmd exited with code $AuthoringExitCode only after '$($Target.Label)' completed, validated, and wrote its hash-bound receipt. Accepting the known post-completion headless shutdown crash."
|
|
}
|
|
|
|
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.HyperTwistHigherDimensionalTrainingGameMode'
|
|
runtimePresentationClassPath = '/Script/UnrealHyperTwist.HyperTwistHigherDimensionalTrainingShellActor'
|
|
presentationEnvironmentOwnership = 'runtime-game-mode-and-shell-components'
|
|
canonicalRenderableElementCount = 120
|
|
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.HyperTwistHigherDimensionalTrainingGameMode'
|
|
runtimePresentationClassPath = '/Script/UnrealHyperTwist.HyperTwistHigherDimensionalTrainingShellActor'
|
|
presentationEnvironmentOwnership = 'runtime-game-mode-and-shell-components'
|
|
canonicalRenderableElementCount = 242
|
|
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.07.19'
|
|
authorTag = 'HyperTwistHigherDimensionalTrainingShell'
|
|
authoringScriptRelativePath = 'scripts/hypertwist_author_higher_dimensional_training_maps.py'
|
|
authoredThroughGameModeClassPath = '/Script/UnrealHyperTwist.HyperTwistHigherDimensionalTrainingGameMode'
|
|
classicReferenceMapHashMd5 = $ClassicReferenceHashMd5
|
|
entries = $ManifestEntries
|
|
}
|
|
|
|
$Manifest | ConvertTo-Json -Depth 6 | Set-Content -Path $ManifestPath -Encoding UTF8
|
|
Write-Host 'Higher-dimensional authored maps verified.'
|