8.8 KiB
Ymir
Ymir is the GameCult library and service boundary around a pinned Box3D release, being cut over into Aetheria's authoritative embedded physics substrate. The name means Not Invented Here. We are taking the hint.
Box3D owns physics algorithms. Ymir owns the service boundary that makes those algorithms usable as durable, typed GameCult world truth. Unity, renderers, and game products consume Ymir state and contact facts; they do not become physics authorities.
The production runtime path is a retained Box3D session. The parity facade witnesses released behavior at the native boundary; Ymir adds stable ids, typed commands and facts, replay memory, and deterministic projection without installing a second solver.
Front Door
- Value: a retained Box3D physics session with GameCult world truth around it: stable entity ids, explicit mutation receipts, typed contact facts (Begin/Hit/End), replay-backed checkpoints, and deterministic result ordering.
- Problem: physics authority must not be split between Unity callbacks, gameplay geometry tests and a managed solver. Box3D decides physics, Ymir owns the service boundary, Aetheria supplies intent.
- Entry points:
src/Ymir.Core/YmirSession.cs: the public in-process retained session (commands, receipts, stepping, queries,CapturePersistence).YmirSimulator.csis the snapshot facade that wraps an isolated session.src/Ymir.Box3D/andnative/Ymir.Box3D/: the native session ABI and the Ymir-owned Box3D shim (GameCult.Ymir.Box3Dpackage).tests/Ymir.Box3D.Parity/: the executable parity contract against pinned Box3D v0.1.0 (docs/box3d-parity.md).docs/architecture.md,docs/retained-session-contract.md,docs/aetheria-cutover.md.- Build and test:
git submodule update --init --recursive, thendotnet test Ymir.slnx(needs CMake and a C17 compiler).
- Live: retained sessions, replay-backed checkpoint reconstruction, parity for overlap and cast queries, tractor membership, contact-begin facts, restitution, torque lifetime, collision filtering and bullet CCD. Aetheria embeds one session per run and zone and stores persistence in a daemon-private CultCache. Package version
0.3.0. - Planned: journal compaction, Linux and macOS package RIDs (built and smoked on their own workers), a committed release smoke for packaging, and the optional standalone daemon (
src/ymir-daemonis a thin command host today and is never in Aetheria's gameplay path).
Target Ownership
- Box3D owns rigid-body integration, collision geometry, broadphase, solver behavior, continuous collision, overlap and cast semantics, contact lifecycle, force and torque lifetime, tolerances, and deterministic step behavior for identical recorded inputs.
- Ymir owns the pinned Box3D version, stable GameCult entity ids, native ABI isolation, public in-process retained sessions, explicit mutation receipts, typed contact facts, snapshot lowering, deterministic result ordering, versioned CultCache snapshots.
- An optional Ymir daemon may own named session routing, durable command receipts, checkpoint reconstruction, CultMesh command/fact publication, and process supervision for worlds it hosts. It is not part of Aetheria's gameplay path.
- Aetheria owns gameplay policy and supplies typed physical intent: bodies, fields, tractor targets, forces, projectiles, filters, and the gameplay consequences of Ymir contact facts.
- CultMath remains available for GameCult-side numeric projections and force preparation. It is not a second collision or integration engine.
- Unity and Eve lowerers render world state and submit commands. They never repair, override, or independently simulate authoritative physics.
Box3D opaque handles are process-local derived state. They are never durable entity ids and never cross the public contract boundary.
Ymir does not promise bit-identical continuation from an arbitrary mid-world snapshot. Replay starts from canonical creation order plus the complete command stream. Checkpoints may accelerate numeric state recovery within named tolerances, but authoritative contact lifecycle facts resume only after that canonical history has been replayed through the checkpoint tick.
Aetheria Deployment Boundary
Aetheria embeds the Ymir library and native Box3D wrapper in its own daemon. The Aetheria daemon owns gameplay ticks, world policy, player sessions, commands, receipts, assets, and the Eve/CultMesh provider advertisement. Generic Eve clients connect directly to Aetheria; they do not connect through Ymir or a rendezvous service.
A future standalone Ymir daemon may expose the same physics contract for tooling or other products. It is not an intermediary in Aetheria's gameplay path and must never become a competing copy of Aetheria world truth.
Current Cutover State
Box3D v0.1.0 is pinned at commit
8441b4a06d6d09dcfb0b0f704df4d847d1437b92. A Ymir-owned native shim and
parity suite already witness released Box3D behavior for:
- sphere overlap and shape casts
- tractor capsule membership and rounded caps
- numeric overlap and cast slop
- planar sphere-world stepping
- contact-begin facts
- restitution mixing
- transient torque lifetime
- category/mask/group collision filtering
- bullet CCD against kinematic bodies, including Box3D's next-step contact-event timing
The production Ymir.Box3D boundary owns the native session ABI. The legacy
snapshot YmirSimulator.Step contract now creates an isolated Box3D session,
projects the result, and disposes it. It contains no managed integrator,
collision loop, or impulse solver.
That snapshot facade deliberately does not pretend to own long-lived world
identity. The public in-process YmirSession now exposes explicit body
mutations, force and torque commands, revisioned receipts, retained stepping,
and typed Begin/Hit/End facts. It never treats omission as removal. Aetheria
embeds one session per run and zone; its old process-wide simulator objects
are not session identifiers. Revision-checked
retained-session circle overlap and cast queries observe the current stable-id
body projection without mutating it. Replay-backed checkpoint reconstruction is
implemented. CapturePersistence emits only the journal suffix not yet stored
by its host plus a bounded resume descriptor; restore verifies contiguous
chunks, the complete journal digest, the projected world, and active contact
episodes before the session can emit facts. Aetheria stores those records in a
daemon-private CultCache and uses its hard-flushed public frame as the commit
marker. Journal compaction and non-Windows RID artifacts remain cutover work.
See the architecture map and the executable parity contract. The retained-session contract records the current ownership cut shared by embedded and optional standalone hosts.
Build And Test
Initialize the pinned dependency and run the solution:
git submodule update --init --recursive
dotnet test Ymir.slnx
The parity project builds the native shim from source and requires CMake plus a C17 compiler:
dotnet test tests\Ymir.Box3D.Parity\Ymir.Box3D.Parity.csproj
Box3D is MIT licensed. Its license is retained in extern/box3d.
GameCult.Ymir.Box3D packages the managed boundary, Box3D license, and native
facade under runtimes/<rid>/native. A local Windows x64 package has loaded in
an isolated empty consumer without CMake or the submodule. A committed release
smoke is still required before that is a repeatable packaging guarantee. Linux
and macOS packages must be produced and smoked on their own release workers
before those RIDs are advertised.
The current package version is 0.3.0. ABI v5 exposes the exact pinned native
build identity plus Box3D body type,
bullet, field-participation, and collision-filter configuration without
exposing Box3D handles. These are Ymir contract fields, but their behavior is
Box3D behavior.
Cutover Rule
A Ymir cutover is complete only when all runtime stepping, collision queries, and contact facts come from Box3D through an explicitly owned Ymir session. Manual Unity callbacks and Aetheria geometry tests must be structurally unable to decide the result. Snapshot compatibility calls may use isolated sessions; they are not allowed to infer or share retained-world identity.
Building against CultLib
Builds are pinned to CultLib 2.0.0 (tag cultlib-unity-v2.0.0, revision 42dce3611a81adc5c5fac54cadbaa5637d6022d3); the build fails if the CultLib checkout differs or is dirty. Create a pinned worktree and point the build at it:
git -C <CultLib> worktree add --detach <path> cultlib-unity-v2.0.0
dotnet build -p:CultLibRoot=<path> # or set CULTLIB_ROOT=<path>
Without an override the sibling ..\CultLib checkout is used and must itself be at that tag.