Skip to content

World snapshot: save_world and load_world (#149, first part) - #160

Merged
nicolas-maman merged 1 commit into
mainfrom
snapshot/world
Oct 9, 2026
Merged

nicolas-maman merged 1 commit into
mainfrom
snapshot/world

Conversation

@nicolas-maman

@nicolas-maman nicolas-maman commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

The first part of #149: the world snapshot (Box3D e77352c's world_snapshot.c). Recording and replay start from one, and it is useful on its own: save states, rollback, debugging a step.

aephysics.snapshot:

  • save_world(world_id) -> (bytes, count) keeps everything a step reads:
    • the settings and the scalars a step carries over;
    • the six id pools;
    • the solver sets with their sims;
    • the bodies;
    • the shapes, with their geometry once each however many shapes share it;
    • the fat boxes;
    • the contacts with their manifolds and mesh caches;
    • the joints, the sensors and the islands;
    • the three trees, as dynamic_tree saves them;
    • the pair set, slots in place;
    • the constraint graph's colours.
  • What a step builds fresh (events, scratch, the solver's constraints) is not kept, nor is what the host wires in (user data, callbacks, worker count).
  • load_world(def, bytes, count) -> WorldId makes a world from def and fills it.
  • Refusal, past the reference's checks:
    • a snapshot of another layout is refused, since its tag folds in the size of every record it copies whole and the geometry's versions;
    • every count is checked against the bytes before anything is copied;
    • each geometry block is checked as bytes from outside are (hull_bytes_valid, mesh_bytes_valid, the compound's sections, and the new height_field_bytes_valid);
    • every pointer a record carried is cleared before the record is used;
    • the loaded world must pass the world's own validation.
    • On any refusal, nothing is left behind.
  • The loaded world owns the meshes, height fields and compounds it holds (dynamics.adopt_geometry, freed with the world). Hulls go through the hull database.

tests/test_snapshot.ae (50 checks):

  • The scene has:
    • a box pyramid reporting to a sensor;
    • spheres, capsules and rocks falling on a mesh with three materials, a height field with holes, and a baked compound;
    • a chain of hinges with a motor;
    • a ragdoll with ankles and its filter joints;
    • a weld, a prismatic spring, a rope, a wheel, a motor and a parallel joint;
    • a disabled body, a kinematic paddle, a bullet, and names on bodies and shapes.
  • It is saved and loaded at steps 0, 1, 45 and 200. The loaded world hashes as the original at once (hash_world_state) and steps 150 steps beside it bit for bit, with the same contact, sensor and hit events every step.
  • A loaded world saved again gives the same bytes.
  • A world stepped on one worker, loaded with four, steps on alike.
  • The loaded world's mesh, field and compound are its own.
  • Every truncation, a byte too many, and another magic, version or layout are refused, with nothing allocated left over.

Found on the way: aether#2611. Same-named locals of different pointer or struct types in sibling while blocks or if branches pass the type checker, but the generated C declares one variable of the first type, so gcc stops. The code here gives each local its own name.

Local gate on Aether 0.795.0: all 35 suites pass with no warnings, and the golden trace matches bit for bit (1,256 steps). Pins: Aether 0.795.0 and aeb v0.325, the latest releases.

Refs #149 (recording, replay and the name cache are next).

aephysics.snapshot keeps everything a step reads: the settings, the id
pools, the solver sets, the bodies, the shapes with their geometry once
each, the fat boxes, the contacts with their manifolds and mesh caches,
the joints, the sensors, the islands, the trees and the pair set, and
the graph's colours. A world loaded from it steps on bit for bit as the
one it was taken from. A snapshot of another layout, or one whose counts,
geometry or invariants fail their checks, loads no world.

The world owns the meshes, height fields and compounds it was loaded with
(dynamics.adopt_geometry); hulls go through the hull database.
height_field.height_field_bytes_valid joins its hull and mesh kin.
@nicolas-maman
nicolas-maman merged commit c327210 into main Oct 9, 2026
2 checks passed
@nicolas-maman
nicolas-maman deleted the snapshot/world branch October 9, 2026 05:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant