[CmdletBinding()] param( [ValidateRange(60, 900)][int]$TimeoutSeconds = 900, [ValidateRange(12.5, 25.0)][double]$CoreVoxelSizeCm = 25.0, [ValidateSet('CoarseFirst', 'Legacy')][string]$StreamingOrder = 'Legacy', [ValidateSet('Auto', 'Legacy', 'Dynamic')][string]$NearReserveMode = 'Auto', [switch]$EnforceCollisionGate, [switch]$StartupTrace, [ValidateRange(-1, 1)][int]$StartupApplyBoost = -1, [switch]$StreamingTraceOnly, [ValidateRange(1, 6000)][int]$TestMoveSpeedCmPerSecond = 600, [ValidateRange(0, 1)][int]$StreamingCollisionLookahead = 1, [string]$TestMoveDirection = '0,1,0', [ValidateRange(0, 1)][int]$CoreRegionConcurrentAdmission = 1, [ValidateRange(0, 4096)][int]$StreamingResultBacklogCap = 256, [ValidateRange(0, 10)][int]$StreamingReadyQueueDepth = 8, [ValidateRange(0, 1)][int]$StreamingBackgroundWorkerCap = 1, [ValidateRange(0, 900)][int]$Step1MaxMeshApplies = 0, [ValidateRange(0, 900)][int]$TestTeleportAfterSeconds = 0, [ValidateRange(0, 1000000)][int]$TestTeleportDistanceCm = 0, [string]$WorldAssemblyManifestPath = '', [ValidateSet('MarchingCubesV1', 'WorldAssemblerHybridV1', 'WorldAssemblerHybridV2')][string]$CoreMesherRecipe = 'MarchingCubesV1', [switch]$EnableHybridFixturePlacement, [switch]$HybridCliffOnly, [switch]$HybridFixturesOnly, [switch]$FloatingIslandsOnly, [switch]$CoreFallbackTest, [switch]$MismatchedManifestFallback, [switch]$CoreOffTest, [switch]$CorePlanOnly, [switch]$SharedFeatureAuditOnly, [int]$CoreTestSeed = [int]::MinValue ) # Exercise AVoxelWorld Core streaming, collision, anchor movement, and carving in BuildHost only. Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $PluginRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) $HostRoot = Join-Path $PluginRoot 'Saved\BuildHost\HostProject' $StagePlugin = Join-Path $HostRoot 'Plugins\VoxelForge' $HostProject = Join-Path $HostRoot 'HostProject.uproject' $OutputRoot = Join-Path $StagePlugin 'Saved\CoreWorldValidation' $OutputDirectory = Join-Path $OutputRoot 'Output' $InputDirectory = Join-Path $OutputRoot 'Input' $StagedWorldAssembly = Join-Path $InputDirectory 'world_assembly.json' $LogDirectory = Join-Path $OutputRoot 'Logs' $LocalAppData = Join-Path $OutputRoot 'LocalAppData' $UserDirectory = Join-Path $OutputRoot 'User' $DerivedDataCache = Join-Path $PluginRoot 'Saved\BuildHost\VFCoreWorldDDC' $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'), (Join-Path $UserDirectory 'Saved\Crashes')) $CoreSizeSuffix = '' if ([Math]::Abs($CoreVoxelSizeCm - 25.0) -gt 0.000001) { $CoreSizeText = $CoreVoxelSizeCm.ToString('0.####', [Globalization.CultureInfo]::InvariantCulture) $CoreSizeSuffix = "_voxel_$CoreSizeText" } $RunName = if ($FloatingIslandsOnly) { "floating_islands$CoreSizeSuffix" } elseif ($CoreFallbackTest -or $MismatchedManifestFallback) { "mismatched_fallback$CoreSizeSuffix" } elseif ($CoreOffTest) { "core_off$CoreSizeSuffix" } elseif ($CorePlanOnly) { if ($CoreTestSeed -ne [int]::MinValue) { "plan_seed_$CoreTestSeed$CoreSizeSuffix" } else { "plan_only$CoreSizeSuffix" } } else { "owner_surface$CoreSizeSuffix" } $RunName += $(if ($StreamingTraceOnly) { '_stream_trace_only' } else { '' }) $StartupApplyBoostLabel = if ($StartupApplyBoost -lt 0) { 'default' } else { [string]$StartupApplyBoost } $RunName += "_applyboost_$StartupApplyBoostLabel" if ($StreamingTraceOnly) { $RunName += "_bgcap_${StreamingBackgroundWorkerCap}_readyq_${StreamingReadyQueueDepth}" } if ($MismatchedManifestFallback) { $CoreFallbackTest = $true } $SelectedModeFlags = @( [bool]$FloatingIslandsOnly, [bool]$CoreFallbackTest, [bool]$CoreOffTest, [bool]$CorePlanOnly, [bool]$StreamingTraceOnly ) $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.' } if ($StreamingTraceOnly -and ($SharedFeatureAuditOnly -or $EnableHybridFixturePlacement -or $HybridCliffOnly -or $HybridFixturesOnly -or $WorldAssemblyManifestPath)) { throw '-StreamingTraceOnly uses the staged owner plan without additional fixture or manifest overrides.' } if ($TestMoveDirection -notmatch '^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+),[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+),[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)$') { throw '-TestMoveDirection must be three comma-separated invariant-culture numbers without spaces.' } $MoveDirectionComponents = @($TestMoveDirection.Split(',') | ForEach-Object { [double]::Parse($_, [Globalization.CultureInfo]::InvariantCulture) }) if ($MoveDirectionComponents[0] -eq 0 -and $MoveDirectionComponents[1] -eq 0 -and $MoveDirectionComponents[2] -eq 0) { throw '-TestMoveDirection must not be the zero vector.' } if (-not $StreamingTraceOnly -and ($TestMoveSpeedCmPerSecond -ne 600 -or $StreamingCollisionLookahead -ne 1 -or $TestMoveDirection -ne '0,1,0' -or $CoreRegionConcurrentAdmission -ne 1 -or $StreamingResultBacklogCap -ne 256 -or $StreamingReadyQueueDepth -ne 8 -or $StreamingBackgroundWorkerCap -ne 1 -or $Step1MaxMeshApplies -ne 0 -or $TestTeleportAfterSeconds -ne 0 -or $TestTeleportDistanceCm -ne 0)) { throw 'Streaming, backlog, apply and teleport controls require -StreamingTraceOnly.' } if (($TestTeleportAfterSeconds -eq 0) -ne ($TestTeleportDistanceCm -eq 0)) { throw 'Set both -TestTeleportAfterSeconds and -TestTeleportDistanceCm for the teleport probe.' } function Assert-UnderPath([string]$Candidate, [string]$Root) { $candidateFull = [IO.Path]::GetFullPath($Candidate).TrimEnd('\', '/') $rootFull = [IO.Path]::GetFullPath($Root).TrimEnd('\', '/') if (-not ($candidateFull.Equals($rootFull, [StringComparison]::OrdinalIgnoreCase) -or $candidateFull.StartsWith($rootFull + '\', [StringComparison]::OrdinalIgnoreCase))) { throw "Refusing a BuildHost path outside its root: $candidateFull" } } 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; } } '@ } 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 ($HasManifestOverride -and -not (Test-Path -LiteralPath $WorldAssemblyManifestPath -PathType Leaf)) { throw "Reviewed world assembly manifest is missing: $WorldAssemblyManifestPath" } if ($MismatchedManifestFallback) { $RunName = 'mismatched_fallback' } if ($SharedFeatureAuditOnly) { if ($SelectedModeCount -ne 0) { throw '-SharedFeatureAuditOnly uses the SurfaceWorld owner route.' } $RunName = 'shared_feature_audit' } $RunName += if ($StreamingOrder -eq 'Legacy') { '_legacy_order' } else { '_coarse_first' } $RunName += switch ($NearReserveMode) { 'Legacy' { '_nearreserve_legacy' } 'Dynamic' { '_nearreserve_dynamic' } default { '_nearreserve_auto' } } if ($HybridFixturesOnly) { $RunName += "_$($CoreMesherRecipe.ToLowerInvariant())" } if ($EnforceCollisionGate) { $RunName += '_collision_gate' } if ($StartupTrace -or $StreamingTraceOnly) { $RunName += '_trace' } if ($StreamingTraceOnly) { $DirectionTag = $TestMoveDirection.Replace(',', '_').Replace('-', 'm').Replace('+', 'p').Replace('.', 'p') $RunName += "_move_${TestMoveSpeedCmPerSecond}_lookahead_${StreamingCollisionLookahead}_dir_${DirectionTag}_region_${CoreRegionConcurrentAdmission}_backlog_${StreamingResultBacklogCap}" if ($Step1MaxMeshApplies -gt 0) { $RunName += "_applymax_$Step1MaxMeshApplies" } if ($TestTeleportAfterSeconds -gt 0) { $RunName += "_teleport_${TestTeleportAfterSeconds}s_${TestTeleportDistanceCm}cm" } } $foreignEditors = @(Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.ProcessName -like 'UnrealEditor*' }) if ($foreignEditors.Count -gt 0) { $ids = ($foreignEditors | ForEach-Object { "$($_.ProcessName):$($_.Id)" }) -join ', ' throw "An UnrealEditor process is already running; leaving it untouched: $ids" } $ExpectedAssetHashes = @{ 'DA_Settings' = '8ABE8243104980260FECA0A6F4CF4927768E8E568221A6F6A2C2694F6D15D454' 'DA_Strate1' = '76063D691D5CE26D2014B587E1972A6724787BE1204E4652CA863BB8D5001BD0' 'DA_Strate2' = '02F56A18CED991BAF93DFB2F69438152275E8353B5E279C1CB7DD6E079E352E2' 'DA_Strate3' = 'F47437F8D156C608AA06E40C5B76716ED4A19FA0F057688E7FECC04DC976428C' 'DA_Strate4' = '7C0DE7D06876035AC7BC4F117B9166AFD77402021843BA4900B470F4B0D0185B' } foreach ($assetName in $ExpectedAssetHashes.Keys) { $stagedAsset = Join-Path $HostRoot "Content\VoxelForge\$assetName.uasset" if (-not (Test-Path -LiteralPath $stagedAsset -PathType Leaf)) { throw "Verified BuildHost asset copy is missing: $assetName" } if ((Get-FileHash -LiteralPath $stagedAsset -Algorithm SHA256).Hash -ne $ExpectedAssetHashes[$assetName]) { throw "BuildHost owner asset copy differs from the recorded round-4 hash: $assetName" } } foreach ($directory in @($OutputDirectory, $InputDirectory, $LogDirectory, $LocalAppData, $UserDirectory, $DerivedDataCache, $ZenData)) { [IO.Directory]::CreateDirectory($directory) | Out-Null } 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.' } if ($HybridCliffOnly -and $CoreMesherRecipe -eq 'MarchingCubesV1') { throw '-HybridCliffOnly requires a WorldAssemblerHybrid recipe.' } if ($HybridCliffOnly -and $EnableHybridFixturePlacement) { throw '-HybridCliffOnly uses the reviewed native cliff manifest and cannot add the surface fixtures.' } if ($HybridFixturesOnly -and $CoreMesherRecipe -eq 'MarchingCubesV1') { throw '-HybridFixturesOnly requires a WorldAssemblerHybrid recipe.' } if ($HybridFixturesOnly -and ($HybridCliffOnly -or $EnableHybridFixturePlacement)) { throw '-HybridFixturesOnly cannot be combined with the other focused 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 = @{} foreach ($CrashRoot in $CrashRoots) { if (Test-Path -LiteralPath $CrashRoot -PathType Container) { foreach ($Crash in @(Get-ChildItem -LiteralPath $CrashRoot -Directory -Filter 'UECC-*' -Recurse -Force)) { $CrashBefore[$Crash.FullName.ToLowerInvariant()] = $Crash.LastWriteTimeUtc.Ticks } } } function Get-NewCrashFolders { $Found = [Collections.Generic.List[string]]::new() foreach ($CrashRoot in $CrashRoots) { if (Test-Path -LiteralPath $CrashRoot -PathType Container) { foreach ($Crash in @(Get-ChildItem -LiteralPath $CrashRoot -Directory -Filter 'UECC-*' -Recurse -Force)) { if (-not $CrashBefore.ContainsKey($Crash.FullName.ToLowerInvariant())) { [void]$Found.Add($Crash.FullName) } } } } return @($Found.ToArray()) } $HybridMesherFlag = switch ($CoreMesherRecipe) { 'WorldAssemblerHybridV1' { 1; break } 'WorldAssemblerHybridV2' { 2; break } default { 0 } } $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', '-corelimit=12', '-stdout', '-FullStdOutLogOutput', '-forcelogflush', '-NoZenAutoLaunch', '-notraceserver', '-nocrashreports', '-ddc=NoZenLocalFallback', ('-userdir="{0}"' -f $UserDirectory), ('-ZenDataPath="{0}"' -f $ZenData), ('-LocalDataCachePath="{0}"' -f $DerivedDataCache), '-run=VoxelForgeExplore', '-seed=0', '-archetype=TunnelNetwork', '-slot=0', '-modes=export', '-gameconfig=1', '-coreworldtest=1', ('-corevoxelsizecm={0}' -f $CoreVoxelSizeCm.ToString('0.####', [Globalization.CultureInfo]::InvariantCulture)), ("-coreislandtest=$FloatingIslandsOnlyFlag"), ("-corefallbacktest=$CoreFallbackTestFlag"), ("-coreofftest=$CoreOffTestFlag"), ("-coreplantest=$CorePlanOnlyFlag"), '-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings', ("-corehybridmesher=$HybridMesherFlag"), ("-corehybridfixtureplacement=$HybridFixturePlacementFlag"), ("-corehybridcliffonly=$HybridCliffOnlyFlag"), ("-corehybridfixturesonly=$HybridFixturesOnlyFlag"), ('-out="{0}"' -f $OutputDirectory) ) $CoarseFirstValue = if ($StreamingOrder -eq 'CoarseFirst') { 1 } else { 0 } $DynamicReserveValue = switch ($NearReserveMode) { 'Legacy' { 0 } 'Dynamic' { 1 } default { 1 } } $LegacyPendingResultCapValue = if ($NearReserveMode -eq 'Legacy') { 1 } else { 0 } $BaseArguments += "-voxel.StreamingCoarseFirst=$CoarseFirstValue" $BaseArguments += "-voxel.StreamingDynamicNearReserve=$DynamicReserveValue" $BaseArguments += "-voxel.StreamingLegacyPendingResultCap=$LegacyPendingResultCapValue" if ($StartupApplyBoost -ge 0) { $BaseArguments += "-voxel.StreamingStartupApplyBoost=$StartupApplyBoost" } $BaseArguments += "-voxel.CoreRegionConcurrentAdmission=$CoreRegionConcurrentAdmission" $BaseArguments += "-voxel.StreamingResultBacklogCap=$StreamingResultBacklogCap" $BaseArguments += "-voxel.StreamingReadyQueueDepth=$StreamingReadyQueueDepth" $BaseArguments += "-voxel.StreamingBackgroundWorkerCap=$StreamingBackgroundWorkerCap" if ($Step1MaxMeshApplies -gt 0) { $BaseArguments += "-voxel.Step1MaxMeshApplies=$Step1MaxMeshApplies" } if ($StreamingTraceOnly) { $BaseArguments += '-coreworldstreamtrace=1' $BaseArguments += '-voxel.TestMove=1' $BaseArguments += "-voxel.TestMoveSpeedCmPerSecond=$TestMoveSpeedCmPerSecond" $BaseArguments += '-voxel.TestMoveStartSeconds=30' $BaseArguments += "-voxel.TestMoveDirection=$TestMoveDirection" $BaseArguments += "-voxel.StreamingCollisionLookahead=$StreamingCollisionLookahead" if ($TestTeleportAfterSeconds -gt 0) { $BaseArguments += "-voxel.TestTeleportAfterSeconds=$TestTeleportAfterSeconds" $BaseArguments += "-voxel.TestTeleportDistanceCm=$TestTeleportDistanceCm" } } if ($StartupTrace -or $StreamingTraceOnly) { $TracePath = Join-Path $LogDirectory "CoreWorldValidation-$RunName.trace.jsonl" $BaseArguments += ('-voxel.StartupTraceFile="{0}"' -f $TracePath) $BaseArguments += '-voxel.StartupTraceUntilEndPlay=1' $BaseArguments += '-voxel.StartupTraceMaxTiles=16384' } if ($SharedFeatureAuditOnly) { $BaseArguments += '-corefeatureauditonly' } if ($HasManifestOverride) { $BaseArguments += ('-coreworldassembly="{0}"' -f $StagedWorldAssembly) } if ($CoreTestSeed -ne [int]::MinValue) { $BaseArguments += "-coretestseed=$CoreTestSeed" } if (-not $EnforceCollisionGate -and ($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' } $OldLocalAppData = $env:LOCALAPPDATA $env:LOCALAPPDATA = $LocalAppData try { $Succeeded = $false for ($Attempt = 1; $Attempt -le 2 -and -not $Succeeded; ++$Attempt) { if ($Attempt -eq 1) { $LogFileName = "CoreWorldValidation-$RunName.log" $StdoutFileName = "CoreWorldValidation-$RunName.stdout.log" $StderrFileName = "CoreWorldValidation-$RunName.stderr.log" } else { $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) 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; Normal priority; run=$RunName." $Process = Start-Process -FilePath $EditorCmd -ArgumentList $Arguments -WorkingDirectory $HostRoot ` -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath ` -WindowStyle Hidden -PassThru $Process.PriorityClass = [Diagnostics.ProcessPriorityClass]::Normal # W16 is a logical determinism partition; at most 12 logical CPUs execute host work. # W16 reste un partitionnement logique; limiter l'execution hote a 12 processeurs logiques. $Process.ProcessorAffinity = [IntPtr]0xFFF $StartedUtc = [datetime]::UtcNow $PeakPrivateBytes = [int64]0 while (-not $Process.HasExited) { Start-Sleep -Seconds 2 $Process.Refresh() if (-not $Process.HasExited) { $PeakPrivateBytes = [Math]::Max($PeakPrivateBytes, [int64]$Process.PrivateMemorySize64) } if (([datetime]::UtcNow - $StartedUtc).TotalSeconds -gt $TimeoutSeconds) { Stop-Process -Id $Process.Id -Force -ErrorAction SilentlyContinue throw "BuildHost Core actor commandlet exceeded the $TimeoutSeconds-second time box." } if (-not $Process.HasExited -and $Process.PrivateMemorySize64 -gt $MemoryLimitBytes) { Stop-Process -Id $Process.Id -Force -ErrorAction SilentlyContinue throw 'BuildHost Core actor commandlet exceeded the 8 GiB private-memory limit.' } } $Process.WaitForExit() $Process.Refresh() $ExitCode = $Process.ExitCode if ([string]::IsNullOrEmpty([string]$ExitCode) -and (Test-Path -LiteralPath $LogPath -PathType Leaf)) { $CompletedLog = Get-Content -LiteralPath $LogPath -Raw if (($CompletedLog -match '\[VoxelForgeCoreWorldTest\] pass complete=1' -or $CompletedLog -match '\[VoxelForgeCoreIslandTest\] pass complete=1') -and $CompletedLog -match 'Commandlet VoxelForgeExploreCommandlet_\d+ finished execution \(result 0\)') { $ExitCode = 0 } elseif ($CompletedLog -match 'Commandlet VoxelForgeExploreCommandlet_\d+ finished execution \(result (-?\d+)\)') { $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 } if ($ExitCode -ne 0) { $NewCrashes = @(Get-NewCrashFolders) $CrashDetail = if ($NewCrashes.Count -gt 0) { " New UECC folders: $($NewCrashes -join '; ')." } else { '' } throw "BuildHost Core actor commandlet attempt $Attempt failed with exit code '$ExitCode'.$CrashDetail See $LogPath." } $Succeeded = $true } if (-not $Succeeded) { throw 'BuildHost Core actor commandlet did not complete successfully.' } } finally { if ($null -eq $OldLocalAppData) { Remove-Item Env:LOCALAPPDATA -ErrorAction SilentlyContinue } else { $env:LOCALAPPDATA = $OldLocalAppData } } $FinalLog = Join-Path $LogDirectory "CoreWorldValidation-$RunName.log" if (-not (Test-Path -LiteralPath $FinalLog -PathType Leaf)) { $FinalLog = Join-Path $LogDirectory "CoreWorldValidation-$RunName.retry.log" } $Text = Get-Content -LiteralPath $FinalLog -Raw if ($SharedFeatureAuditOnly) { if ($Text -notmatch '\[VoxelForgeSharedFeatureCost\] pass complete=1 warmed_routes=1') { throw "Shared feature audit did not pass: $FinalLog" } if (@(Get-NewCrashFolders).Count -gt 0) { throw 'Shared feature audit produced a new crash folder.' } Write-Host 'VOXELFORGE_SHARED_FEATURE_AUDIT_PASS warmed_routes=1' Write-Host "Core actor log: $FinalLog" Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes" return } if ($StreamingTraceOnly) { $ExpectedWalkDirection = "walk_direction=$TestMoveDirection" if ($Text -notmatch '\[VoxelForgeCoreWorldStreamTrace\] initial_ready=1 .*walk_tick_ms_p95=.*walk_tick_ms_max=' -or $Text -notmatch ("\[VoxelForgeCoreWorldStreamTrace\] pass complete=1 .*walk_speed_cm_s=$TestMoveSpeedCmPerSecond") -or -not $Text.Contains($ExpectedWalkDirection) -or $Text -notmatch '\[VoxelForgeCoreWorldTest\] pass complete=1') { throw "BuildHost actor-only stream trace did not prove initial readiness and a completed walk sample. See $FinalLog." } $NewCrashes = @(Get-NewCrashFolders) if ($NewCrashes.Count -gt 0) { throw "New UECC crash folders appeared during the stream trace: $($NewCrashes -join '; ')" } Write-Host "VOXELFORGE_CORE_STREAM_TRACE_PASS boost=$StartupApplyBoostLabel order=$StreamingOrder" Write-Host "Core actor log: $FinalLog" Write-Host "Startup trace: $TracePath" Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes" return } 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] plan_generated=PASS', '[VoxelForgeCoreIslandTest] standalone_reference=PASS', '[VoxelForgeCoreIslandTest] worker_hash_matrix=1/8/16 stable=1', '[VoxelForgeCoreIslandTest] pass phase=initial', '[VoxelForgeCoreIslandTest] height_anchor_agreement=PASS', '[VoxelForgeCoreIslandTest] content_anchor=PASS', '[VoxelForgeCoreIslandTest] blueprint_edit=PASS', '[VoxelForgeCoreIslandTest] switch_off_legacy=PASS', '[VoxelForgeCoreIslandTest] pass complete=1', '[VoxelForgePawnSpeedFixture] source=staged_blueprints walk_cm_s=600.000 sprint_cm_s=6000.000' )) { if ($Text.IndexOf($Marker, [StringComparison]::Ordinal) -lt 0) { throw "BuildHost floating-island log is missing '$Marker'. See $FinalLog." } } foreach ($Surface in @('island_top', 'span')) { if ($Text -notmatch ('\[VoxelForgeCoreIslandTest\] capsule_contact=PASS surface=' + [regex]::Escape($Surface) + ' .*collision_ready=1')) { throw "BuildHost island log is missing cooked capsule contact for '$Surface'. See $FinalLog." } } foreach ($Lod in @(0, 1)) { if ($Text -notmatch ('\[VoxelForgeIslandStreaming\] timing lod=' + $Lod + ' kind=.*air .*core_p95_ms=') -or $Text -notmatch ('\[VoxelForgeIslandStreaming\] timing lod=' + $Lod + ' kind=.*(island|mixed|span) .*legacy_p95_ms=')) { throw "BuildHost island log is missing matched air and surface timing at LOD$Lod. See $FinalLog." } } $NewCrashes = @(Get-NewCrashFolders) 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 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 } if ($HybridFixturesOnly) { foreach ($Fixture in @('corner90', 'doorway', 'riser1m', 'cliff_ledge', 'organic_cave_chamber')) { $FixtureMarker = '\[WorldAssemblerHybridPluginFixture\] name=' + [regex]::Escape($Fixture) + ' lod=0 .*exact_repeat=1' if ($Text -notmatch $FixtureMarker) { throw "BuildHost fixture log is missing '$Fixture'. See $FinalLog." } } if ($Text -notmatch '\[WorldAssemblerHybridPluginBorder\] same_lod=PASS independent=1' -or $Text -notmatch '\[WorldAssemblerHybridPluginBorder\] lod0_lod1_doorway=1 cases=125 over_50cm_cases=0') { throw "BuildHost fixture log is missing passing border probes. See $FinalLog." } if ($CoreMesherRecipe -eq 'WorldAssemblerHybridV2') { foreach ($Fixture in @('corner90', 'doorway', 'riser1m', 'cliff_ledge', 'organic_cave_chamber')) { $FixtureMarker = '\[WorldAssemblerHybridPluginFixtureV2\] name=' + [regex]::Escape($Fixture) + ' lod=0 .*exact_repeat=1' if ($Text -notmatch $FixtureMarker) { throw "BuildHost V2 fixture log is missing '$Fixture'. See $FinalLog." } } if ($Text -notmatch '\[WorldAssemblerHybridPluginBorderV2\] same_lod=PASS independent=1 mc_identity=1') { throw "BuildHost fixture log is missing the V2 border identity proof. See $FinalLog." } } $NewCrashes = @(Get-NewCrashFolders) if ($NewCrashes.Count -gt 0) { throw "New UECC crash folders appeared during plugin fixture checks: $($NewCrashes -join '; ')" } Write-Host "VOXELFORGE_CORE_HYBRID_FIXTURES_PASS recipe=$CoreMesherRecipe analytic=5 borders=1" Write-Host "Core actor log: $FinalLog" Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes" return } if ($HybridCliffOnly) { if ($Text -notmatch '\[WorldAssemblerHybridNativeCliff\] key=\(-22,13,-58\) lod=0 .*bit_identical=1 type4_only=1') { throw "BuildHost log is missing the sampled native SurfaceWorld cliff identity proof. See $FinalLog." } $NewCrashes = @(Get-NewCrashFolders) if ($NewCrashes.Count -gt 0) { throw "New UECC crash folders appeared during the native cliff check: $($NewCrashes -join '; ')" } Write-Host "VOXELFORGE_CORE_HYBRID_CLIFF_PASS recipe=$CoreMesherRecipe bit_identical=1" Write-Host "Core actor log: $FinalLog" Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes" return } foreach ($Phase in @('initial', 'anchor', 'edit', 'surface_travel', 'surface_strate_travel')) { if ($Text -notmatch "\[VoxelForgeCoreWorldTest\] pass phase=$Phase") { throw "BuildHost Core actor log is missing the '$Phase' validation marker. See $FinalLog." } } 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 = '' if ($EnableHybridFixturePlacement) { $FixtureHashMatch = [regex]::Match($Text, '\[VoxelForgeCoreWorldTest\] hybrid_fixture_placement=1 boxes=9 contacts=5 manifest_hash=([0-9a-f]{16})') if (-not $FixtureHashMatch.Success) { throw "BuildHost actor log is missing the generated hybrid fixture manifest hash. See $FinalLog." } $ExpectedRuntimeAssemblyHash = $FixtureHashMatch.Groups[1].Value } 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 a plan for the unchanged owner SurfaceWorld settings. See $FinalLog." } $RecipeMarker = '\[VoxelForgeCoreWorldTest\] world_initialized=1 recipe=' + [regex]::Escape($CoreMesherRecipe) if ($Text -notmatch $RecipeMarker) { throw "BuildHost actor log does not confirm the requested $CoreMesherRecipe runtime selection. See $FinalLog." } if ($CoreMesherRecipe -in @('WorldAssemblerHybridV1', 'WorldAssemblerHybridV2')) { foreach ($Fixture in @('corner90', 'doorway', 'riser1m', 'cliff_ledge', 'organic_cave_chamber')) { $FixtureMarker = '\[WorldAssemblerHybridPluginFixture\] name=' + [regex]::Escape($Fixture) + ' lod=0 .*exact_repeat=1' if ($Text -notmatch $FixtureMarker) { throw "BuildHost log is missing the production mesher fixture '$Fixture'. See $FinalLog." } if ($CoreMesherRecipe -eq 'WorldAssemblerHybridV2') { $V2FixtureMarker = '\[WorldAssemblerHybridPluginFixtureV2\] name=' + [regex]::Escape($Fixture) + ' lod=0 .*exact_repeat=1' if ($Text -notmatch $V2FixtureMarker) { throw "BuildHost actor log is missing the V2 production mesher fixture '$Fixture'. See $FinalLog." } } } if ($Text -notmatch '\[WorldAssemblerHybridPluginBorder\] same_lod=PASS independent=1') { throw "BuildHost log is missing the independent same-LOD border proof. See $FinalLog." } if ($Text -notmatch '\[WorldAssemblerHybridPluginBorder\] lod0_lod1_doorway=1 cases=125 over_50cm_cases=0') { throw "BuildHost log is missing a passing 125-phase MC doorway contour result. See $FinalLog." } } if ($EnableHybridFixturePlacement -and $Text -notmatch '\[VoxelForgeHybridCollisionContact\] pass=1 probes=5') { throw "BuildHost log is missing the cooked hybrid fixture trace contacts. See $FinalLog." } if ($CoreMesherRecipe -eq 'WorldAssemblerHybridV2' -and $EnableHybridFixturePlacement -and $Text -notmatch '\[VoxelForgeHybridCollisionContact\] fixture=corner_top .*expected_point_error_cm=[0-9.]+') { throw "BuildHost log is missing the V2 flat-face contact precision proof. See $FinalLog." } 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=[1-9]\d* hashes=on') { throw "BuildHost Core actor log is missing the matched native/legacy-bridge surface timing. See $FinalLog." } foreach ($Marker in @( '[VoxelForgeCoreWorldTest] geometry_scale_agreement=PASS', '[VoxelForgeCoreWorldTest] height_agreement=PASS', '[VoxelForgeCoreWorldTest] switch_off_content_gate=PASS', '[VoxelForgeCoreWorldTest] blueprint_carve=PASS', '[VoxelForgeCoreWorldTest] blueprint_fill=PASS', '[VoxelForgePawnSpeedFixture] source=staged_blueprints walk_cm_s=600.000 sprint_cm_s=6000.000' )) { if ($Text -notmatch [regex]::Escape($Marker)) { throw "BuildHost actor log is missing the round-6 proof '$Marker'. See $FinalLog." } } foreach ($Backend in @('core_native', 'legacy_surface_bridge')) { foreach ($LOD in @(0, 1)) { foreach ($Kind in @('flat_column', 'relief', 'mixed', 'unknown')) { if ($Text -notmatch "\[WorldAssemblerPawnLag\] sample=unhashed_runtime_fastpath backend=$Backend lod=$LOD kind=$Kind ") { throw "BuildHost actor log is missing the unhashed $Backend LOD$LOD $Kind streaming-lag row. See $FinalLog." } } } } $NewCrashes = @(Get-NewCrashFolders) if ($NewCrashes.Count -gt 0) { throw "New UECC crash folders appeared during Core actor validation: $($NewCrashes -join '; ')" } Write-Host "VOXELFORGE_CORE_WORLD_PASS recipe=$CoreMesherRecipe fixtures=$HybridFixturePlacementFlag streaming=1 collision=1 anchor_move=1 carve=1" Write-Host "Core actor log: $FinalLog" Write-Host "Peak commandlet private bytes sampled: $PeakPrivateBytes"