<# .SYNOPSIS Exports the player's cybernetic arm from the user's .blend to SourceArt\Arm (one FBX per segment + manifest) and regenerates Source\TheDescent\Player\Arm\ArmLayout.inl. Headless Blender; the .blend is never saved. .EXAMPLE powershell -NoProfile -ExecutionPolicy Bypass -File Tools\export_arm.ps1 Exit code 0 = PASS, 1 = FAIL. #> [CmdletBinding()] param( [string]$Blend = 'D:\HADAL - The Descent\models\robotic-arm\robotic-arm.blend' ) $ErrorActionPreference = 'Stop' $ProjectRoot = Split-Path -Parent $PSScriptRoot $Blender = 'E:\Steam\steamapps\common\Blender\blender.exe' $Script = Join-Path $PSScriptRoot 'blender\export_arm.py' $LogFile = Join-Path $ProjectRoot 'Saved\Logs\export_arm_last.log' if (-not (Test-Path $Blender)) { Write-Host "EXPORT FAIL: Blender not found at $Blender"; exit 1 } if (-not (Test-Path $Blend)) { Write-Host "EXPORT FAIL: $Blend not found"; exit 1 } New-Item -ItemType Directory -Force -Path (Split-Path $LogFile) | Out-Null $before = Get-Item $Blend $sw = [System.Diagnostics.Stopwatch]::StartNew() $blArgs = @('-b', ('"' + $Blend + '"'), '--python-exit-code', '1', '--python', ('"' + $Script + '"'), '--') # Blender prints progress to stdout; keep all of it in the log file. cmd /c so stderr lines stay plain text. cmd.exe /c ('"' + $Blender + '" ' + ($blArgs -join ' ') + ' > "' + $LogFile + '" 2>&1') $exit = $LASTEXITCODE $sw.Stop() $lines = Get-Content $LogFile if ($VerbosePreference -eq 'Continue') { $lines | ForEach-Object { Write-Host $_ } } else { $lines | Where-Object { $_ -match '^\[export_arm\]' } | ForEach-Object { Write-Host $_ } } $after = Get-Item $Blend if ($before.Length -ne $after.Length -or $before.LastWriteTimeUtc -ne $after.LastWriteTimeUtc) { Write-Host "EXPORT FAIL: the source .blend changed on disk. This must never happen." exit 1 } $secs = [math]::Round($sw.Elapsed.TotalSeconds, 1) if ($exit -eq 0) { Write-Host ("EXPORT PASS {0}s -> SourceArt\Arm" -f $secs); exit 0 } Write-Host ("EXPORT FAIL exit={0} {1}s log={2}" -f $exit, $secs, $LogFile) exit 1