7.2 KiB
Slice J5.6 — projectile-simulation ownership
Date: 2026-07-26 Scope: ownership relocation only; no retail algorithm, packet, collision policy, impact authority, or presentation change
Objective
Move the mutable projectile component, projectile workset, prediction version,
authoritative correction, and retail projectile step into the same
AcDream.Runtime physics lifetime that already owns the canonical entity
record, body, object clock, collision engine, shadows, and full cell.
App remains responsible for:
- resolving the projectile's immutable Setup/DAT collision sphere;
- supplying the current graphical projection validity acknowledgement;
- rebucketing and positioning the retained render projection after a Runtime commit;
- synchronizing the render shadow and effect pose;
- drawing meshes, trails, particles, sounds, and impact effects.
ACE remains authoritative for targets, hits, damage, impact scripts, and deletion.
Named-retail oracle
Primary source:
docs/research/named-retail/acclient_2013_pseudo_c.txt.
CPhysicsObj::UpdateObjectInternal0x005156B0CPhysicsObj::update_object0x00515D10CPhysicsObj::SetPositionInternal(CTransition const*)0x00515330CPhysicsObj::set_velocity0x005113F0OBJECTINFO::missile_ignore0x0050CEB0Frame::set_vector_heading0x00535DB0
The complete translated retail projectile control flow is pinned in
docs/research/2026-07-13-retail-projectile-vfx-pseudocode.md. The existing
Core ProjectilePhysicsStepper and collision driver were cross-checked there
against ACE's physics implementation and Holtburger/ACViewer's DAT
interpretation. J5.6 reuses those algorithms unchanged.
Preserved control flow
for each spatial projectile owned by the current incarnation:
reject static, frozen, parented, hidden, cell-less, or inactive bodies
advance the retained CPhysicsObj clock in retail 0.2-second quanta
for each due quantum:
calculate acceleration from the final PhysicsState
clamp speed to 50 world units/second
integrate position, velocity, omega, and AlignPath orientation
continuously sweep the authored Setup-local collision sphere
apply retail missile-ignore and inelastic/elastic collision rules
commit the accepted frame and full cell to the canonical record
stop the split prediction if any authority/incarnation token changed
publish one immutable committed frame to the host
The graphical host may reject the presentation acknowledgement after a re-entrant delete, replacement, rebucket, or session reset. That rejection invalidates the pending prediction; it cannot roll back or redirect a newer canonical owner.
Previous ownership gap
Before J5.6:
RuntimeEntityRecordowned identity, body, state, clocks, and cell;RuntimePhysicsStateowned the engine, shadows, remotes, and ordinary/remote worksets;- App
ProjectileControllerstill owned the projectile component, projectile workset snapshot, quantum stepping, correction, and canonical cell commit.
That split made a no-window Runtime unable to fly the same projectile without reconstructing App behavior and left projectile mutation on the wrong side of the presentation boundary.
Implemented boundary
RuntimeEntityRecord.Projectileis the sole mutable projectile component slot.RuntimeProjectileowns the canonical body, authored collision sphere, and prediction-authority version.RuntimePhysicsStateowns binding, refresh, spatial membership, authoritative vector/state correction, and the exact-key projectile workset.RuntimeProjectilePhysicsUpdaterowns the unchanged retail quantum, integration, sweep, collision, cell-crossing, and split-prediction logic.- Runtime cell commits flow through the same typed
RuntimePhysicsCellCommitused by ordinary and remote objects. - App
ProjectileControllerresolves DAT/Setup shape data, delegates the simulation, and applies only retained render projection, shadow, and effect pose acknowledgements. - Delete, GUID reuse, visibility withdrawal, pending-to-loaded recovery, authoritative correction, and session teardown use the canonical Runtime record and workset; they never reconstruct from stale spawn data.
No gameplay outcome moved client-side. No projectile-specific render pass, second GUID map, body mirror, effect owner, or collision owner was introduced.
Automated acceptance
On production commit
2aee33569f0268d7bc0f4f52437dfa0b405432a4:
- Runtime tests: 317 passed.
- App tests: 3,718 passed / 3 skipped.
- Focused Core projectile tests: 47 passed.
- Complete Release solution: 8,591 passed / 5 skipped.
- Release solution build: zero warnings and zero errors.
The focused fixtures cover:
- canonical component/body/workset identity;
- 0.2-second catch-up quanta and prediction invalidation;
- clamp, gravity, omega, full 3-D AlignPath, and collision;
- thin walls and inelastic stopping;
- missile/ethereal/designated-target exclusion;
- loaded, pending, landblock crossing, and hydration;
- State/Vector/Position correction order;
- deletion, same-GUID reuse, reset, and 96-owner lifetime stress;
- no duplicate mesh, body, shadow, script, effect, or projectile owner.
Connected acceptance
All connected processes used the exact embedded/source commit
2aee33569f0268d7bc0f4f52437dfa0b405432a4 and closed gracefully.
- Arrow plus representative spell projectile:
.test-out/j56-projectile-20260726-143256recorded an authoritative missile attack, live Arrow spawn, live Acid Stream spawn, and matching authoritative deletes. - Crossbow bolt:
.test-out/j56-crossbow-evidence-20260726-145612recorded a missile attack, live Quarrel spawn with Setup0x0200012A, authoritative ammo pickup/update, projectile delete, and target death. - Lifecycle/reconnect:
logs/connected-world-gate-20260726-145731/report.jsonpassed capped login plus fresh uncapped reconnect, all seven checkpoints, zero failures, and two code-zero exits. - Canonical nine-stop route:
logs/connected-r6-soak-20260726-151349.report.jsonmaterialized all nine destinations, passed the Caul/Holtburg/Caul-return forward, jump, combat, and movement-truth exercises, matched source and binary, and exited with code zero and zero failures.
The first route attempt,
logs/connected-r6-soak-20260726-150347.report.json, intentionally remains in
the evidence trail. Its strict plateau check saw the already-known late lazy
mesh population (582 -> 604) while sampled entity counts happened to match
and therefore reported one failure. The immediate warm-machine rerun saw the
same class of late population (581 -> 598) together with one changed visible
owner and correctly classified it as workload variation. The accepted J5.5
baseline exhibited the same late Caul behavior (575 -> 597), and the J5.6
diff contains no mesh-cache, mesh-preparation, streaming, or residency change.
This is not waived as a projectile result and no threshold was loosened.
Divergence and rollback
J5.6 changes ownership only. The retail algorithm, constants, packet order, server authority, and presentation are unchanged, so it introduces no new retail-divergence row.
Exact rollback:
git revert 2aee33569f0268d7bc0f4f52437dfa0b405432a4