wip(assembler): M3 round 4 -- plans built inside Unreal from the owner's strates; no import needed
SurfaceWorld and FloatingIslands plans generate at startup from the resolved seed, strate types and heights (hashed, cached). Imported JSON is an opt-in override (off by default); an invalid override shows an on-screen notice and falls back to legacy. BuildHost on staged owner assets: SurfaceWorld cross-system checks, islands at owner height (route, collision, anchors, BP edits), seed 137501, W1/W8/W16, Core-off legacy. XY-column cache verified (hashes kept); island LOD0 p95 91 ms vs 133 ms sprint deadline. Not exercised: season-seed path (no Season in staged settings), rendered notice pixels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
48fa028086
commit
111cf3d262
21 files changed
+1934
-391
No files matched your search
@@ -1,6 +1,6 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateRange(1, 16)][int]$MaxParallelActions = 16,
|
||||
[ValidateRange(1, 4)][int]$MaxParallelActions = 4,
|
||||
[ValidateRange(60, 900)][int]$TimeoutSeconds = 900
|
||||
)
|
||||
|
||||
@@ -33,6 +33,42 @@ function Assert-UnderPath([string]$Candidate, [string]$Root) {
|
||||
}
|
||||
}
|
||||
|
||||
if (-not ('VoxelForgeRound4BuildMemoryProbe' -as [type])) {
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class VoxelForgeRound4BuildMemoryProbe {
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
private struct MEMORYSTATUSEX {
|
||||
public uint dwLength;
|
||||
public uint dwMemoryLoad;
|
||||
public ulong ullTotalPhys;
|
||||
public ulong ullAvailPhys;
|
||||
public ulong ullTotalPageFile;
|
||||
public ulong ullAvailPageFile;
|
||||
public ulong ullTotalVirtual;
|
||||
public ulong ullAvailVirtual;
|
||||
public ulong ullAvailExtendedVirtual;
|
||||
}
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
||||
public static ulong AvailablePhysicalBytes() {
|
||||
var status = new MEMORYSTATUSEX();
|
||||
status.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
||||
if (!GlobalMemoryStatusEx(ref status)) throw new InvalidOperationException("GlobalMemoryStatusEx failed.");
|
||||
return status.ullAvailPhys;
|
||||
}
|
||||
}
|
||||
'@
|
||||
}
|
||||
|
||||
function Wait-ForLaunchMemory {
|
||||
while ([VoxelForgeRound4BuildMemoryProbe]::AvailablePhysicalBytes() -lt 4GB) {
|
||||
Write-Warning 'BuildHost UBT launch is waiting for at least 4 GiB of free physical memory.'
|
||||
Start-Sleep -Seconds 20
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-DirectoryContents([string]$Source, [string]$Destination) {
|
||||
if (-not (Test-Path -LiteralPath $Source -PathType Container)) {
|
||||
throw "Canonical Core source directory is missing: $Source"
|
||||
@@ -92,11 +128,11 @@ Copy-Item -LiteralPath (Join-Path $PluginRoot 'VoxelForge.uplugin') `
|
||||
# never resolve, open, copy, or compare against the owner's project Content directory.
|
||||
$hostAssetRoot = Join-Path $HostRoot 'Content\VoxelForge'
|
||||
$expectedAssetHashes = @{
|
||||
'DA_Settings' = '5D2977F57E75A63B6B73499CD6E0AA7FBBF3718CE7F70318107BF922F0819AB7'
|
||||
'DA_Strate1' = 'CDA1F985E589F28CA6E93A068FECC3CA92487E4AD5700F2C301C4B563E40E5F9'
|
||||
'DA_Settings' = '8ABE8243104980260FECA0A6F4CF4927768E8E568221A6F6A2C2694F6D15D454'
|
||||
'DA_Strate1' = '76063D691D5CE26D2014B587E1972A6724787BE1204E4652CA863BB8D5001BD0'
|
||||
'DA_Strate2' = '02F56A18CED991BAF93DFB2F69438152275E8353B5E279C1CB7DD6E079E352E2'
|
||||
'DA_Strate3' = 'F47437F8D156C608AA06E40C5B76716ED4A19FA0F057688E7FECC04DC976428C'
|
||||
'DA_Strate4' = '279570AE3CBA7B3507269C8209A7C931EEB7A15CC3241CE07B50120996B1C656'
|
||||
'DA_Strate4' = '7C0DE7D06876035AC7BC4F117B9166AFD77402021843BA4900B470F4B0D0185B'
|
||||
}
|
||||
foreach ($assetName in $expectedAssetHashes.Keys) {
|
||||
$stagedAsset = Join-Path $hostAssetRoot "$assetName.uasset"
|
||||
@@ -105,7 +141,7 @@ foreach ($assetName in $expectedAssetHashes.Keys) {
|
||||
}
|
||||
$stagedHash = (Get-FileHash -LiteralPath $stagedAsset -Algorithm SHA256).Hash
|
||||
if ($stagedHash -ne $expectedAssetHashes[$assetName]) {
|
||||
throw "BuildHost asset copy differs from the recorded round-2 hash: $assetName"
|
||||
throw "BuildHost owner asset copy differs from the recorded round-4 hash: $assetName"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +167,13 @@ for ($attempt = 1; $attempt -le 2 -and -not $buildSucceeded; ++$attempt) {
|
||||
$attemptStdout = if ($attempt -eq 1) { $BuildStdout } else { Join-Path $LogRoot 'UBT-CoreIntegration.retry.stdout.log' }
|
||||
$attemptStderr = if ($attempt -eq 1) { $BuildStderr } else { Join-Path $LogRoot 'UBT-CoreIntegration.retry.stderr.log' }
|
||||
Write-Host "BuildHost UBT attempt $attempt of 2; max parallel actions=$MaxParallelActions; BelowNormal priority."
|
||||
Wait-ForLaunchMemory
|
||||
$foreignEditors = @(Get-Process -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.ProcessName -like 'UnrealEditor*' })
|
||||
if ($foreignEditors.Count -gt 0) {
|
||||
$ids = ($foreignEditors | ForEach-Object { "$($_.ProcessName):$($_.Id)" }) -join ', '
|
||||
throw "UnrealEditor is already running; leaving it untouched: $ids"
|
||||
}
|
||||
$process = Start-Process -FilePath $dotnet -ArgumentList $argumentList -WorkingDirectory $PluginRoot `
|
||||
-RedirectStandardOutput $attemptStdout -RedirectStandardError $attemptStderr `
|
||||
-WindowStyle Hidden -PassThru
|
||||
|
||||
@@ -6,7 +6,12 @@ param(
|
||||
[switch]$EnableHybridFixturePlacement,
|
||||
[switch]$HybridCliffOnly,
|
||||
[switch]$HybridFixturesOnly,
|
||||
[switch]$FloatingIslandsOnly
|
||||
[switch]$FloatingIslandsOnly,
|
||||
[switch]$CoreFallbackTest,
|
||||
[switch]$MismatchedManifestFallback,
|
||||
[switch]$CoreOffTest,
|
||||
[switch]$CorePlanOnly,
|
||||
[int]$CoreTestSeed = [int]::MinValue
|
||||
)
|
||||
|
||||
# Exercise AVoxelWorld Core streaming, collision, anchor movement, and carving in BuildHost only.
|
||||
@@ -29,6 +34,25 @@ $ZenData = Join-Path $OutputRoot 'ZenData'
|
||||
$EditorCmd = 'E:\Program Files\Epic Games\UE_5.7\Engine\Binaries\Win64\UnrealEditor-Cmd.exe'
|
||||
$MemoryLimitBytes = 8GB
|
||||
$CrashRoots = @((Join-Path $HostRoot 'Saved\Crashes'), (Join-Path $StagePlugin 'Saved\Crashes'))
|
||||
$RunName = if ($FloatingIslandsOnly) { 'floating_islands' }
|
||||
elseif ($CoreFallbackTest -or $MismatchedManifestFallback) { 'mismatched_fallback' }
|
||||
elseif ($CoreOffTest) { 'core_off' }
|
||||
elseif ($CorePlanOnly) { if ($CoreTestSeed -ne [int]::MinValue) { "plan_seed_$CoreTestSeed" } else { 'plan_only' } }
|
||||
else { 'owner_surface' }
|
||||
|
||||
if ($MismatchedManifestFallback) { $CoreFallbackTest = $true }
|
||||
$SelectedModeFlags = @(
|
||||
[bool]$FloatingIslandsOnly, [bool]$CoreFallbackTest,
|
||||
[bool]$CoreOffTest, [bool]$CorePlanOnly
|
||||
)
|
||||
$SelectedModeCount = @($SelectedModeFlags | Where-Object { $_ }).Count
|
||||
if ($SelectedModeCount -gt 1) { throw 'Select one Core test mode per BuildHost launch.' }
|
||||
if ($CorePlanOnly -and $CoreTestSeed -eq [int]::MinValue) {
|
||||
throw '-CorePlanOnly requires a specific CoreTestSeed.'
|
||||
}
|
||||
if ($CoreTestSeed -ne [int]::MinValue -and -not $CorePlanOnly) {
|
||||
throw '-CoreTestSeed is valid only with -CorePlanOnly.'
|
||||
}
|
||||
|
||||
function Assert-UnderPath([string]$Candidate, [string]$Root) {
|
||||
$candidateFull = [IO.Path]::GetFullPath($Candidate).TrimEnd('\', '/')
|
||||
@@ -39,26 +63,65 @@ function Assert-UnderPath([string]$Candidate, [string]$Root) {
|
||||
}
|
||||
}
|
||||
|
||||
Assert-UnderPath $HostRoot (Join-Path $PluginRoot 'Saved\BuildHost')
|
||||
Assert-UnderPath $OutputRoot (Join-Path $StagePlugin 'Saved')
|
||||
if ([string]::IsNullOrWhiteSpace($WorldAssemblyManifestPath)) {
|
||||
$WorldAssemblyManifestPath = if ($FloatingIslandsOnly) {
|
||||
Join-Path $PluginRoot 'Standalone\Research\WorldAssemblerM3\Round3\results\world_assembly_floating_islands.json'
|
||||
} else {
|
||||
Join-Path $PluginRoot 'Standalone\Research\WorldAssemblerM1\round4\world_assembly.json'
|
||||
if (-not ('VoxelForgeRound4MemoryProbe' -as [type])) {
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class VoxelForgeRound4MemoryProbe {
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
private struct MEMORYSTATUSEX {
|
||||
public uint dwLength;
|
||||
public uint dwMemoryLoad;
|
||||
public ulong ullTotalPhys;
|
||||
public ulong ullAvailPhys;
|
||||
public ulong ullTotalPageFile;
|
||||
public ulong ullAvailPageFile;
|
||||
public ulong ullTotalVirtual;
|
||||
public ulong ullAvailVirtual;
|
||||
public ulong ullAvailExtendedVirtual;
|
||||
}
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
||||
public static ulong AvailablePhysicalBytes() {
|
||||
var status = new MEMORYSTATUSEX();
|
||||
status.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
||||
if (!GlobalMemoryStatusEx(ref status)) throw new InvalidOperationException("GlobalMemoryStatusEx failed.");
|
||||
return status.ullAvailPhys;
|
||||
}
|
||||
}
|
||||
$WorldAssemblyManifestPath = [IO.Path]::GetFullPath($WorldAssemblyManifestPath)
|
||||
Assert-UnderPath $WorldAssemblyManifestPath $PluginRoot
|
||||
'@
|
||||
}
|
||||
|
||||
function Wait-ForLaunchMemory {
|
||||
while ([VoxelForgeRound4MemoryProbe]::AvailablePhysicalBytes() -lt 4GB) {
|
||||
Write-Warning 'BuildHost launch is waiting for at least 4 GiB of free physical memory.'
|
||||
Start-Sleep -Seconds 20
|
||||
}
|
||||
}
|
||||
|
||||
Assert-UnderPath $HostRoot (Join-Path $PluginRoot 'Saved\BuildHost')
|
||||
Assert-UnderPath $OutputRoot (Join-Path $StagePlugin 'Saved')
|
||||
if ([string]::IsNullOrWhiteSpace($WorldAssemblyManifestPath) -and
|
||||
($CoreFallbackTest -or $MismatchedManifestFallback)) {
|
||||
$WorldAssemblyManifestPath = Join-Path $PluginRoot `
|
||||
'Standalone\Research\WorldAssemblerM3\Round3\results\world_assembly_floating_islands.json'
|
||||
}
|
||||
$HasManifestOverride = -not [string]::IsNullOrWhiteSpace($WorldAssemblyManifestPath)
|
||||
if ($HasManifestOverride) {
|
||||
$WorldAssemblyManifestPath = [IO.Path]::GetFullPath($WorldAssemblyManifestPath)
|
||||
Assert-UnderPath $WorldAssemblyManifestPath $PluginRoot
|
||||
}
|
||||
foreach ($required in @($HostProject, $EditorCmd)) {
|
||||
if (-not (Test-Path -LiteralPath $required -PathType Leaf)) {
|
||||
throw "Required BuildHost commandlet input is missing: $required"
|
||||
}
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $WorldAssemblyManifestPath -PathType Leaf)) {
|
||||
if ($HasManifestOverride -and -not (Test-Path -LiteralPath $WorldAssemblyManifestPath -PathType Leaf)) {
|
||||
throw "Reviewed world assembly manifest is missing: $WorldAssemblyManifestPath"
|
||||
}
|
||||
|
||||
if ($MismatchedManifestFallback) { $RunName = 'mismatched_fallback' }
|
||||
|
||||
$foreignEditors = @(Get-Process -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.ProcessName -like 'UnrealEditor*' })
|
||||
if ($foreignEditors.Count -gt 0) {
|
||||
@@ -67,11 +130,11 @@ if ($foreignEditors.Count -gt 0) {
|
||||
}
|
||||
|
||||
$ExpectedAssetHashes = @{
|
||||
'DA_Settings' = '5D2977F57E75A63B6B73499CD6E0AA7FBBF3718CE7F70318107BF922F0819AB7'
|
||||
'DA_Strate1' = 'CDA1F985E589F28CA6E93A068FECC3CA92487E4AD5700F2C301C4B563E40E5F9'
|
||||
'DA_Settings' = '8ABE8243104980260FECA0A6F4CF4927768E8E568221A6F6A2C2694F6D15D454'
|
||||
'DA_Strate1' = '76063D691D5CE26D2014B587E1972A6724787BE1204E4652CA863BB8D5001BD0'
|
||||
'DA_Strate2' = '02F56A18CED991BAF93DFB2F69438152275E8353B5E279C1CB7DD6E079E352E2'
|
||||
'DA_Strate3' = 'F47437F8D156C608AA06E40C5B76716ED4A19FA0F057688E7FECC04DC976428C'
|
||||
'DA_Strate4' = '279570AE3CBA7B3507269C8209A7C931EEB7A15CC3241CE07B50120996B1C656'
|
||||
'DA_Strate4' = '7C0DE7D06876035AC7BC4F117B9166AFD77402021843BA4900B470F4B0D0185B'
|
||||
}
|
||||
foreach ($assetName in $ExpectedAssetHashes.Keys) {
|
||||
$stagedAsset = Join-Path $HostRoot "Content\VoxelForge\$assetName.uasset"
|
||||
@@ -79,7 +142,7 @@ foreach ($assetName in $ExpectedAssetHashes.Keys) {
|
||||
throw "Verified BuildHost asset copy is missing: $assetName"
|
||||
}
|
||||
if ((Get-FileHash -LiteralPath $stagedAsset -Algorithm SHA256).Hash -ne $ExpectedAssetHashes[$assetName]) {
|
||||
throw "BuildHost asset copy differs from the recorded round-2 hash: $assetName"
|
||||
throw "BuildHost owner asset copy differs from the recorded round-4 hash: $assetName"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,16 +150,14 @@ foreach ($directory in @($OutputDirectory, $InputDirectory, $LogDirectory, $Loca
|
||||
$UserDirectory, $DerivedDataCache, $ZenData)) {
|
||||
[IO.Directory]::CreateDirectory($directory) | Out-Null
|
||||
}
|
||||
Copy-Item -LiteralPath $WorldAssemblyManifestPath -Destination $StagedWorldAssembly -Force
|
||||
$ManifestData = Get-Content -LiteralPath $StagedWorldAssembly -Raw | ConvertFrom-Json
|
||||
if ($FloatingIslandsOnly) {
|
||||
if ($ManifestData.content_hash -ne '94b563f1ce622def' -or
|
||||
@($ManifestData.floating_islands).Count -ne 1 -or
|
||||
@($ManifestData.plan.strates).Count -ne 0) {
|
||||
throw "BuildHost world assembly input is not the reviewed round-3 island manifest: $($ManifestData.content_hash)"
|
||||
}
|
||||
} elseif ($ManifestData.content_hash -ne '8933693d9560ba9f') {
|
||||
throw "BuildHost world assembly input is not the reviewed round-4 manifest: $($ManifestData.content_hash)"
|
||||
if ($HasManifestOverride) {
|
||||
Copy-Item -LiteralPath $WorldAssemblyManifestPath -Destination $StagedWorldAssembly -Force
|
||||
$ManifestData = Get-Content -LiteralPath $StagedWorldAssembly -Raw | ConvertFrom-Json
|
||||
} else {
|
||||
$ManifestData = $null
|
||||
}
|
||||
if ($MismatchedManifestFallback -and ($null -eq $ManifestData -or $ManifestData.content_hash -ne '94b563f1ce622def' -or @($ManifestData.floating_islands).Count -ne 1 -or @($ManifestData.plan.strates).Count -ne 0)) {
|
||||
throw "Fallback regression input is not the old round-3 island manifest: $($ManifestData.content_hash)"
|
||||
}
|
||||
if ($EnableHybridFixturePlacement -and $CoreMesherRecipe -eq 'MarchingCubesV1') {
|
||||
throw 'Hybrid fixture placement requires a WorldAssemblerHybrid recipe.'
|
||||
@@ -113,9 +174,8 @@ if ($HybridFixturesOnly -and $CoreMesherRecipe -eq 'MarchingCubesV1') {
|
||||
if ($HybridFixturesOnly -and ($HybridCliffOnly -or $EnableHybridFixturePlacement)) {
|
||||
throw '-HybridFixturesOnly cannot be combined with the other focused hybrid modes.'
|
||||
}
|
||||
if ($FloatingIslandsOnly -and ($CoreMesherRecipe -ne 'MarchingCubesV1' -or
|
||||
$EnableHybridFixturePlacement -or $HybridCliffOnly -or $HybridFixturesOnly)) {
|
||||
throw '-FloatingIslandsOnly uses the reviewed MC island manifest and cannot be combined with hybrid modes.'
|
||||
if (($FloatingIslandsOnly -or $CoreFallbackTest -or $CoreOffTest -or $CorePlanOnly) -and ($CoreMesherRecipe -ne 'MarchingCubesV1' -or $EnableHybridFixturePlacement -or $HybridCliffOnly -or $HybridFixturesOnly)) {
|
||||
throw 'Core world integration modes use Marching Cubes and cannot be combined with hybrid modes.'
|
||||
}
|
||||
|
||||
$CrashBefore = @{}
|
||||
@@ -150,6 +210,9 @@ $HybridFixturePlacementFlag = if ($EnableHybridFixturePlacement) { 1 } else { 0
|
||||
$HybridCliffOnlyFlag = if ($HybridCliffOnly) { 1 } else { 0 }
|
||||
$HybridFixturesOnlyFlag = if ($HybridFixturesOnly) { 1 } else { 0 }
|
||||
$FloatingIslandsOnlyFlag = if ($FloatingIslandsOnly) { 1 } else { 0 }
|
||||
$CoreFallbackTestFlag = if ($CoreFallbackTest) { 1 } else { 0 }
|
||||
$CoreOffTestFlag = if ($CoreOffTest) { 1 } else { 0 }
|
||||
$CorePlanOnlyFlag = if ($CorePlanOnly) { 1 } else { 0 }
|
||||
$BaseArguments = @(
|
||||
('-project="{0}"' -f $HostProject),
|
||||
'-nullrhi', '-unattended', '-nop4', '-nosplash', '-NoSound',
|
||||
@@ -161,17 +224,27 @@ $BaseArguments = @(
|
||||
'-run=VoxelForgeExplore', '-seed=0', '-archetype=TunnelNetwork', '-slot=0',
|
||||
'-modes=export', '-gameconfig=1', '-coreworldtest=1',
|
||||
("-coreislandtest=$FloatingIslandsOnlyFlag"),
|
||||
("-corefallbacktest=$CoreFallbackTestFlag"),
|
||||
("-coreofftest=$CoreOffTestFlag"),
|
||||
("-coreplantest=$CorePlanOnlyFlag"),
|
||||
'-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings',
|
||||
('-coreworldassembly="{0}"' -f $StagedWorldAssembly),
|
||||
("-corehybridmesher=$HybridMesherFlag"),
|
||||
("-corehybridfixtureplacement=$HybridFixturePlacementFlag"),
|
||||
("-corehybridcliffonly=$HybridCliffOnlyFlag"),
|
||||
("-corehybridfixturesonly=$HybridFixturesOnlyFlag"),
|
||||
('-out="{0}"' -f $OutputDirectory)
|
||||
)
|
||||
if ($FloatingIslandsOnly) {
|
||||
# Keep this stationary route fixture out of the movement gate; island/span cooked contacts are probed directly.
|
||||
# Garder ce fixture immobile hors du gate de mouvement ; les contacts cuisines ile/pont sont verifies directement.
|
||||
if ($HasManifestOverride) {
|
||||
$BaseArguments += ('-coreworldassembly="{0}"' -f $StagedWorldAssembly)
|
||||
}
|
||||
if ($CoreTestSeed -ne [int]::MinValue) {
|
||||
$BaseArguments += "-coretestseed=$CoreTestSeed"
|
||||
}
|
||||
if ($FloatingIslandsOnly -or (-not $CoreFallbackTest -and -not $CoreOffTest -and -not $CorePlanOnly)) {
|
||||
# This commandlet keeps the travel pawn stationary; surface's initial collision cooks are still audited,
|
||||
# and FloatingIslandsOnly separately probes cooked island/span capsule contacts.
|
||||
# Le pawn de voyage du commandlet reste immobile ; les collisions de surface initiales sont auditees,
|
||||
# et FloatingIslandsOnly sonde separement les contacts capsules ile/pont cuisines.
|
||||
$BaseArguments += '-voxel.CollisionGate=0'
|
||||
}
|
||||
|
||||
@@ -181,19 +254,26 @@ try {
|
||||
$Succeeded = $false
|
||||
for ($Attempt = 1; $Attempt -le 2 -and -not $Succeeded; ++$Attempt) {
|
||||
if ($Attempt -eq 1) {
|
||||
$LogFileName = 'CoreWorldValidation.log'
|
||||
$StdoutFileName = 'CoreWorldValidation.stdout.log'
|
||||
$StderrFileName = 'CoreWorldValidation.stderr.log'
|
||||
$LogFileName = "CoreWorldValidation-$RunName.log"
|
||||
$StdoutFileName = "CoreWorldValidation-$RunName.stdout.log"
|
||||
$StderrFileName = "CoreWorldValidation-$RunName.stderr.log"
|
||||
} else {
|
||||
$LogFileName = 'CoreWorldValidation.retry.log'
|
||||
$StdoutFileName = 'CoreWorldValidation.retry.stdout.log'
|
||||
$StderrFileName = 'CoreWorldValidation.retry.stderr.log'
|
||||
$LogFileName = "CoreWorldValidation-$RunName.retry.log"
|
||||
$StdoutFileName = "CoreWorldValidation-$RunName.retry.stdout.log"
|
||||
$StderrFileName = "CoreWorldValidation-$RunName.retry.stderr.log"
|
||||
}
|
||||
$LogPath = Join-Path $LogDirectory $LogFileName
|
||||
$StdoutPath = Join-Path $LogDirectory $StdoutFileName
|
||||
$StderrPath = Join-Path $LogDirectory $StderrFileName
|
||||
$Arguments = @($BaseArguments) + ('-abslog="{0}"' -f $LogPath)
|
||||
Write-Host "BuildHost Core actor commandlet attempt $Attempt of 2; BelowNormal priority."
|
||||
Wait-ForLaunchMemory
|
||||
$foreignEditors = @(Get-Process -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.ProcessName -like 'UnrealEditor*' })
|
||||
if ($foreignEditors.Count -gt 0) {
|
||||
$ids = ($foreignEditors | ForEach-Object { "$($_.ProcessName):$($_.Id)" }) -join ', '
|
||||
throw "UnrealEditor is already running; leaving it untouched: $ids"
|
||||
}
|
||||
Write-Host "BuildHost Core actor commandlet attempt $Attempt of 2; BelowNormal priority; run=$RunName."
|
||||
$Process = Start-Process -FilePath $EditorCmd -ArgumentList $Arguments -WorkingDirectory $HostRoot `
|
||||
-RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath `
|
||||
-WindowStyle Hidden -PassThru
|
||||
@@ -228,6 +308,17 @@ try {
|
||||
$ExitCode = [int]$Matches[1]
|
||||
}
|
||||
}
|
||||
if ($CoreFallbackTest -and $ExitCode -eq 1 -and (Test-Path -LiteralPath $LogPath -PathType Leaf)) {
|
||||
$CompletedLog = Get-Content -LiteralPath $LogPath -Raw
|
||||
$ExpectedFallbackErrors = $CompletedLog -match '\[VoxelForgeCoreFallbackTest\] fallback=PASS core_disabled=1 legacy_generator=1' -and
|
||||
$CompletedLog -match '\[VoxelForgeCoreRuntime\] fallback_notice=on_screen seconds=20' -and
|
||||
$CompletedLog -match '\[VoxelForgeCoreWorldTest\] pass complete=1' -and
|
||||
$CompletedLog -match 'Commandlet VoxelForgeExploreCommandlet_\d+ finished execution \(result 0\)'
|
||||
if ($ExpectedFallbackErrors -and @(Get-NewCrashFolders).Count -eq 0) {
|
||||
Write-Warning 'Accepting commandlet status 1 because the expected Core Error logs accompanied explicit fallback-pass/result-0 markers and no crash.'
|
||||
$ExitCode = 0
|
||||
}
|
||||
}
|
||||
if ($ExitCode -eq -1073741502 -and $Attempt -eq 1) {
|
||||
Write-Warning 'BuildHost Core actor commandlet exited with 0xC0000142; retrying once.'
|
||||
continue
|
||||
@@ -248,14 +339,61 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
$FinalLog = Join-Path $LogDirectory 'CoreWorldValidation.log'
|
||||
$FinalLog = Join-Path $LogDirectory "CoreWorldValidation-$RunName.log"
|
||||
if (-not (Test-Path -LiteralPath $FinalLog -PathType Leaf)) {
|
||||
$FinalLog = Join-Path $LogDirectory 'CoreWorldValidation.retry.log'
|
||||
$FinalLog = Join-Path $LogDirectory "CoreWorldValidation-$RunName.retry.log"
|
||||
}
|
||||
$Text = Get-Content -LiteralPath $FinalLog -Raw
|
||||
if ($CoreFallbackTest) {
|
||||
foreach ($Marker in @(
|
||||
'[VoxelForgeCoreFallbackTest] fallback=PASS core_disabled=1 legacy_generator=1',
|
||||
'[VoxelForgeCoreRuntime] fallback_notice=on_screen seconds=20',
|
||||
'Core initialization failed; falling back to the legacy generator.'
|
||||
)) {
|
||||
if ($Text.IndexOf($Marker, [StringComparison]::Ordinal) -lt 0) {
|
||||
throw "BuildHost fallback regression log is missing '$Marker'. See $FinalLog."
|
||||
}
|
||||
}
|
||||
$NewCrashes = @(Get-NewCrashFolders)
|
||||
if ($NewCrashes.Count -gt 0) {
|
||||
throw "New UECC crash folders appeared during the fallback regression: $($NewCrashes -join '; ')"
|
||||
}
|
||||
Write-Host 'VOXELFORGE_CORE_MISMATCHED_MANIFEST_FALLBACK_PASS on_screen=1 legacy=1'
|
||||
Write-Host "Core actor log: $FinalLog"
|
||||
Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes"
|
||||
return
|
||||
}
|
||||
if ($CoreOffTest) {
|
||||
if ($Text -notmatch '\[VoxelForgeCoreOffTest\] legacy_unchanged=PASS core_disabled=1 voxel_cm=12\.5 density_samples=3' -or
|
||||
$Text -notmatch '\[VoxelForgeCoreWorldTest\] pass complete=1') {
|
||||
throw "BuildHost Core-off run did not prove unchanged owner legacy density and scale. See $FinalLog."
|
||||
}
|
||||
$NewCrashes = @(Get-NewCrashFolders)
|
||||
if ($NewCrashes.Count -gt 0) {
|
||||
throw "New UECC crash folders appeared during the Core-off test: $($NewCrashes -join '; ')"
|
||||
}
|
||||
Write-Host 'VOXELFORGE_CORE_OFF_LEGACY_PASS voxel_cm=12.5 density_samples=3'
|
||||
Write-Host "Core actor log: $FinalLog"
|
||||
Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes"
|
||||
return
|
||||
}
|
||||
if ($CorePlanOnly) {
|
||||
if ($Text -notmatch ('\[VoxelForgeCorePlanTest\] pass source=locked_owner_layout_seed_override seed=' +
|
||||
[regex]::Escape([string]$CoreTestSeed) + ' .* deterministic_json=1')) {
|
||||
throw "BuildHost did not generate a deterministic owner-layout plan for seed $CoreTestSeed. See $FinalLog."
|
||||
}
|
||||
$NewCrashes = @(Get-NewCrashFolders)
|
||||
if ($NewCrashes.Count -gt 0) {
|
||||
throw "New UECC crash folders appeared during the nonzero-seed plan test: $($NewCrashes -join '; ')"
|
||||
}
|
||||
Write-Host "VOXELFORGE_CORE_NONZERO_SEED_PLAN_PASS seed=$CoreTestSeed"
|
||||
Write-Host "Core actor log: $FinalLog"
|
||||
Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes"
|
||||
return
|
||||
}
|
||||
if ($FloatingIslandsOnly) {
|
||||
foreach ($Marker in @(
|
||||
'[VoxelForgeCoreIslandTest] manifest_import=PASS',
|
||||
'[VoxelForgeCoreIslandTest] plan_generated=PASS',
|
||||
'[VoxelForgeCoreIslandTest] standalone_reference=PASS',
|
||||
'[VoxelForgeCoreIslandTest] worker_hash_matrix=1/8/16 stable=1',
|
||||
'[VoxelForgeCoreIslandTest] pass phase=initial',
|
||||
@@ -286,7 +424,7 @@ if ($FloatingIslandsOnly) {
|
||||
if ($NewCrashes.Count -gt 0) {
|
||||
throw "New UECC crash folders appeared during the island actor test: $($NewCrashes -join '; ')"
|
||||
}
|
||||
Write-Host "VOXELFORGE_CORE_FLOATING_ISLANDS_PASS manifest=$($ManifestData.content_hash) hashes=standalone water_fixed=1 lod=0,1 workers=1,8,16"
|
||||
Write-Host "VOXELFORGE_CORE_FLOATING_ISLANDS_PASS hashes=standalone water_fixed=1 lod=0,1 workers=1,8,16"
|
||||
Write-Host "Core actor log: $FinalLog"
|
||||
Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes"
|
||||
return
|
||||
@@ -345,7 +483,7 @@ foreach ($Phase in @('initial', 'anchor', 'edit', 'surface_travel', 'surface_str
|
||||
if ($Text -notmatch '\[VoxelForgeCoreWorldTest\] worker_hash_matrix=1/8/16 stable=1') {
|
||||
throw "BuildHost Core actor log is missing the W1/W8/W16 determinism marker. See $FinalLog."
|
||||
}
|
||||
$ExpectedRuntimeAssemblyHash = $ManifestData.content_hash
|
||||
$ExpectedRuntimeAssemblyHash = ''
|
||||
if ($EnableHybridFixturePlacement) {
|
||||
$FixtureHashMatch = [regex]::Match($Text,
|
||||
'\[VoxelForgeCoreWorldTest\] hybrid_fixture_placement=1 boxes=9 contacts=5 manifest_hash=([0-9a-f]{16})')
|
||||
@@ -354,10 +492,14 @@ if ($EnableHybridFixturePlacement) {
|
||||
}
|
||||
$ExpectedRuntimeAssemblyHash = $FixtureHashMatch.Groups[1].Value
|
||||
}
|
||||
$AssemblyMarker = '\[VoxelForgeCoreWorldTest\] world_assembly_hash=' +
|
||||
[regex]::Escape($ExpectedRuntimeAssemblyHash) + ' plans=1 native=1'
|
||||
if ($EnableHybridFixturePlacement) {
|
||||
$AssemblyMarker = '\[VoxelForgeCoreWorldTest\] world_assembly_source=settings_override world_assembly_hash=' +
|
||||
[regex]::Escape($ExpectedRuntimeAssemblyHash) + ' surface_strates=1 island_strates=0 native=1'
|
||||
} else {
|
||||
$AssemblyMarker = '\[VoxelForgeCoreWorldTest\] world_assembly_source=generated_at_startup world_assembly_hash=[0-9a-f]{16} surface_strates=1 island_strates=0 native=1'
|
||||
}
|
||||
if ($Text -notmatch $AssemblyMarker) {
|
||||
throw "BuildHost actor log does not prove the expected native SurfaceWorld plan was attached. See $FinalLog."
|
||||
throw "BuildHost actor log does not prove a plan for the unchanged owner SurfaceWorld settings. See $FinalLog."
|
||||
}
|
||||
$RecipeMarker = '\[VoxelForgeCoreWorldTest\] world_initialized=1 recipe=' +
|
||||
[regex]::Escape($CoreMesherRecipe)
|
||||
@@ -396,7 +538,7 @@ if ($CoreMesherRecipe -eq 'WorldAssemblerHybridV2' -and $EnableHybridFixturePlac
|
||||
if ($Text -notmatch '\[VoxelForgeCoreWorldTest\] native_biome_field=1 .*sampled_biomes=[2-9]') {
|
||||
throw "BuildHost Core actor log does not prove native SurfaceWorld biome assignment. See $FinalLog."
|
||||
}
|
||||
if ($Text -notmatch '\[VoxelForgeCoreWorldTest\] matched_surface_tile_timing=1 .*same_keys=1 tiles=2553') {
|
||||
if ($Text -notmatch '\[VoxelForgeCoreWorldTest\] matched_surface_tile_timing=1 .*same_keys=1 tiles=[1-9]\d* hashes=on') {
|
||||
throw "BuildHost Core actor log is missing the matched native/legacy-bridge surface timing. See $FinalLog."
|
||||
}
|
||||
foreach ($Marker in @(
|
||||
|
||||
Reference in new issue
Block a user