Add portable tracked Godot launcher
This commit is contained in:
@@ -28,6 +28,9 @@ S:\Game Hacking\Eushully\Himegari\ ← workspace root (three siblings)
|
|||||||
│
|
│
|
||||||
└── age-reimpl/ ← OUR WORK (everything we made lives here)
|
└── age-reimpl/ ← OUR WORK (everything we made lives here)
|
||||||
│
|
│
|
||||||
|
├── run-godot.ps1 / run-godot.cmd tracked development launcher + Windows wrapper;
|
||||||
|
│ resolves Godot/game-root from parameters, environment,
|
||||||
|
│ PATH, and the conventional sibling install
|
||||||
├── tools/ Python tooling (parser/disassembler + extractors + VM)
|
├── tools/ Python tooling (parser/disassembler + extractors + VM)
|
||||||
│ ├── paths.py ★ central path anchor — the ONLY place that knows
|
│ ├── paths.py ★ central path anchor — the ONLY place that knows
|
||||||
│ │ where the game / extracted / build dirs are. All
|
│ │ where the game / extracted / build dirs are. All
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ at 2.5M lines). All observe-only → parity preserved; all on `run`/`play`/`swee
|
|||||||
steps / 493k sleeps). Dumped when the scene ends or the window closes. e.g.
|
steps / 493k sleeps). Dumped when the scene ends or the window closes. e.g.
|
||||||
`godot --path godot -- --scene SC0000 --boot --shot out/p1.png --trace-histogram out/hist.txt`.
|
`godot --path godot -- --scene SC0000 --boot --shot out/p1.png --trace-histogram out/hist.txt`.
|
||||||
|
|
||||||
**Godot frontend** (`S:/Godot/Godot_v4.7…`; project = `godot/`). Toolchain: `godot --headless --path godot
|
**Godot frontend** (Godot 4.7 .NET; project = `godot/`). Toolchain: `godot --headless --path godot
|
||||||
--import` → `dotnet build godot/Himegari.csproj` → `godot [--headless] --path godot [-- <userargs>]`.
|
--import` → `dotnet build godot/Himegari.csproj` → `godot [--headless] --path godot [-- <userargs>]`.
|
||||||
Plays the real bytecode with call-script execution on (subroutines run live). The game root is selected
|
Plays the real bytecode with call-script execution on (subroutines run live). The game root is selected
|
||||||
before catalog loading: `--game-root <directory>` wins, otherwise the directory containing the running
|
before catalog loading: `--game-root <directory>` wins, otherwise the directory containing the running
|
||||||
@@ -350,9 +350,13 @@ input, or audible output; run those gates on a real Linux desktop.
|
|||||||
|
|
||||||
With the exported executable placed in an AGE install, a no-argument launch therefore uses that install
|
With the exported executable placed in an AGE install, a no-argument launch therefore uses that install
|
||||||
and starts the persistent `SYSTEM4.BIN` root naturally. Direct development runs are hosted by the Godot
|
and starts the persistent `SYSTEM4.BIN` root naturally. Direct development runs are hosted by the Godot
|
||||||
editor executable, so pass `--game-root <install>` after Godot's `--` separator; the local
|
editor executable, so pass `--game-root <install>` after Godot's `--` separator. The tracked
|
||||||
`run-godot.ps1`/`.cmd` launchers pass the local script's directly configured `$gameRoot` value. Edit that
|
`run-godot.ps1`/`.cmd` launchers resolve Godot and the game root without machine-specific tracked paths.
|
||||||
one assignment when testing another installed game. Those launchers make the natural route explicit with
|
Explicit `-GodotConsole`/`-GameRoot` values win, followed by `AGE_GODOT_CONSOLE`/`AGE_GAME_ROOT`; Godot
|
||||||
|
then falls back to `godot4`, `godot`, or `godot-mono` on `PATH`, while the game root falls back to the
|
||||||
|
conventional `../Himegari_Game` sibling only when it contains `SYS4INI.BIN`. `run-godot.ps1 -Doctor`
|
||||||
|
prints the resolved repository, Godot, game-root, .NET, and Python prerequisites without building or
|
||||||
|
launching. The launchers make the natural route explicit with
|
||||||
`--scene SYSTEM4` and pass neither `--boot` nor SC0000 seeds. Examples below focus on their
|
`--scene SYSTEM4` and pass neither `--boot` nor SC0000 seeds. Examples below focus on their
|
||||||
feature-specific arguments and assume the game root is already selected this way. `--headless` can't
|
feature-specific arguments and assume the game root is already selected this way. `--headless` can't
|
||||||
render texture ops (no GPU context) — run windowed for real scenes.
|
render texture ops (no GPU context) — run windowed for real scenes.
|
||||||
|
|||||||
5
run-godot.cmd
Normal file
5
run-godot.cmd
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
REM Default windowed launch follows SYSTEM4, exposes TITLE's shipped developer menu,
|
||||||
|
REM and uses the accepted GPU retained renderer. Performance logging is opt-in again.
|
||||||
|
REM -StartupDiagnostics overrides the developer-menu flag for a native-faithful capture.
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0run-godot.ps1" -NativeDebugMenu %*
|
||||||
184
run-godot.ps1
Normal file
184
run-godot.ps1
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
# run-godot.ps1 -- build the C# and launch the Himegari Godot project (how we've been running it).
|
||||||
|
#
|
||||||
|
# .\run-godot.ps1 build, then run the persistent SYSTEM4 root windowed
|
||||||
|
# .\run-godot.ps1 -SelfTest build, then headless self-test (asserts the dialogue trace vs vm0)
|
||||||
|
# .\run-godot.ps1 -Import also (re)import the project first (needed after adding assets)
|
||||||
|
# .\run-godot.ps1 -NoBuild skip the dotnet build, just launch
|
||||||
|
# .\run-godot.ps1 -NativeDebugMenu expose TITLE's unreachable shipped developer menu
|
||||||
|
# .\run-godot.ps1 -StartupDiagnostics capture the natural TITLE -> Game Start -> SC0000 route
|
||||||
|
# .\run-godot.ps1 -PerfLog write a timestamped frame/compositor CSV under build/perf
|
||||||
|
# .\run-godot.ps1 -SoftwareRenderer use the retained software correctness oracle
|
||||||
|
# .\run-godot.ps1 -Doctor resolve and print prerequisites without building or launching
|
||||||
|
#
|
||||||
|
# Uses the *console* Godot build so GD.Print / DRAW logs / the selftest result show in the terminal.
|
||||||
|
# Resolution order is explicit parameter, AGE_* environment variable, then a portable fallback.
|
||||||
|
param(
|
||||||
|
[string]$GodotConsole,
|
||||||
|
[string]$GameRoot,
|
||||||
|
[switch]$SelfTest,
|
||||||
|
[switch]$Import,
|
||||||
|
[switch]$NoBuild,
|
||||||
|
[switch]$NativeDebugMenu,
|
||||||
|
[switch]$StartupDiagnostics,
|
||||||
|
[switch]$PerfLog,
|
||||||
|
[switch]$SoftwareRenderer,
|
||||||
|
[switch]$Doctor
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$repo = $PSScriptRoot # age-reimpl/
|
||||||
|
$project = Join-Path $repo 'godot'
|
||||||
|
$csproj = Join-Path $project 'Himegari.csproj'
|
||||||
|
|
||||||
|
function Resolve-ConfiguredFile {
|
||||||
|
param(
|
||||||
|
[string]$ExplicitValue,
|
||||||
|
[string]$EnvironmentValue,
|
||||||
|
[string[]]$PathCommands,
|
||||||
|
[string]$Description
|
||||||
|
)
|
||||||
|
|
||||||
|
$configured = if ($ExplicitValue) { $ExplicitValue } elseif ($EnvironmentValue) { $EnvironmentValue } else { $null }
|
||||||
|
if ($configured) {
|
||||||
|
if (-not (Test-Path -LiteralPath $configured -PathType Leaf)) {
|
||||||
|
throw "$Description not found: $configured"
|
||||||
|
}
|
||||||
|
return (Resolve-Path -LiteralPath $configured).Path
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($commandName in $PathCommands) {
|
||||||
|
$command = Get-Command $commandName -CommandType Application -ErrorAction SilentlyContinue |
|
||||||
|
Select-Object -First 1
|
||||||
|
if ($command) { return $command.Source }
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "$Description not found. Pass -GodotConsole, set AGE_GODOT_CONSOLE, or add Godot to PATH."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Resolve-ConfiguredGameRoot {
|
||||||
|
param(
|
||||||
|
[string]$ExplicitValue,
|
||||||
|
[string]$EnvironmentValue,
|
||||||
|
[string]$ConventionalValue
|
||||||
|
)
|
||||||
|
|
||||||
|
$configured = if ($ExplicitValue) {
|
||||||
|
$ExplicitValue
|
||||||
|
} elseif ($EnvironmentValue) {
|
||||||
|
$EnvironmentValue
|
||||||
|
} else {
|
||||||
|
$ConventionalValue
|
||||||
|
}
|
||||||
|
if (-not (Test-Path -LiteralPath $configured -PathType Container)) {
|
||||||
|
throw "Game root not found: $configured. Pass -GameRoot or set AGE_GAME_ROOT."
|
||||||
|
}
|
||||||
|
$resolved = (Resolve-Path -LiteralPath $configured).Path
|
||||||
|
if (-not (Test-Path -LiteralPath (Join-Path $resolved 'SYS4INI.BIN') -PathType Leaf)) {
|
||||||
|
throw "Game root does not contain SYS4INI.BIN: $resolved"
|
||||||
|
}
|
||||||
|
return $resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
$godotArguments = @{
|
||||||
|
ExplicitValue = $GodotConsole
|
||||||
|
EnvironmentValue = $env:AGE_GODOT_CONSOLE
|
||||||
|
PathCommands = @('godot4', 'godot', 'godot-mono')
|
||||||
|
Description = 'Godot .NET console executable'
|
||||||
|
}
|
||||||
|
$godot = Resolve-ConfiguredFile @godotArguments
|
||||||
|
$gameRootArguments = @{
|
||||||
|
ExplicitValue = $GameRoot
|
||||||
|
EnvironmentValue = $env:AGE_GAME_ROOT
|
||||||
|
ConventionalValue = Join-Path (Split-Path $repo -Parent) 'Himegari_Game'
|
||||||
|
}
|
||||||
|
$resolvedGameRoot = Resolve-ConfiguredGameRoot @gameRootArguments
|
||||||
|
|
||||||
|
if ($Doctor) {
|
||||||
|
$dotnet = Get-Command dotnet -CommandType Application -ErrorAction SilentlyContinue |
|
||||||
|
Select-Object -First 1
|
||||||
|
$python = Get-Command py -CommandType Application -ErrorAction SilentlyContinue |
|
||||||
|
Select-Object -First 1
|
||||||
|
if (-not $dotnet) { throw '.NET SDK not found on PATH.' }
|
||||||
|
if (-not $python) { throw 'Python launcher py.exe not found on PATH.' }
|
||||||
|
Write-Host "Repository : $repo"
|
||||||
|
Write-Host "Godot : $godot"
|
||||||
|
Write-Host "Game root : $resolvedGameRoot"
|
||||||
|
Write-Host "dotnet : $($dotnet.Source)"
|
||||||
|
Write-Host "Python : $($python.Source)"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($SelfTest -and $StartupDiagnostics) {
|
||||||
|
throw '-SelfTest and -StartupDiagnostics are mutually exclusive.'
|
||||||
|
}
|
||||||
|
|
||||||
|
$diagnosticFiles = @()
|
||||||
|
if ($StartupDiagnostics) {
|
||||||
|
$diagnosticDir = Join-Path $repo 'build\validation\title-newgame'
|
||||||
|
New-Item -ItemType Directory -Force -Path $diagnosticDir | Out-Null
|
||||||
|
$diagnosticFiles = @(
|
||||||
|
(Join-Path $diagnosticDir 'godot.log'),
|
||||||
|
(Join-Path $diagnosticDir 'timeline.jsonl'),
|
||||||
|
(Join-Path $diagnosticDir 'histogram.txt'),
|
||||||
|
(Join-Path $diagnosticDir 'page-map.jsonl')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
$perfLogFile = $null
|
||||||
|
if ($PerfLog -and -not $SelfTest) {
|
||||||
|
$perfLogDir = Join-Path $repo 'build\perf'
|
||||||
|
New-Item -ItemType Directory -Force -Path $perfLogDir | Out-Null
|
||||||
|
$perfLogFile = Join-Path $perfLogDir ("run-{0}.csv" -f (Get-Date -Format 'yyyyMMdd-HHmmss-fff'))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $NoBuild) {
|
||||||
|
Write-Host "==> dotnet build $csproj" -ForegroundColor Cyan
|
||||||
|
dotnet build $csproj -c Debug --nologo -v q
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "build failed" }
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Import) {
|
||||||
|
Write-Host "==> importing project" -ForegroundColor Cyan
|
||||||
|
& $godot --headless --path $project --import
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($SelfTest) {
|
||||||
|
Write-Host "==> headless self-test" -ForegroundColor Cyan
|
||||||
|
& $godot --headless --path $project -- --selftest --game-root $resolvedGameRoot
|
||||||
|
} else {
|
||||||
|
# SYSTEM4 owns the real initializer/title/New Game chain. Do not add --boot or SC0000
|
||||||
|
# seeds here: those belong only to explicit direct-scene diagnostics.
|
||||||
|
Write-Host "==> launching windowed from SYSTEM4" -ForegroundColor Cyan
|
||||||
|
$userArgs = @('--scene', 'SYSTEM4', '--game-root', $resolvedGameRoot)
|
||||||
|
if ($perfLogFile) {
|
||||||
|
Write-Host "==> performance log: $perfLogFile" -ForegroundColor Cyan
|
||||||
|
$userArgs += @('--perf-log', $perfLogFile)
|
||||||
|
}
|
||||||
|
if ($SoftwareRenderer) { $userArgs += @('--render-backend', 'software') }
|
||||||
|
if ($NativeDebugMenu -and -not $StartupDiagnostics) { $userArgs += '--native-debug-menu' }
|
||||||
|
if ($StartupDiagnostics) {
|
||||||
|
Write-Host "==> startup diagnostics enabled (native exit semantics)" -ForegroundColor Cyan
|
||||||
|
$userArgs += @(
|
||||||
|
'--timeline-log', $diagnosticFiles[1],
|
||||||
|
'--trace-histogram', $diagnosticFiles[2],
|
||||||
|
'--page-map', $diagnosticFiles[3]
|
||||||
|
)
|
||||||
|
& $godot --log-file $diagnosticFiles[0] --path $project -- @userArgs
|
||||||
|
} else {
|
||||||
|
& $godot --path $project -- @userArgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$godotExitCode = $LASTEXITCODE
|
||||||
|
if ($StartupDiagnostics) {
|
||||||
|
Write-Host "==> startup diagnostic artifacts" -ForegroundColor Cyan
|
||||||
|
foreach ($file in $diagnosticFiles) {
|
||||||
|
if (Test-Path -LiteralPath $file) {
|
||||||
|
$length = (Get-Item -LiteralPath $file).Length
|
||||||
|
Write-Host (" {0} ({1:N0} bytes)" -f $file, $length)
|
||||||
|
} else {
|
||||||
|
Write-Warning "diagnostic artifact was not written: $file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($godotExitCode -ne 0) { exit $godotExitCode }
|
||||||
Reference in New Issue
Block a user