First visible bondage animation pipeline orchestrator. Consumes the
primitives added in P3-01..P3-04 + P3-09 to rebuild the livingAnimations
map of a player based on currently equipped bondage items.
Design decisions :
- IdentityHashMap dedup (armbinder covers N regions -> 1 unique stack).
Defensive even though the capability already dedupes (so we don't
depend on an upstream invariant that might regress).
- Sort by posePriority ASC so highest-priority iterates last -> wins
conflicts (Map.put last-write-wins semantics in livingAnimations).
- Option B : JSON items don't bind IDLE, let EF defaults flow through
after resetLivingAnimations() which re-pushes default motions.
- null-check on animations() : 99% of V2 legacy items lack the JSON
block and return null from the parser, must be skipped silently.
- @OnlyIn(Dist.CLIENT) at class level : ClientAnimator is client-only,
server class-loader must never touch this handler.
- Extracted testable methods (extractSortedDefinitions + applyDefinitions)
with functional callbacks (Runnable + LivingAnimationAdder + Function
resolvers). Generic <T> on extractSortedDefinitions lets tests pass
Object dummies without MC ItemStack bootstrap.
Tests (15) covering :
- rebuildBondageAnimations null-safety
- extractSortedDefinitions : empty input, null resolver result, identity
dedup (multi-region), ASC priority sort, null entries skipped
- applyDefinitions : reset-only on empty, null/empty animations skipped,
multi-binding single item, two-item conflict last-write-wins, reset
ordering before any adder, end-to-end multi-region dedup, animResolver
contract (no internal dereference)
Note : this commit provides the HANDLER. The first visible bondage
animation still requires P3-06 (hook it to PacketSyncV2Equipment +
LivingEquipmentChangeEvent) and P3-08 (updateMotion state machine) to
fully light up. Jalon = pipeline viable, not yet wired.
212 tests GREEN (197 baseline + 15 new).