Records empty enemy EventGraphs, stock AIController possession, orphan attack montage, and separates GetASC defect from chase/attack failure. Co-authored-by: Cursor <cursoragent@cursor.com>
242 lines
15 KiB
Markdown
242 lines
15 KiB
Markdown
# 09 — Enemy AI Static Analysis
|
|
|
|
**Status: Draft**
|
|
|
|
- **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
|
|
- **Last completed pass:** Pass 9 (Batch 4C)
|
|
- **Next pass expected to contribute:** Pass 4 / Pass 10 when authorized — not auto-started
|
|
|
|
## Draft tracking
|
|
|
|
### Completed sections
|
|
- Native enemy ASC, highlight, no native AI combat
|
|
- Full BP_EnemyCharacterBase / BP_Enemy_Skeleton structural + EventGraph reconstruction
|
|
- BPI_EnemyCharacter implementation status
|
|
- Controller / AutoPossessAI class + instance
|
|
- AI framework negative inventory
|
|
- Targeting / chase / attack absence
|
|
- Attack montage orphan
|
|
- ABP_Skeleton locomotion + Death + IsDead forced false
|
|
- Damage/death reception absence at BP layer
|
|
- Enemy GAS compatibility (Pass 7 + Pass 9)
|
|
- Test01 navigation context (no NavMeshBoundsVolume / RecastNavMesh)
|
|
- Root-cause classifications for chase and attack
|
|
|
|
### Pending sections
|
|
- Runtime possession confirmation under PIE
|
|
- Whether engine TakeDamage has any other consumer outside enemy BP
|
|
- ABP Death transition condition exact VariableGet wiring (DSL empty)
|
|
|
|
### Evidence still required
|
|
- PIE: does stock AIController possess placed skeletons?
|
|
- PIE: player ApplyDamage visual/health effect on skeleton
|
|
- Manual Editor: ABP Death transition rule pins
|
|
|
|
---
|
|
|
|
## 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.
|