Files
realms-in-ruin-dev/Documentation/Archaeology/09-EnemyAI-StaticAnalysis.md
T
tedwardsandCursor aa0058a018 Document Pass 11 Phase 1 synthesis and close static archaeology.
Add executive summary and ability migration matrix; finalize evidence index, runtime validation plan, and Phase 1 handoff.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-16 23:40:52 -07:00

220 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 09 — Enemy AI Static Analysis
**Status: Complete**
- **Scope:** Complete static reconstruction of enemy control, targeting, chase, attack, damage, death, animation callbacks, navigation context, and enemy-GAS boundary (Pass 9). Builds on Batch 1 native + Pass 3 structural seeds.
- **Inspection method:** Native C++ read of `ARIRBaseEnemyCharacter` / `ARIRBaseCharacter` / `ITargetInterface`; BlueprintTools EventGraph DSL + interface graphs; AssetTools find/deps/refs; ObjectTools CDO + placed-instance properties; SceneTools find_actors in Test01; project-wide AI asset/subclass searches.
- **Evidence classifications used:** Observed Implementation, Documented Intent, Observed Runtime Behavior, Inferred, Unknown.
- **Tool or visibility limitations:** AnimGraph/transition DSL empty (Death transition rule not fully readable); CharacterMovement orient flags partially unreadable; no PIE possession/nav query validation.
- **Last updated:** 2026-07-16
- **Current phase:** Phase 1 — Static Architecture (complete)
- **Last completed pass:** Pass 11 (Batch 5) — status close; static content Pass 9 (Batch 4C). **Superseded:** earlier “next = Pass 4/10” — Batch 4D completed separately without reopening this docs combat findings.
- **Next pass expected to contribute:** Phase 2D when authorized
## Completion notes
Static enemy AI archaeology is complete. Chase/attack classified **Implementation Missing** (not caused by GetASC). Runtime possession/damage/Death pins: doc `13`.
---
## Executive summary
**Observed Runtime Behavior (project brief):** Enemy chase and attack are nonfunctional — Existing Baseline Defect.
**Pass 9 static conclusion:**
| System | Primary classification |
|--------|------------------------|
| Target acquisition | **Implementation Missing** |
| Chase | **Implementation Missing** (secondary: no navmesh in Test01) |
| Attack initiation | **Implementation Missing** (interface stub + orphan montage) |
| Attack damage | **Implementation Missing** |
| Attack cleanup | **Missing** |
| Damage reception | **Implementation Missing** (BP); ASC Health unconnected to ApplyDamage |
| Death | **Connected but Incomplete** (ABP Death state exists; `IsDead` forced `false` every Update) |
| Enemy GE compatibility | **Existing Baseline Defect** (GetASC → nullptr); separate from chase/attack |
Chase and attack failures are **not** attributable to the enemy ASC accessor defect. They are attributable to **absence of connected chase/attack implementation** at native and Blueprint layers.
---
## 1. Enemy class and control matrix
| Asset/class | Parent | Controller class | AutoPossessAI | Movement component | AnimBP | Interfaces | Status | Evidence |
|---|---|---|---|---|---|---|---|---|
| `ARIRBaseEnemyCharacter` | `ARIRBaseCharacter` + `ITargetInterface` | None set in native | N/A | Inherited CharacterMovement | N/A | ITargetInterface (Highlight/UnHighlight) | Active (ASC+highlight only) | RIRBaseEnemyCharacter.cpp |
| `BP_EnemyCharacterBase` | `RIRBaseEnemyCharacter` | `/Script/AIModule.AIController` | PlacedInWorld | CharMoveComp (inherited) | None on base | None | Scaffolding / empty graphs | CDO + EventGraph DSL |
| `BP_Enemy_Skeleton` | `BP_EnemyCharacterBase_C` | `/Script/AIModule.AIController` | PlacedInWorld | CharMoveComp | `ABP_Skeleton` | `BPI_EnemyCharacter` (GetEnemyREF only) | Scaffolding / empty combat graphs | CDO + DSL |
**Native-only behavior (Observed Implementation):** ASC + AttributeSet on self (Minimal); `InitAbilityActorInfo(this,this)` in BeginPlay; mesh Visibility Block; custom-depth highlight. **No** MoveTo, perception, attack, damage, or health mutation in native.
**Blueprint EventGraphs (both base and Skeleton) — Observed Implementation:**
```
(event EventBeginPlay)
(event Collision|EventActorBeginOverlap (OtherActor))
(event EventTick (DeltaSeconds))
```
All three entry nodes are **Present but Unconnected** (no wired body). Variables on both BPs: **[]**.
**GetEnemyREF (Skeleton only):** returns `self` — Observed Implementation (trivial).
**BPI members not implemented on Skeleton/base:** `AddPlayerTarget`, `EnemyMeleeAttack` — Documented Intent only on interface asset.
---
## 2. Current-level instance matrix
Level: `/Game/_Main/Levels/Testing/Test01`
| Instance | Class | Controller override | AutoPossess override | Relevant instance overrides | Navigation context | Evidence |
|---|---|---|---|---|---|---|
| `BP_Enemy_Skeleton_C_1` | `BP_Enemy_Skeleton_C` | `/Script/AIModule.AIController` (same as CDO) | PlacedInWorld | **None observed** vs CDO | No NavMeshBoundsVolume; no RecastNavMesh; only AbstractNavData fallback | get_properties; find_actors |
| `BP_Enemy_Skeleton_C_0` | same | Unknown — not fully property-dumped | Unknown | Unknown | same level | find_actors presence only |
Selected actor at Pass 9 start/end: `BP_Enemy_Skeleton_C_1` — unchanged.
**Possession note:** `AutoPossessAI=PlacedInWorld` statically allows placed instances to receive AI possession; **spawned** enemies would not auto-possess under this setting. Runtime possession state: **Unknown** without PIE. Stock `AIController` provides no project behavior tree / blackboard / custom logic.
---
## 3. AI framework inventory
| System | Assets/classes found | Active reference path | Status | Evidence |
|---|---|---|---|---|
| Behavior Tree | **None** (`find_assets` name BehaviorTree `/Game` → []) | None | Missing | find_assets |
| Blackboard | **None** (`find_assets` Blackboard → []) | None | Missing | find_assets |
| StateTree | **None** (`find_assets` StateTree → []) | None | Missing | find_assets |
| EQS / EnvQuery | **None** (`find_assets` EnvQuery → []) | None | Missing | find_assets |
| AIPerception assets | **None** (`find_assets` AIPerception → []) | None | Missing | find_assets |
| PawnSensing | None on enemy components | None | Missing | ActorTools component list |
| Custom AIController | search_subclasses → only engine `AIController`, `DetourCrowdAIController`, `GridPathAIController` | Assigned as stock AIController on enemy CDOs | Missing (project) | search_subclasses; CDO |
| MassAI / SmartObject | Not searched by name beyond above; no enemy component refs | None observed | Missing (Observed absence on enemies) | component inventory |
---
## 4. Targeting and chase table
| Entry point | Target source | Awareness check | Movement request | Update mechanism | Stop condition | Connection status | Root-cause relevance |
|---|---|---|---|---|---|---|---|
| EventTick (base/Skeleton) | None | None | None | Tick enabled natively; body empty | N/A | Present but Unconnected | Primary: no chase logic |
| EventActorBeginOverlap | OtherActor pin only | None | None | None | None | Present but Unconnected | No target store |
| BPI AddPlayerTarget | Interface signature only | — | — | — | — | Missing implementation | Documented Intent unused |
| BeginPlay | None | None | None | None | None | Present but Unconnected | No init chase |
| AI MoveTo / SimpleMoveTo / PathFollowing | — | — | **None observed** | — | — | Missing | No movement request exists |
| GetPlayerCharacter / GetPlayerPawn nodes | — | — | — | — | — | Missing in enemy graphs | No player acquisition |
**Primary chase classification: Implementation Missing.**
**Secondary condition:** Test01 has **no** `NavMeshBoundsVolume` and **no** `RecastNavMesh` (find_actors empty). Navmesh readiness is **secondary** — even with a baked mesh, no movement request exists to consume it.
---
## 5. Attack table
| Entry point | Range gate | State gate | Animation | Hit window | Damage path | Cooldown | Cleanup | Status | Evidence |
|---|---|---|---|---|---|---|---|---|---|
| BPI EnemyMeleeAttack | — | — | — | — | — | — | — | **Missing** (unimplemented) | list_graphs / Skeleton events |
| EventTick / Overlap | — | — | — | — | — | — | — | No attack body | EventGraph DSL |
| `Anim_SkeletonAttackMontage` | — | — | Asset exists | Unknown | None (0 referencers) | — | — | **Present but Unreferenced** | get_referencers [] |
| Native C++ | — | — | — | — | None | — | — | Missing | RIRBaseEnemyCharacter.cpp |
**Primary attack initiation classification: Implementation Missing.**
**Secondary:** Orphan attack montage `/Game/_Main/Animations/Enemies/Skeleton/Anim_SkeletonAttackMontage` — Present but Unreferenced; not evidence of an attack path.
---
## 6. Damage and death table
| Input mechanism | Health source | Mutation | Death threshold | Death behavior | Cleanup | Status | Evidence |
|---|---|---|---|---|---|---|---|
| Player ApplyDamage (Paladin/Amazonian/Cleric) | Expected engine TakeDamage | **No** enemy BP `ReceiveAnyDamage`; **no** ASC Health bridge | None observed | None in enemy BP | None | Implementation Missing (reception) | Event list; AttributeSet has no PostGEExecute |
| ASC Health attribute | `URIRAttributeSet` on enemy | Not written by combat graphs | None | None | — | Scaffolding Only for combat | Pass 7 + Pass 9 |
| Gameplay Effect on enemy | EffectActor library GetASC | **nullptr** via base GetASC | N/A | Early-out | — | Existing Baseline Defect | Pass 7 |
| Death animation | ABP Death state + `Anim_Monster_Dead_1..4` | `IsDead` set to **literal false** every UpdateAnimation | Unreachable via IsDead | Death state present | Unknown | Connected but Incomplete | ABP EventGraph DSL |
| DestroyActor / ragdoll / rewards | — | — | — | None observed on enemy BP | Missing | Missing | EventGraph DSL |
**Player→enemy ApplyDamage compatibility (static):** Playable attacks **do** call `ApplyDamage` (Pass 6). Enemy Blueprints **do not** implement AnyDamage→health→death. Native AttributeSet does not clamp or kill from ApplyDamage. **Inferred:** player melee may deal engine damage events with **no observed enemy health/death consumer** — Requires Runtime Inspection for visual feedback only.
---
## 7. Animation callback table
| Asset | Notify/callback | Receiver | Gameplay consequence | State reset | Connection status | Evidence |
|---|---|---|---|---|---|---|
| `ABP_Skeleton` EventGraph | BlueprintInitializeAnimation | GetEnemyREF → Enemy Reference | Cache REF | — | Connected | read_graph_dsl |
| `ABP_Skeleton` EventGraph | BlueprintUpdateAnimation | SetSpeed from velocity; **SetIsDead(false)**; DeathIndex DoOnce | Locomotion speed; **blocks death flag** | — | Connected (death flag forced false) | read_graph_dsl |
| `ABP_Skeleton` Locomotion | States: Idle/Walk/Run, Death | — | Presentation | — | Death transition Unknown (DSL empty) | list_graphs |
| `Anim_SkeletonAttackMontage` | Unknown notifies | No owner plays montage | None | — | Present but Unreferenced | get_referencers [] |
| Death sequences `Anim_Monster_Dead_1..4` | Via ABP Death state | ABP_Skeleton | Cosmetic death pose if state entered | — | Referenced by ABP only | get_dependencies |
**No enemy AnimNotify → damage / UseAbility / ApplyDamage path observed.**
---
## 8. Enemy GAS compatibility table
| Consumer | ASC lookup method | Expected owner | Static result | Null behavior | Potential impact | Runtime verification |
|---|---|---|---|---|---|---|
| `ARIREffectActor::ApplyEffectToTarget` | `UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent``ARIRBaseCharacter::GetAbilitySystemComponent` → PlayerState | Enemy self ASC | **nullptr** | Early return; no GE | Potions/effects skip enemies | PIE |
| Enemy direct `AbilitySystemComponent` member | Native TObjectPtr on enemy | Self | Valid if used | — | No combat consumer observed | — |
| IAbilitySystemInterface on enemy | Same as GetASC base | Self intended | nullptr | Same | Interface consumers fail | PIE |
| Enemy AttributeSet Health | Direct member | Self | Exists; unreplicated combat use | — | Spawn Init values only | PIE |
| Enemy BP damage/death | N/A | — | No ASC read/write in enemy graphs | — | Combat independent of ASC | — |
| Chase / attack graphs | N/A | — | **No dependency on ASC** | — | **GetASC defect does not explain chase/attack failure** | — |
---
## 9. Root-cause summary
| System | Primary classification | Secondary conditions | Exact evidence | Runtime question |
|---|---|---|---|---|
| Target acquisition | **Implementation Missing** | BPI AddPlayerTarget unimplemented; empty Tick/Overlap | EventGraph DSL; interface | — |
| Chase | **Implementation Missing** | No MoveTo; stock AIController; **no navmesh in Test01** | DSL; find_assets; find_actors | Would possession alone idle forever? |
| Attack initiation | **Implementation Missing** | EnemyMeleeAttack unimplemented; attack montage 0 refs | Interface; get_referencers | — |
| Attack damage | **Implementation Missing** | No ApplyDamage/GE from enemy | Native + BP | — |
| Attack cleanup | **Missing** | — | — | — |
| Damage reception | **Implementation Missing** | No ReceiveAnyDamage; no ASC bridge from ApplyDamage | Event list | Do player hits show feedback? |
| Death | **Connected but Incomplete** | ABP Death + death anims exist; **SetIsDead(false)** every frame | ABP EventGraph DSL | Can Death state ever enter? |
| Enemy Gameplay Effect compatibility | **Existing Baseline Defect** / Incomplete Refactor | GetASC → PlayerState | RIRBaseCharacter.cpp | EffectActor on enemy |
---
## BPI_EnemyCharacter inventory
Path: `/Game/_Main/Blueprints/Interfaces/BPI_EnemyCharacter`
| Member | Implemented on Skeleton | Callers (referencers of interface asset) |
|---|---|---|
| GetEnemyREF | Yes → return self | `BP_Enemy_Skeleton`, `ABP_Skeleton` |
| AddPlayerTarget | **No** | None observed beyond interface declaration |
| EnemyMeleeAttack | **No** | None observed |
---
## Negative-search evidence log
| Search | Scope | Result |
|---|---|---|
| find_assets BehaviorTree `/Game` | Project | [] |
| find_assets Blackboard `/Game` | Project | [] |
| find_assets StateTree `/Game` | Project | [] |
| find_assets EnvQuery `/Game` | Project | [] |
| find_assets AIPerception `/Game` | Project | [] |
| search_subclasses AIController | Engine+project | Engine-only classes |
| Source grep MoveTo/BehaviorTree/Attack AI | Source/REALMSINRUIN | No AI combat (only enemy class highlight/ASC) |
| get_referencers Anim_SkeletonAttackMontage | Asset registry | [] |
| find_actors NavMeshBoundsVolume / RecastNavMesh | Test01 | [] |
| Enemy EventGraph MoveTo/GetPlayer*/ApplyDamage nodes | Both enemy BPs | None (empty DSL) |
---
## Migration / defect notes (inventory only)
- Reconstructing enemy AI requires **new implementation** (or restoring unobserved deleted content) — not a reconnect of an existing connected graph.
- Interface `AddPlayerTarget` / `EnemyMeleeAttack` are Documented Intent scaffolds.
- Fixing enemy GetASC is a separate Incomplete Refactor; it does not restore chase/attack.
- ABP `SetIsDead(false)` is a static death-path defect independent of chase.