Add executive summary and ability migration matrix; finalize evidence index, runtime validation plan, and Phase 1 handoff. Co-authored-by: Cursor <cursoragent@cursor.com>
169 lines
14 KiB
Markdown
169 lines
14 KiB
Markdown
# 10 — Animation Dependencies
|
||
|
||
**Status: Complete**
|
||
|
||
- **Scope:** Animation Blueprints, Montages, AnimNotify Blueprints for playable characters (Pass 8) plus enemy AnimBP/montage findings required by Pass 9 combat archaeology.
|
||
- **Last updated:** 2026-07-16
|
||
- **Current phase:** Phase 1 — Static Architecture (complete)
|
||
- **Last completed pass:** Pass 11 (Batch 5) — status close; static content Pass 8–9. **Superseded:** earlier “next = Pass 4/10” — Batch 4D completed without changing animation findings.
|
||
- **Next pass expected to contribute:** Phase 2B cleanup contracts / Manual Editor notify times when authorized
|
||
|
||
## Completion notes
|
||
|
||
Static animation-dependency archaeology is complete. Notify trigger times, interrupt skip of `AN_AttackComplete`, and Gunslinger AnimClass remain runtime/Manual Editor (`13`).
|
||
|
||
---
|
||
|
||
## Shared animation → ability architecture
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Begin[Server_Ability_N_Begin] --> MC[Multicast_PlayMontage]
|
||
MC --> Play[PlayMontage Mesh]
|
||
Play --> AN1[AN_Ability_00N]
|
||
Play --> ANC[AN_AttackComplete]
|
||
AN1 --> BPI[BPI UseAbility00N]
|
||
BPI --> Auth[SwitchHasAuthority]
|
||
Auth --> FX[ApplyDamage / Heal / Spawn]
|
||
ANC --> SetAtk[BPI SetIsAttacking]
|
||
SetAtk --> Clear[CurrentlyAttacking false]
|
||
```
|
||
|
||
**Observed Implementation:** `Multicast_PlayMontage` on `BP_PlayerCharacterBase` plays the montage with **OnCompleted / OnBlendOut / OnInterrupted unwired**. Attack-window gameplay and `CurrentlyAttacking` cleanup for notify-driven abilities depend on embedded AnimNotify Blueprints, not montage delegates.
|
||
|
||
**Shared notify Blueprints** (`/Game/_Main/Blueprints/Characters/PlayerCharacters/PlayerCharacterRelated/`):
|
||
|
||
| Notify BP | Received_Notify body | Classification |
|
||
|---|---|---|
|
||
| `AN_Ability_001` | `Abilities\|UseAbility001(GetOwner(MeshComp))` | Observed Implementation |
|
||
| `AN_Ability_002` | `UseAbility002(GetOwner)` | Observed Implementation (Cleric agent + deps) |
|
||
| `AN_Ability_003` | `UseAbility003(GetOwner)` | Observed Implementation (Cleric agent + deps) |
|
||
| `AN_Ability_004` | `UseAbility004(GetOwner)` | Observed Implementation (Paladin/Cleric agents + deps) |
|
||
| `AN_AttackComplete` | `BPIPlayerCharacter\|SetIsAttacking(GetOwner(MeshComp))` | Observed Implementation (`read_graph_dsl`) |
|
||
|
||
---
|
||
|
||
## 1. Per-character animation architecture
|
||
|
||
| Character | AnimBP | Skeleton | Relevant state machines | Montage slots | Ability callbacks | Death path | Confidence |
|
||
|---|---|---|---|---|---|---|---|
|
||
| Paladin | `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Paladin/ABP_Paladin` | `SKEL_Hu_M` | `Locomotion`: Idle, Walk/Run, Charge, Block, Death | UpperBody (montages) | None in ABP — notifies call character BPI | `IsDead` → Death state; DeathIndex random | High |
|
||
| Amazonian | `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Amazon/ABP_Amazon` | `SKEL_Hu_F` | `Locomotion`: Idle, Walk/Run, Death | UpperBody | None in ABP | `IsDead` → Death | High |
|
||
| Cleric | `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Cleric/ABP_Cleric` | Male (`SKEL_Hu_M` family) | `Locomotion`: Idle, Walk/Run, **Divine Circle**, Death | UpperBody | None in ABP; reads `DivineCircleActive?` from Cleric | `IsDead` → Death | High |
|
||
| Wizard | `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Wizard/ABP_Wizard` | `SKEL_Hu_M` | `Locomotion`: Idle, Walk/Run, Death | None used by abilities | None — no ability montages in Wizard folder | Death anims in deps | High |
|
||
| Gunslinger | **None** (deps = base only; IsDataOnly) | Unknown / inherited | N/A | N/A | None | Inherited base death only | Medium |
|
||
|
||
**ABP parent class (all inspected):** stock `Engine.AnimInstance` — Observed Implementation.
|
||
|
||
**Paladin ABP drivers (EventGraph):** per-frame reads `IsCharging`, `IsBlocking`, `IsDead`, velocity→`IsMoving` from Paladin REF. Block/Charge/Death transitions driven by those booleans — Observed Implementation.
|
||
|
||
**Cleric ABP drivers:** `DivineCircleActive?` ← `GetDivineCircleActive` on Cleric REF; `IsDead`; speed/moving — Observed Implementation (`read_graph_dsl`).
|
||
|
||
**Amazonian / Wizard ABP:** locomotion + death only — no Block/Charge/DivineCircle states — Observed Implementation.
|
||
|
||
---
|
||
|
||
## 2. Per-ability Montage table
|
||
|
||
| Character | Slot/system | Caller | Montage | Section | Notifies | Callback target | Gameplay consequence | Cleanup dependency | Evidence status |
|
||
|---|---|---|---|---|---|---|---|---|---|
|
||
| Paladin | Ability 001 | `Server_Ability_001_Begin` → Multicast | `.../Paladin/AnimMontages/Attack_{A,B,C,D}_Fast_Montage` (random) | Default (single segment); name Unknown | `AN_Ability_001`, `AN_AttackComplete` (+ sound on A) | `UseAbility001`; `SetIsAttacking` | Authority BoxOverlap ApplyDamage | `AN_AttackComplete` → clear CurrentlyAttacking | Observed Implementation |
|
||
| Paladin | Ability 002 | Begin/End set `IsBlocking` | **No Montage** | — | — | ABP Block state | Presentation only | End clears IsBlocking | Observed Implementation |
|
||
| Paladin | Ability 003 | Charge + Client_Charge | **No Montage** (ChargeTimeline) | — | — | — | ChargeBox ApplyDamage | Timeline/End paths (not notify) | Observed Implementation |
|
||
| Paladin | Ability 004 | `Server_Ability_004_Begin` → Multicast | `.../Paladin/AnimMontages/Abilities/Paladin_Ability004_Montage` | Unknown | `AN_Ability_004`, `AN_AttackComplete`, Niagara `NS_Paladin_Ability004` | `UseAbility004`; `SetIsAttacking` | Authority SphereOverlap ApplyDamage + SFX | `AN_AttackComplete` | Observed Implementation |
|
||
| Amazonian | Ability 001 / melee | `Server_Ability_001_Begin` → Multicast | `.../Amazon/AnimMontages/A_Hu_F_Combat_2H_Attack{01,02,_Base,_}_Montage` | Unknown | `AN_Ability_001`, `AN_AttackComplete` | `UseAbility001`; `SetIsAttacking` | Authority BoxOverlap ApplyDamage | `AN_AttackComplete` | Observed Implementation + Observed Runtime Behavior |
|
||
| Amazonian | 002–004 | Inherited stubs | None | — | — | — | PrintString | — | Observed Implementation |
|
||
| Cleric | Ability 001 | `Server_Ability_001_Begin` → Multicast | `.../Cleric/AnimMontages/Cleric_PrimaryAttack_*` (4) | Unknown | `AN_Ability_001`, `AN_AttackComplete` | `UseAbility001` (**unimplemented** on Cleric) | **No hit** — dead notify | `AN_AttackComplete` still clears attacking | Observed Implementation |
|
||
| Cleric | Ability 002 | Begin → Multicast | `.../Cleric/AnimMontages/Abilities/Cleric_Ability002_Montage` | Unknown | `AN_Ability_002`, `AN_AttackComplete` (+ Niagara/sound deps) | `UseAbility002` (implemented) | Authority heal Players | `AN_AttackComplete` | Observed Implementation |
|
||
| Cleric | Ability 003 | `ConcentrateHandle` timer plays montage | `.../Cleric/AnimMontages/Abilities/Cleric_Ability003_Montage` | Unknown | `AN_Ability_003` (**dead**), `AN_AttackComplete` | `UseAbility003` unimplemented; damage in timer | ApplyDamage in ConcentrateHandle | `EndConcentrate` (not notify) | Observed Implementation |
|
||
| Cleric | Ability 004 | Begin → Multicast | `.../Cleric/AnimMontages/Abilities/Cleric_Ability004_Montage` | Unknown | `AN_Ability_004`, `AN_AttackComplete` | `UseAbility004` (broken spawn) | SpawnActor empty class | `AN_AttackComplete` | Observed Implementation |
|
||
| Wizard | 001–004 | Inherited stubs | **No montages** in Wizard anim folder | — | — | — | PrintString | — | Observed Implementation |
|
||
| Gunslinger | 001–004 | Inherited stubs | None | — | — | — | PrintString | — | Observed Implementation |
|
||
|
||
**Present but Unconnected montage:** `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Cleric/AnimMontages/Cleric_Hu_M_Spell_Staff_Up_Impact_Montage` — references `AN_Ability_004` / `AN_AttackComplete`; **0 referencers**.
|
||
|
||
Play rate: Multicast path uses rate **1** (Pass 6 / Amazonian agent). Start position: Unknown. Root motion: Unknown — Tool Limitation.
|
||
|
||
---
|
||
|
||
## 3. AnimNotify / callback table
|
||
|
||
| Notify or callback | Asset | Character | Ability | Receiver | Downstream path | Authority observation | Connection status |
|
||
|---|---|---|---|---|---|---|---|
|
||
| AN_Ability_001 | `.../PlayerCharacterRelated/AN_Ability_001` | Paladin, Amazonian | 001 | Character via BPI `UseAbility001` | Authority overlap ApplyDamage | Multicast montage → notify all machines; damage Authority-only | **Connected** |
|
||
| AN_Ability_001 | same | Cleric | 001 | BPI `UseAbility001` | **No implementation** on Cleric/base | Notify fires; no gameplay | **Notify Present; Receiver Unimplemented** |
|
||
| AN_Ability_002 | `.../AN_Ability_002` | Cleric | 002 | `UseAbility002` | Authority heal | Same multicast pattern | **Connected** |
|
||
| AN_Ability_003 | `.../AN_Ability_003` | Cleric | 003 | `UseAbility003` | Unimplemented; damage is timer | Vestigial | **Notify Present; Receiver Unimplemented** |
|
||
| AN_Ability_004 | `.../AN_Ability_004` | Paladin | 004 | `UseAbility004` | Authority AoE damage | Multicast + Authority | **Connected** |
|
||
| AN_Ability_004 | same | Cleric | 004 | `UseAbility004` | Broken SpawnActor | Multicast + Authority | **Connected (broken body)** |
|
||
| AN_AttackComplete | `.../AN_AttackComplete` | Paladin, Amazonian, Cleric (all listed montages) | 001/002/004 (+ Cleric primary) | BPI `SetIsAttacking` | Base Authority: CurrentlyAttacking=false, CanMove true | Multicast notify; state Authority-only | **Connected** |
|
||
| PerformingWhirlwind | N/A animation | Amazonian | — | Character EventAnyDamage Get only | No AnimBP/montage Set | — | **Present but Unconnected setter** |
|
||
| Divine Circle state | ABP_Cleric | Cleric | 003 presentation | Reads DivineCircleActive | Locomotion state | Cosmetic | **Connected** (presentation) |
|
||
|
||
---
|
||
|
||
## 4. Pass 6 reclassification table
|
||
|
||
| Character | Slot | Previous status | Revised status | New evidence | Reason |
|
||
|---|---|---|---|---|---|
|
||
| Paladin | 001 | Implemented | **Implemented** (qualified) | `AN_Ability_001` → `UseAbility001`; cleanup `AN_AttackComplete` | Animation connectivity confirmed; status unchanged |
|
||
| Paladin | 002 | Partial | **No change** | ABP Block driven by `IsBlocking` | Presentation path confirmed; hit absorb still untraced |
|
||
| Paladin | 003 | Implemented | **No change** | No Montage; ChargeTimeline | Animation pass does not alter charge path |
|
||
| Paladin | 004 | Implemented | **Implemented** (qualified) | `AN_Ability_004` → `UseAbility004` | Connectivity confirmed; empty particle remains |
|
||
| Amazonian | 001 | Implemented | **No change** | Full notify → damage → cleanup chain | Confirms known working melee path |
|
||
| Amazonian | 002–004 | Stub | **No change** | No montages/notifies | — |
|
||
| Amazonian | Whirlwind | Partial / unconnected setter | **No change** | Not in ABP or montages | Still Get-only on character |
|
||
| Cleric | 001 | Partial (montage only) | **Partial** (qualified: dead notify) | `AN_Ability_001` present; `UseAbility001` unimplemented | Notify does not add gameplay |
|
||
| Cleric | 002 | Partial | **Partial** (qualified: notify-driven heal) | `AN_Ability_002` → `UseAbility002` | Heal path confirmed animation-timed; FX hole remains |
|
||
| Cleric | 003 | Implemented | **Implemented** (qualified: timer + vestigial notify) | Damage in ConcentrateHandle; `AN_Ability_003` dead; ABP Divine Circle state | Notify not required for damage |
|
||
| Cleric | 004 | Partial / defect | **No change** (qualified: notify-timed) | `AN_Ability_004` → broken `UseAbility004` | Spawn defect unchanged |
|
||
| Wizard | 001–004 | Stub | **No change** | ABP locomotion only; zero Wizard montages | — |
|
||
| Gunslinger | 001–004 | Stub | **No change** | No AnimBP; deps = base only | — |
|
||
|
||
---
|
||
|
||
## Networking and authority (static)
|
||
|
||
| Observation | Classification |
|
||
|---|---|
|
||
| Montage started via Multicast → notifies evaluate on server and clients | Observed Implementation / Inferred (UE montage notify semantics) |
|
||
| `UseAbility*` / `SetIsAttacking` bodies use `SwitchHasAuthority` | Observed Implementation (Pass 6) |
|
||
| Duplicate damage prevented by Authority gate if notify fires everywhere | Inferred static risk mitigation — Requires Runtime Inspection |
|
||
| Gameplay depends on cosmetic Multicast montage evaluating notifies on the server | Observed Implementation — **static risk:** if server skips animation evaluation, hit windows may not fire |
|
||
| Missing `AN_AttackComplete` (interrupt) leaves `CurrentlyAttacking` true | Inferred — PlayMontage interrupt pins unwired |
|
||
| No client-authoritative ApplyDamage in notify receivers | Observed Implementation |
|
||
|
||
---
|
||
|
||
## Answers to Pass 8 known questions (compact)
|
||
|
||
1. **UseAbility* callers:** `AN_Ability_001–004` AnimNotify BPs (not AnimBP EventGraph).
|
||
2. **Paladin 001 damage:** Yes — via `AN_Ability_001` during montage.
|
||
3. **Paladin block:** No Montage; ABP `Block` state from `IsBlocking`; End clears flags.
|
||
4. **Paladin charge cleanup:** Not Montage-callback; ChargeTimeline / ability logic.
|
||
5. **Amazonian melee path:** Begin → Multicast montage → `AN_Ability_001` → `UseAbility001` → Authority damage; `AN_AttackComplete` clears attacking.
|
||
6. **Weapon collision notifies:** Not observed on inspected montages (overlap queries inside UseAbility*).
|
||
7. **PerformingWhirlwind:** Never set by animation; still unconnected.
|
||
8. **Cleric 001 hidden gameplay:** No — notify dead (`UseAbility001` unimplemented).
|
||
9. **Cleric 002/003/004:** 002/004 notify-driven; 003 timer-driven; Divine Circle ABP presentation.
|
||
10. **Wizard spell assets via anim:** No Wizard montages; no notify chain to unwired NS/GE/projectile.
|
||
11. **Gunslinger shared AnimBP/Montage:** No — no AnimBP dependency.
|
||
12. **CurrentlyAttacking clear:** Via `AN_AttackComplete` for notify-driven attacks; interrupt cleanup Unknown.
|
||
13. **Death anims:** ABP Death state from `IsDead`; destruction/respawn remain character `PlayerDeath` (not notify-driven).
|
||
14. **Client-only gameplay timing:** Damage Authority-gated; presentation may diverge — Requires Runtime Inspection.
|
||
|
||
---
|
||
|
||
## Pass 9 — Enemy animation dependencies
|
||
|
||
| Character | AnimBP | Skeleton | Relevant state machines | Montage slots | Ability callbacks | Death path | Confidence |
|
||
|---|---|---|---|---|---|---|---|
|
||
| Skeleton enemy | `/Game/_Main/Animations/Enemies/Skeleton/ABP_Skeleton` | UE4_Mannequin_Skeleton (deps) | Locomotion: Idle/Walk/Run, Death | None used by combat | GetEnemyREF cache only | Death state + `Anim_Monster_Dead_1..4`; **`SetIsDead(false)` every Update** | High |
|
||
|
||
| Asset | Notify/callback | Character | Ability | Receiver | Downstream | Connection status |
|
||
|---|---|---|---|---|---|---|
|
||
| `Anim_SkeletonAttackMontage` | Unknown (unplayed) | Skeleton | Attack | None | None | **Present but Unreferenced** (0 referencers) |
|
||
| `ABP_Skeleton` Update | SetIsDead(false) | Skeleton | Death | Self | Blocks death flag | **Connected but Incomplete** |
|
||
|
||
No enemy AnimNotify → ApplyDamage path observed. Full enemy AI: `09-EnemyAI-StaticAnalysis.md`.
|