fix #203: preserve animation on appearance updates
This commit is contained in:
parent
ff06aa3107
commit
c7607f019c
9 changed files with 237 additions and 22 deletions
|
|
@ -46,6 +46,28 @@ Copy this block when adding a new issue:
|
|||
|
||||
---
|
||||
|
||||
## #203 — Unequipping armor freezes character and world animations — FIXED
|
||||
|
||||
**Status:** DONE — 2026-07-11 (this change)
|
||||
**Severity:** HIGH
|
||||
**Component:** live entities / animation / appearance updates
|
||||
|
||||
**Description:** After armor was removed, the local character stopped animating
|
||||
and animation-dependent world interactions such as doors appeared frozen.
|
||||
|
||||
**Root cause:** `0xF625 ObjDescEvent` was incorrectly handled as a full
|
||||
despawn/respawn. That discarded the live `WorldEntity`, animation manager,
|
||||
physics host, and collision registration while the player movement controller
|
||||
still referenced the discarded sequencer. Named retail instead applies
|
||||
`DoObjDescChangesFromDefault` to the existing object.
|
||||
|
||||
**Resolution:** Appearance hydration now mutates only the existing entity's
|
||||
meshes, palette, part overrides, and bounds. Entity identity, animation playback,
|
||||
movement, physics, collision, selection, and dead-reckoning state survive. The
|
||||
classification cache is invalidated in place. A regression test pins entity and
|
||||
sequencer identity across the update. User verified the exact equip/unequip flow
|
||||
in the Release client.
|
||||
|
||||
## #191 — Tapping W (brief forward press) glides forward without playing the step animation
|
||||
## #194 — WbDrawDispatcher._groups is never pruned (minor)
|
||||
|
||||
|
|
@ -7161,7 +7183,7 @@ threshold.
|
|||
|
||||
**Component:** rendering / `WbDrawDispatcher` / `EntityClassificationCache` / `LandblockLoader`
|
||||
|
||||
**Resolution.** New `EntityClassificationCache` keyed by `(entityId, landblockHint)` tuple in `src/AcDream.App/Rendering/Wb/EntityClassificationCache.cs`. The dispatcher routes static entities (NOT in `_animatedEntities`) through the cache — first-frame slow-path populates flat `CachedBatch[]` (one entry per (partIdx, batchIdx) with the part-relative `RestPose` and resolved `BindlessTextureHandle`); subsequent-frame cache hits skip classification entirely and append `cached.RestPose * entityWorld` to each matching group. Animated entities bypass. Invalidation fires from `RemoveLiveEntityByServerGuid` (per-entity, `0xF747`/`0xF625`) and `RemoveEntitiesFromLandblock` (per-LB, Near→Far demote + unload).
|
||||
**Resolution.** New `EntityClassificationCache` keyed by `(entityId, landblockHint)` tuple in `src/AcDream.App/Rendering/Wb/EntityClassificationCache.cs`. The dispatcher routes static entities (NOT in `_animatedEntities`) through the cache — first-frame slow-path populates flat `CachedBatch[]` (one entry per (partIdx, batchIdx) with the part-relative `RestPose` and resolved `BindlessTextureHandle`); subsequent-frame cache hits skip classification entirely and append `cached.RestPose * entityWorld` to each matching group. Animated entities bypass. Invalidation fires from `RemoveLiveEntityByServerGuid` for real despawns (`0xF747`), directly from the in-place `0xF625` appearance mutation, and from `RemoveEntitiesFromLandblock` (per-LB, Near→Far demote + unload).
|
||||
|
||||
**Perf result.** Entity dispatcher cpu_us **median ~1200 µs, p95 ~1500 µs** at horizon-safe + High preset on AMD Radeon RX 9070 XT @ 1440p. Pre-Tier-1 baseline was ~3500m / ~4000p95. ~66% reduction in median, ~63% in p95. Well under the A.5 spec budget (median ≤ 2.0 ms, p95 ≤ 2.5 ms). No `BUDGET_OVER` flag observed.
|
||||
|
||||
|
|
|
|||
|
|
@ -292,6 +292,13 @@ Target state: every entity in the world — player, NPC, monster, lifestone,
|
|||
door, chest — becomes a `GameEntity`. The renderer iterates them and draws.
|
||||
The plugin API exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
||||
|
||||
Lifecycle invariant in both the current split model and the target `GameEntity`:
|
||||
an `ObjDescEvent` changes appearance in place. It may replace resolved meshes,
|
||||
palette ranges, part overrides, and visual bounds, but it must preserve entity
|
||||
identity plus animation, motion, physics, collision, selection, and
|
||||
dead-reckoning owners. Only a real delete/despawn tears those owners down. This
|
||||
matches retail's `CPhysicsObj::DoObjDescChangesFromDefault` behavior.
|
||||
|
||||
---
|
||||
|
||||
## Per-Frame Update Order (current runtime)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@
|
|||
**Created:** 2026-05-10, opening move of the ISSUE #53 retry session.
|
||||
**Purpose:** enumerate every code path that writes to `WorldEntity.MeshRefs` (the dispatcher's load-bearing per-entity input) and every adjacent state read by `WbDrawDispatcher.ClassifyBatches` / model-matrix composition, classify each as STATIC or DYNAMIC, and design the cache invalidation surface BEFORE touching renderer code.
|
||||
|
||||
> **Superseded detail (2026-07-11):** this historical audit described
|
||||
> `0xF625 ObjDescEvent` as despawn + respawn. That was an acdream implementation
|
||||
> artifact, not retail behavior, and caused animation state to freeze after
|
||||
> equip/unequip. Appearance updates now mutate the existing entity and invalidate
|
||||
> its classification cache in place, matching
|
||||
> `CPhysicsObj::DoObjDescChangesFromDefault`. Real despawns remain unchanged.
|
||||
|
||||
This audit is the load-bearing prerequisite the prior Tier 1 attempt (commit `3639a6f`, reverted at `9b49009`) skipped. Cache design follows from the audit, not the other way around.
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@
|
|||
**Originating issue:** [docs/ISSUES.md](../../ISSUES.md) §#53.
|
||||
**Phase context:** Phase Post-A.5 polish, Priority 3 (only remaining priority after #52 + #54 closed).
|
||||
|
||||
> **Historical correction (2026-07-11):** this spec inherited the old assumption
|
||||
> that `0xF625 ObjDescEvent` was a despawn/respawn. The cache behavior remains
|
||||
> valid, but appearance updates now preserve entity identity and invalidate the
|
||||
> entity's cache entry in place, matching retail.
|
||||
|
||||
---
|
||||
|
||||
## §1. Problem
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue