Skip to content

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 11 Jul 19:28
· 51 commits to main since this release
a6c8adf

Added

  • Isolation summaries and restart costs beyond stderr (issue #66, from the Manifold 0.7.0
    dogfooding). RestartWorld's cost is no longer invisible: the restart (shutdown + harvest +
    boot) is measured in the registry, attached to the requesting scenario's own test output
    ("[Atlas] world restarted: ... (cost 7.1 s, paid outside the scenario's reported
    duration).", the same channel degrade reports use, so it lands in the IDE test explorer,
    the TRX per-test output and atlas run), and accumulated into the per-class isolation
    summary ("2 restart(s) (14.1 s total)"); degraded rollbacks get the same treatment, their
    summary breakdown now carrying the total fallback-recycle cost. The per-class summaries
    themselves now travel beyond stderr: worker mode emits a new additive class-summary
    protocol event (documented in the worker-protocol spec; v stays 1) between the class's
    last test event and its class-end, fed by a reflection-installed harness sink plus a
    graceful final-host shutdown before the stream closes; atlas run --parallel prints each
    observed summary live, repeats them under an "Isolation summaries:" section in its final
    summary, and stores them as the aggregated TRX's run-level output
    (ResultSummary/Output/StdOut). Plain dotnet test and atlas run keep their stderr line
    unchanged.

  • Mini-dimension support and mod-cooperation hooks for world rollback (issue #48, stage 3 of
    the snapshot/rollback design). Rollback now covers EVERY dimension: capture records loaded
    chunk columns as (X, Z, Dimension) triples (the database rows were dimension-keyed all
    along), marks loaded mini-dimension chunks dirty before the forced save so the engine's
    dimension-aware reload always finds complete columns, discards non-zero-dimension columns
    through the engine's own per-chunk unload helper (never persisting, and never firing
    column-unloaded events the engine itself does not emit for mini-dimensions), and reloads
    them via the public LoadChunkColumnForDimension with a dimension-aware completion check.
    Boot-time pregenerated mini-dimensions no longer disqualify rollback (the issue #48
    acceptance bar): the MiniDimensionChunksLoaded degrade reason is no longer produced (the
    enum member is kept, like PlayersJoined in stage 2, so recorded summaries and logs keep
    their meaning). New mod-cooperation contract for mods whose in-memory state is keyed to
    SaveGame data (registries, allocators, generated-marker stores): Atlas pushes two engine
    event-bus events synchronously on the game thread, atlas:rollback:captured (once per
    capture, after the snapshot is in memory) and atlas:rollback:restored (every restore,
    after the database and SaveGame globals are restored and BEFORE any chunk column reloads,
    so chunk-loaded handlers and ticks never observe desynced mod state), with versioned
    TreeAttribute payloads (version = 1, generation, restoreCount). The event name plus
    payload shape is the whole contract: cooperating mods reference only VintagestoryAPI and
    rebuild their state from api.WorldManager.SaveGame exactly as at boot; the listener is
    inert outside Atlas runs. A throwing handler degrades the rollback fail-closed under the
    new ModHookFailed reason ("mod rollback hook failed") and fails the scenario under
    StrictIsolation. Mods that cooperate through neither lifecycle events nor the hook remain
    a documented hard boundary (use FreshWorld); no unsound detection heuristics were added.
    Also ships the restore-cost instrumentation the spec asked for: every restore logs one
    stderr line with the measured duration and the dirty-columns-at-restore ratio (the numbers
    that would justify the deliberately deferred dirty-column filtering optimization).

  • Player-aware world rollback (issue #47, stage 2 of the snapshot/rollback design):
    [AtlasScenario(RollbackWorld = true)] now works on classes with joined test players. The
    snapshot captures, per joined player, the playerdata blob the forced save wrote (restored
    verbatim into the database) plus the live state a reset needs; a rollback resets the live,
    still-connected player in place: position, watched attributes (health, saturation, custom mod
    trees, merged key-by-key so behaviors that cached sub-tree references keep working),
    inventories (the swapped-inventories duplicate-items case), world player data (game mode,
    move speed, picking range, spawn, hotbar slot, deaths) and per-player moddata. Players that
    joined AFTER the snapshot was captured are removed by the rollback, so the world returns
    exactly to its captured population; their engine-side identity caches and playerdata rows are
    purged and their joined-name claims released, so the same name can rejoin as a brand-new
    player (the rollback waits for the release, so an immediate rejoin never hits the
    duplicate-name guard). Restore ordering is player-safe by construction: post-capture players
    are removed while the world is still live, the database is restored before the in-memory
    unload (so any player-adjacent column the engine re-requests already reads snapshot bytes),
    and live players are reset in the same game-thread turn as the unload, before a single tick
    is pumped. The stage 1 guards are gone: capture no longer refuses joined players, and the
    players-joined setup error in the rollback path is removed (the PlayersJoined degrade
    reason is kept so already-recorded summaries and logs keep their meaning, but it is no longer
    produced); rollbacks on player-hosting classes count as plain successes in the per-class
    isolation summary. Not reset, documented boundary: a player's animation/interaction state
    (test players are headless) and the host-scoped privileges/role data, which is not world
    state. RestartWorld still rejects joined players: their connections die with the host.