feat(vfx): bind effects to live animated poses
This commit is contained in:
parent
96ddfdf175
commit
542dcfc384
41 changed files with 3246 additions and 741 deletions
|
|
@ -740,10 +740,84 @@ Repository links:
|
|||
2. Logical entity creation/destruction is separate from spatial rebucketing.
|
||||
3. Server Position/Vector/State/Delete packets remain authoritative.
|
||||
4. No client-side impact, explosion, damage, or deletion is synthesized.
|
||||
5. Per-object frame ordering preserves retail: animation/timed object hooks,
|
||||
movement commit and child updates, particle tick, then PhysicsScript tick.
|
||||
A script-created emitter begins particle simulation on the following tick.
|
||||
5. Presentation frame ordering is fixed: advance animation/root motion,
|
||||
publish indexed parts, compose equipped children, drain animation hooks,
|
||||
tick owner PhysicsScripts, refresh attached emitters/lights, then advance
|
||||
particle simulation and draw.
|
||||
|
||||
Retail stages animation hooks inside `CSequence::update`, then executes them
|
||||
from `CPhysicsObj::process_hooks` before the new root is committed. The same
|
||||
update subsequently calls `CPhysicsObj::set_frame` (`0x00514090`), which runs
|
||||
`CPartArray::SetFrame` and `UpdateChildrenInternal`; that relocates the newly
|
||||
parented emitter/held child to the final pose before `ParticleManager` advances
|
||||
or anything draws. acdream's explicit publish-then-drain barrier preserves that
|
||||
observable ordering without exposing a half-committed pose to modern sinks.
|
||||
6. Hidden suppresses mesh/collision/interaction but does not destroy the effect
|
||||
owner.
|
||||
7. DAT assets determine models, colors, timing, and attachment behavior.
|
||||
8. Every ported branch receives a conformance test and a named-retail citation.
|
||||
|
||||
## 14. Step 5 implementation map (2026-07-14)
|
||||
|
||||
- `EntityEffectPoseRegistry` exposes current root and indexed part-local poses
|
||||
through `IEntityEffectPoseSource`. The indexed channel contains retail's
|
||||
rigid `CPhysicsPart` frames, not drawable mesh scale: `UpdateParts
|
||||
0x005190F0` multiplies only the animation origin by object scale, while
|
||||
`SetScaleInternal 0x00518A00` stores Setup `DefaultScale` separately on
|
||||
`gfxobj_scale`. Animated entities publish those rigid frames beside their
|
||||
visually scaled `MeshRef` composition; equipped children then publish
|
||||
`holdingFrame * parentPart * parentRoot` plus the child's own indexed part
|
||||
locals. Appearance replacement republishes immediately.
|
||||
- `AnimationHookFrameQueue` captures hooks during sequence advance and drains
|
||||
only after equipped-child composition. `AnimationDone` and `UseTime` remain
|
||||
paired with the sequencer even if its render pose vanished during teardown.
|
||||
- `ParticleHookSink` binds each live handle to local owner, exact part index
|
||||
(including root `-1`), complete offset Frame, logical emitter ID, and render
|
||||
pass. It applies the offset origin through `partLocal * rootWorld`; the
|
||||
retained offset quaternion remains intentionally unused per
|
||||
`Particle::Init 0x0051C930`.
|
||||
- Normal nonzero logical IDs replace, blocking nonzero IDs suppress while the
|
||||
old emitter remains live, and zero IDs create anonymously. Natural emitter
|
||||
retirement releases the logical ID. `StopParticleEmitter` retains the ID
|
||||
until that retirement, while destroy removes it immediately. Missing
|
||||
`ParticleEmitterInfo` DAT
|
||||
records log owner + DID and create nothing; the former synthesized generic
|
||||
cloud is removed.
|
||||
- World-released particles retain their emission origin while future emissions
|
||||
follow the refreshed anchor. Parent-local particles consume the refreshed
|
||||
anchor for existing particles, matching `Particle::Update 0x0051C290` and
|
||||
`ParticleEmitter::UpdateParticles 0x0051D180`.
|
||||
Loaded-to-pending spatial transitions skip particle update/draw under retail's
|
||||
cell-less `update_object 0x00515D10` gate while retaining the emitter,
|
||||
particles, original absolute creation times, and logical ID. Authoritative pose
|
||||
correction may still refresh the anchor. Re-entry evaluates elapsed particle
|
||||
age/emitter duration once and emits no absent-time backlog; timestamps are not
|
||||
shifted to freeze the effect.
|
||||
- Setup lights retain their complete local `LIGHTINFO` frame.
|
||||
`LiveEntityLightController` owns live registration/re-entry and every frame
|
||||
`LightingHookSink` composes it through the current owner root/cell. Held
|
||||
objects use the child root published after `CPhysicsObj::UpdateChild
|
||||
0x00512D50`; top-level roots follow their `WorldEntity`. PhysicsState's
|
||||
Lighting bit and `SetLightHook` both drive the same create/destroy state,
|
||||
matching `CPhysicsObj::set_state 0x00514DD0` and `set_lights 0x0050FCF0`.
|
||||
This retires AP-67 and TS-10.
|
||||
Light presentation follows `LiveEntityRuntime`'s final projection edge, so a
|
||||
loaded-to-loaded rebucket does not replay registration and a pending owner
|
||||
contributes no stale light. Attached lights wait for the composed-child-pose
|
||||
barrier before their first registration.
|
||||
- Setup-part indices are retained separately from drawable `MeshRefs`; a
|
||||
missing middle GfxObj cannot shift later hook/holding indices. Nested held
|
||||
objects update parent-before-child and compose through the parent's already
|
||||
published child root. The buffers are retained by the attachment owner and
|
||||
reused each frame.
|
||||
- Logical teardown removes queues, emitters, lights, and poses exactly once;
|
||||
rebucketing does not. Pose loss withdraws an attached projection and its
|
||||
descendants while retaining accepted relations for valid later recovery.
|
||||
A post-publish parent-first recovery drain realizes the complete descendant
|
||||
chain, preventing an A→B→C graph from stranding C after B returns. The drain
|
||||
is edge-triggered by object/appearance/pose publication, never a per-frame
|
||||
retry loop for a permanently absent Setup or holding part.
|
||||
Session reset clears captured hooks and live poses
|
||||
through normal owner teardown while retaining DAT-static/synthetic poses.
|
||||
TS-11 and TS-12 are retired with the emitter-binding and
|
||||
live-part mechanisms.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue