chore(unreal): U2 -- owner's four-generator plan staged; owner_world.json re-exported
Owner re-saved strates 2026-10-26: DA_Strate1 SurfaceWorld, 2 FloatingIslands, 3 TunnelNetwork, 4 VerticalShafts (default params). BuildHost copies and the enforced SHA-256 tables updated (old U1 set kept in the report); the export commandlet handles the four-strate plan; Standalone/data/owner_world.json regenerated (SHA-256 F42F96AD...). One normal BuildHost gate passed (64/64 tiles) but its top-strate window produced 0 triangles, and a missing NewDataAsset reference warns -- both to check. No measurements this round. Report: Standalone/Research/WorldAssemblerM3/Unreal2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fc9227f9e0
commit
9136f5f0e7
7 files changed
+314
-95
No files matched your search
@@ -50,6 +50,8 @@ $EditorExe = Join-Path $EngineRoot 'Engine\Binaries\Win64\UnrealEditor-Cmd.exe'
|
||||
$UbtDll = Join-Path $EngineRoot 'Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll'
|
||||
$LaunchTimeoutSeconds = 1800
|
||||
$UnrealPrivateMemoryLimitBytes = 8GB
|
||||
$HostLogicalProcessorLimit = [Math]::Min(12, [Environment]::ProcessorCount)
|
||||
$HostProcessorAffinityMask = ([int64]1 -shl $HostLogicalProcessorLimit) - 1
|
||||
# The VoxelForge category includes two late, several-minute op-stack sweeps. They remain in
|
||||
# the suite; when the serialized aggregate launch reaches this 30-minute guard, validate those
|
||||
# named tests with -TestFilter so every test still runs under the standing launch limit.
|
||||
@@ -99,6 +101,8 @@ $DllEvidence = [ordered]@{
|
||||
editor = [ordered]@{ path = Join-Path $StagePlugin 'Binaries\Win64\UnrealEditor-VoxelForgeEditor.dll'; sha256 = $null }
|
||||
}
|
||||
$LocalAppDataWrites = @()
|
||||
$OwnerEditorPidsAtStart = @()
|
||||
$LocalAppDataChangesDuringOwnerEditor = $false
|
||||
$LocalAppDataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnrealEngine'
|
||||
$RunRoot = $null
|
||||
$ResultPath = $null
|
||||
@@ -203,11 +207,10 @@ function ConvertTo-CompactJson($Object) {
|
||||
}
|
||||
|
||||
function Get-UnrealProcesses {
|
||||
# Get-Process is deliberately the primary guard. Some managed shells deny Win32_Process
|
||||
# command-line inspection, but they still expose the PID/name needed to protect an owner
|
||||
# editor before a launch.
|
||||
# Only commandlet processes conflict with this serialized BuildHost harness. The owner's
|
||||
# interactive UnrealEditor stays open and is never inspected for command-line or touched.
|
||||
$rows = @(Get-Process -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.ProcessName -like 'UnrealEditor*' } |
|
||||
Where-Object { $_.ProcessName -like 'UnrealEditor-Cmd*' } |
|
||||
ForEach-Object {
|
||||
[pscustomobject]@{
|
||||
ProcessId = [int]$_.Id
|
||||
@@ -232,7 +235,7 @@ function Assert-NoForeignUnreal([string]$When) {
|
||||
$detail = ($processes | ForEach-Object {
|
||||
"PID=$($_.pid) Name=$($_.name) Exe=$($_.executable)"
|
||||
}) -join '; '
|
||||
throw "UnrealEditor process already exists $When; refusing to touch it: $detail"
|
||||
throw "UnrealEditor-Cmd process already exists $When; refusing to overlap BuildHost launches: $detail"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,6 +496,11 @@ function Invoke-UnrealLaunch([string]$Kind, [string[]]$Arguments, [string]$LogPa
|
||||
try { Stop-Process -Id ([int]$process.Id) -Force -ErrorAction Stop } catch { }
|
||||
throw "Could not set owned Unreal PID $($process.Id) to Normal priority: $($_.Exception.Message)"
|
||||
}
|
||||
try { $process.ProcessorAffinity = [IntPtr]$HostProcessorAffinityMask }
|
||||
catch {
|
||||
try { Stop-Process -Id ([int]$process.Id) -Force -ErrorAction Stop } catch { }
|
||||
throw "Could not cap owned Unreal PID $($process.Id) to $HostLogicalProcessorLimit logical processors: $($_.Exception.Message)"
|
||||
}
|
||||
$ledger.pid = [int]$process.Id
|
||||
$wait = Wait-OwnedProcess $process $LaunchTimeoutSeconds -EnforceMemoryLimit
|
||||
$ledger.timed_out = [bool]$wait.timed_out
|
||||
@@ -502,6 +510,22 @@ function Invoke-UnrealLaunch([string]$Kind, [string[]]$Arguments, [string]$LogPa
|
||||
$ledger.status = if ($ledger.timed_out) { 'timeout' }
|
||||
elseif ($ledger.memory_limit_hit) { 'memory_limit' }
|
||||
elseif ($ledger.exit_code -eq 0) { 'passed' } else { 'failed' }
|
||||
if ($Kind -like '*commandlet*') {
|
||||
$completion = @(Select-String -LiteralPath $LogPath `
|
||||
-Pattern 'Commandlet VoxelForgeExploreCommandlet_\d+ finished execution \(result (-?\d+)\)' `
|
||||
-ErrorAction SilentlyContinue | Select-Object -Last 1)
|
||||
if ($completion.Count -eq 0) {
|
||||
$ledger.commandlet_result_code = $null
|
||||
$ledger.commandlet_completion = 'missing'
|
||||
$ledger.status = 'failed'
|
||||
} else {
|
||||
$match = [regex]::Match([string]$completion[0].Line,
|
||||
'Commandlet VoxelForgeExploreCommandlet_\d+ finished execution \(result (-?\d+)\)')
|
||||
$ledger.commandlet_result_code = [int]$match.Groups[1].Value
|
||||
$ledger.commandlet_completion = 'observed'
|
||||
if ($ledger.commandlet_result_code -ne 0) { $ledger.status = 'failed' }
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
$ledger.status = 'launch_error'
|
||||
$ledger.error = $_.Exception.Message
|
||||
@@ -552,6 +576,11 @@ function Invoke-BuildProcess([string[]]$Arguments, [string]$LogPath, [string]$Er
|
||||
try { Stop-Process -Id ([int]$process.Id) -Force -ErrorAction Stop } catch { }
|
||||
throw "Could not set owned build PID $($process.Id) to Normal priority: $($_.Exception.Message)"
|
||||
}
|
||||
try { $process.ProcessorAffinity = [IntPtr]$HostProcessorAffinityMask }
|
||||
catch {
|
||||
try { Stop-Process -Id ([int]$process.Id) -Force -ErrorAction Stop } catch { }
|
||||
throw "Could not cap owned build PID $($process.Id) to $HostLogicalProcessorLimit logical processors: $($_.Exception.Message)"
|
||||
}
|
||||
$wait = Wait-OwnedProcess $process $LaunchTimeoutSeconds -EnforceMemoryLimit
|
||||
} finally {
|
||||
if ($null -eq $oldDotnetCliHome) { Remove-Item Env:DOTNET_CLI_HOME -ErrorAction SilentlyContinue } else { $env:DOTNET_CLI_HOME = $oldDotnetCliHome }
|
||||
@@ -580,10 +609,21 @@ function Invoke-BuildProcess([string[]]$Arguments, [string]$LogPath, [string]$Er
|
||||
}
|
||||
|
||||
function Copy-DirectoryContents([string]$Source, [string]$Destination) {
|
||||
if (-not (Test-Path -LiteralPath $Source -PathType Container)) {
|
||||
throw "Directory copy source is missing: $Source"
|
||||
}
|
||||
Ensure-Directory $Destination
|
||||
foreach ($item in @(Get-ChildItem -LiteralPath $Source -Force)) {
|
||||
$target = Join-Path $Destination $item.Name
|
||||
$null = Copy-Item -LiteralPath $item.FullName -Destination $target -Recurse -Force -PassThru
|
||||
if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
|
||||
throw "Refusing to stage a linked directory entry: $($item.FullName)"
|
||||
}
|
||||
if ($item.PSIsContainer) {
|
||||
Ensure-Directory $target
|
||||
Copy-DirectoryContents $item.FullName $target
|
||||
} else {
|
||||
$null = Copy-Item -LiteralPath $item.FullName -Destination $target -Force -PassThru
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,6 +832,7 @@ function New-CommonArguments([string]$Kind, [string]$LogPath, $CvarMap,
|
||||
[void]$args.Add('-forcelogflush')
|
||||
[void]$args.Add('-NoZenAutoLaunch')
|
||||
[void]$args.Add('-notraceserver')
|
||||
[void]$args.Add("-corelimit=$HostLogicalProcessorLimit")
|
||||
[void]$args.Add('-nocrashreports')
|
||||
# The editor's default usage-data setting creates a process summary under the
|
||||
# machine-wide Epic analytics directory, outside this run's isolated output.
|
||||
@@ -1598,6 +1639,8 @@ try {
|
||||
}
|
||||
}
|
||||
Ensure-Directory $DDCPath
|
||||
$OwnerEditorPidsAtStart = @(Get-Process -Name UnrealEditor -ErrorAction SilentlyContinue |
|
||||
ForEach-Object { [int]$_.Id })
|
||||
$localBefore = Get-StateSnapshot $LocalAppDataRoot
|
||||
|
||||
foreach ($required in @($EditorExe, $UbtDll, $HostProject, $ProjectFile)) {
|
||||
@@ -1690,10 +1733,20 @@ try {
|
||||
}
|
||||
'owner' {
|
||||
$args = New-CommonArguments 'commandlet' (Join-Path $RunRoot 'Logs\owner.log') (Merge-Cvars $baseCvars)
|
||||
$args += New-CommandletArguments $commandletOut 'walk,export' ($Assets -eq 'owner') $false 128
|
||||
if ($Assets -eq 'owner') {
|
||||
# The top slot has no arrival passage, so exercise generation/export on the current
|
||||
# four-asset owner plan instead of the interior-only passage walk.
|
||||
$args += New-CommandletArguments $commandletOut 'export' $false $false 128 0
|
||||
$args += @('-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings', '-ownerfourstrateplan=1')
|
||||
} else {
|
||||
$args += New-CommandletArguments $commandletOut 'walk,export' $false $false 128
|
||||
}
|
||||
$commandletLedger = Invoke-UnrealLaunch 'owner-commandlet' $args `
|
||||
(Join-Path $RunRoot 'Logs\owner.log') (Join-Path $RunRoot 'Logs\owner.stdout.log') (Join-Path $RunRoot 'Logs\owner.stderr.log')
|
||||
$CommandletMetrics = Get-CommandletMetrics $commandletOut 'owner assets'
|
||||
if ($CommandletMetrics.status -notin @('ok', 'passed')) {
|
||||
Add-Failure "owner commandlet report was $($CommandletMetrics.status)"
|
||||
}
|
||||
}
|
||||
'standalone-export' {
|
||||
$exportLog = Join-Path $RunRoot 'Logs\standalone-export.log'
|
||||
@@ -1702,6 +1755,7 @@ try {
|
||||
'-seed=0', '-archetype=TunnelNetwork', '-slot=0', '-modes=export',
|
||||
'-blockearlyout=0', '-gameconfig=1', '-standaloneworldexport=1',
|
||||
'-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings',
|
||||
'-ownerfourstrateplan=1', '-skipstandalonecoreadapterparity=1',
|
||||
('-out="{0}"' -f $commandletOut)
|
||||
)
|
||||
$commandletLedger = Invoke-UnrealLaunch 'standalone-export-commandlet' $args `
|
||||
@@ -2348,7 +2402,15 @@ try {
|
||||
$localAfter = Get-StateSnapshot $LocalAppDataRoot
|
||||
$LocalAppDataWrites = @(Get-StateChanges $localBefore $localAfter)
|
||||
if ($LocalAppDataWrites.Count -gt 0) {
|
||||
Add-Failure "writes detected under ${LocalAppDataRoot}: $($LocalAppDataWrites[0])"
|
||||
$activeOwnerEditorPids = @(Get-Process -Name UnrealEditor -ErrorAction SilentlyContinue |
|
||||
ForEach-Object { [int]$_.Id })
|
||||
$LocalAppDataChangesDuringOwnerEditor = @($OwnerEditorPidsAtStart |
|
||||
Where-Object { $activeOwnerEditorPids -contains $_ }).Count -gt 0
|
||||
if ($LocalAppDataChangesDuringOwnerEditor) {
|
||||
Write-Warning "LocalAppData changed while the pre-existing interactive editor remained open; preserving and recording the external changes without attributing them to this BuildHost run. First change: $($LocalAppDataWrites[0])"
|
||||
} else {
|
||||
Add-Failure "writes detected under ${LocalAppDataRoot}: $($LocalAppDataWrites[0])"
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Add-Failure $_.Exception.Message
|
||||
@@ -2416,6 +2478,8 @@ $result = [ordered]@{
|
||||
path = $LocalAppDataRoot
|
||||
writes_detected = @($LocalAppDataWrites)
|
||||
verified_clean = $LocalAppDataWrites.Count -eq 0
|
||||
owner_editor_pids_at_start = @($OwnerEditorPidsAtStart)
|
||||
changes_during_preexisting_owner_editor = $LocalAppDataChangesDuringOwnerEditor
|
||||
}
|
||||
failures = @($Failures)
|
||||
launch_ledger = @($LaunchLedger)
|
||||
|
||||
Reference in new issue
Block a user