v0.8.0
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 andatlas 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 additiveclass-summary
protocol event (documented in the worker-protocol spec;vstays 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 --parallelprints 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). Plaindotnet testandatlas runkeep 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 publicLoadChunkColumnForDimensionwith a dimension-aware completion check.
Boot-time pregenerated mini-dimensions no longer disqualify rollback (the issue #48
acceptance bar): theMiniDimensionChunksLoadeddegrade reason is no longer produced (the
enum member is kept, likePlayersJoinedin 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) andatlas: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
TreeAttributepayloads (version= 1,generation,restoreCount). The event name plus
payload shape is the whole contract: cooperating mods reference only VintagestoryAPI and
rebuild their state fromapi.WorldManager.SaveGameexactly as at boot; the listener is
inert outside Atlas runs. A throwing handler degrades the rollback fail-closed under the
newModHookFailedreason ("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 (useFreshWorld); 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 (thePlayersJoineddegrade
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.RestartWorldstill rejects joined players: their connections die with the host.