Skip to content

v0.9.1

Choose a tag to compare

@github-actions github-actions released this 14 Jul 01:52
· 21 commits to main since this release
dccdbb4

Fixed

  • JoinPlayer no longer hands the world back to the scenario while the engine's background
    server-assets build can still be enumerating live game content (issue #84, from the
    StratumParity field report: a scenario that joined a player and immediately ran a
    2048-SetBlock burst, under a staged source mod that lengthens the build, hit "Collection was
    modified" inside BuildServerAssetsPacket on a TyronThreadPool thread, and an unhandled
    pool-thread exception kills the whole testhost process, twice in a row on a 4-core CI
    runner). After the join reaches the Playing state, JoinPlayer now waits for the exact
    completion signal the issue #46 dispose-time guard already reads from the other end of the
    host lifecycle (the private ServerMain.serverAssetsPacket box: packet assigned by
    non-dedicated builds, Atlas's case, or Length bumped by dedicated ones), awaited on the
    game-thread tick scheduler so the pump keeps processing while the build finishes, and
    bounded at 1800 ticks (~60 s at the engine's nominal tick pace, mirroring the dispose-side
    bound) with an engine-drift AtlasSetupException on expiry. On the supported engines
    (verified by decompile on 1.20.12, 1.21.7 and 1.22.3) the build is queued at boot by
    ServerMain.Launch() and HandleRequestJoin itself blocks on the same signal, so a
    completed join normally settles the check instantly: the guard costs two cached-reflection
    reads per join and only actually waits when a mod kicked the player mid-join before the
    join's own wait ran (or on engine forks that defer the build to the first join, the field
    report's case). The probe reflection now has a single owner (ServerAssetsBuildProbe, its
    pure signal shape in AssetsBuildSignal) shared by both guards, and an engine whose signal
    layout drifted degrades exactly like the dispose side: skip the wait behind a one-time
    warning. The faulty enumeration itself is vanilla engine code (reported upstream at
    StratumServer/Stratum#151); Atlas closes the window scenarios could race it from.

  • Scratch directories no longer accumulate until they exhaust the temp filesystem (issue
    #83, from the StratumParity field report: a day of repeated local runs piled up 722
    directories, 1.7 GB, under /tmp/atlas on a 16 GB tmpfs, at which point the ENGINE's own
    disk guard ("Disk space is below 400 megabytes... Will kill server now") failed every
    subsequent boot with a message that never mentions Atlas). The registry now sweeps a
    disposed host's scratch directory (world save, logs, staged mods), but only when nothing
    argues for keeping it: no scenario of the owning class has failed so far, the host did
    not crash, its game thread joined within the teardown bound, and ATLAS_KEEP_SCRATCH is
    not set (set it to 1 to keep everything while debugging). Anything red keeps its scratch
    untouched, because server-main.log in there is the documented post-mortem artifact the
    0.9.0 engine-crash fail-fast points users at; an abnormal process death keeps everything
    too (the sweep only runs on orderly teardowns). Multi-host classes sweep per host under
    the same green-so-far rule (a FreshWorld recycle mid-class, a completed RestartWorld
    restart once its save is harvested), the atlas fixture harvest path never sweeps (the
    fixture is copied out of the scratch after disposal), and deletion is best-effort by
    design: a short bounded retry covers the engine releasing file handles a beat after
    stop, and a delete that still fails logs one stderr line instead of failing any test.
    Applies to dotnet test and the atlas CLI (sequential, worker and parallel modes)
    alike: they share the registry. The keep-or-delete decision and the retry loop live in
    pure cores (ScratchRetention, ScratchCleanup, the AssetsBuildSettle pattern) with unit
    coverage; the E2E regressions run guinea pig classes through the full pipeline and
    assert a green class's scratch is gone after hand-off while a failing class's survives
    with its server-main.log.