From 137aeb5953cd00b331c25472c3702609135cac63 Mon Sep 17 00:00:00 2001 From: "j.foucher" Date: Thu, 26 Mar 2026 20:04:55 +0100 Subject: [PATCH] Update CLAUDE.md with PS_AI_Behavior architecture and testing status Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/CLAUDE.md | 80 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index d41dc15..5724cae 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,6 +1,8 @@ -# PS_AI_ConvAgent — Notes pour Claude +# PS_AI_Agent — Notes pour Claude -## Naming Convention +## Plugins dans ce repo + +### PS_AI_ConvAgent - **Module**: `PS_AI_ConvAgent` / `PS_AI_ConvAgentEditor` - **API macro**: `PS_AI_CONVAGENT_API` - **Class prefix**: `PS_AI_ConvAgent_` (e.g. `UPS_AI_ConvAgent_PostureComponent`) @@ -8,29 +10,71 @@ - **UI display**: `"PS AI ConvAgent"` (categories, DisplayName) - **CoreRedirects**: DefaultEngine.ini handles both ElevenLabs* and PS_AI_Agent_* → PS_AI_ConvAgent_* +### PS_AI_Behavior +- **Module**: `PS_AI_Behavior` / `PS_AI_BehaviorEditor` +- **API macro**: `PS_AI_BEHAVIOR_API` +- **Class prefix**: `PS_AI_Behavior_` (e.g. `UPS_AI_Behavior_PersonalityComponent`) +- **UI display**: `"PS AI Behavior"` (categories, DisplayName) +- **Interface**: `IPS_AI_Behavior_Interface` — implements on host project Pawns + +## PS_AI_Behavior — Architecture + +### Core Design +- **Interface-driven**: `IPS_AI_Behavior_Interface` on Pawns decouples plugin from host project +- **Personality profiles**: DataAsset with 5 trait axes, thresholds, target priority, speed per state +- **NPCType enum**: Civilian, Enemy, Protector, Any (unified — no separate SplineCategory) +- **TeamIds**: Civilian=1, Enemy=2, Protector=3, auto-assigned in OnPossess +- **Hostile switch**: Enemy with IsBehaviorHostile=false → TeamId=1 (disguised), flips to 2 at runtime + +### Blackboard +- Key `BehaviorState` = Enum type, path: `/Script/PS_AI_Behavior.EPS_AI_Behavior_State` +- Values: Idle(0), Patrol(1), Alerted(2), Combat(3), Fleeing(4), TakingCover(5), Dead(6) +- BB asset created manually in editor (runtime fallback exists but prefer asset) +- SetValueAsEnum / GetValueAsEnum (not Int) + +### BT Pattern +- Services on Selector: UpdateThreat + EvaluateReaction +- Decorator Observer Aborts = Both on Combat/Flee branches +- Spline branch as fallback (lowest priority, no condition decorator) +- Attack task stays InProgress permanently, Decorator pulls out on state change + +### Spline System +- SplinePath actors placed in level, SplineCategory = NPCType +- SplineNetwork WorldSubsystem auto-detects junctions +- SplineFollowerComponent on Pawns: uses Pawn's real velocity, debug green sphere +- Junction switching: 70% probability, direction filter (dot > -0.5) + +### Perception +- Senses configured in BeginPlay (NOT constructor — NewObject crashes in CDO) +- RequestStimuliListenerUpdate() after ConfigureSenses +- Detect ALL affiliations, filter by Hostile attitude in CalculateThreatLevel +- Target priority from PersonalityProfile (combat targeting) + +### Known Gotchas (UE 5.5) +- BB Enum picker doesn't list plugin enums — use string path +- NTFS junctions (not symlinks) for UE5 cross-project plugin linking +- SVN doesn't traverse junctions — robocopy for initial import +- Live Coding fails on header changes — full rebuild required +- BlueprintNativeEvent: UHT auto-generates _Implementation defaults, don't duplicate in .cpp +- FGenericTeamId::NoTeam comparison: always recalculate TeamId (BP CDOs may reset to 0) + +### Testing Status (2026-03-26) +- ✅ Patrol, Spline following, Perception, Threat, Flee, Combat delegation, Hostile switch +- 🔲 Cover Points, EQS, Editor tools (SplineEdMode, CoverPoint placement) + ## Posture System — Diagonal Tilt Bug (à corriger) ### Problème -Le tilt diagonal (ear-to-shoulder) est PLUS VISIBLE avec la neck bone chain qu'avec le mono-bone. Le swing-twist decomposition ne suffit pas. - -### Cause probable -Le swing-twist est fait une seule fois sur le tip bone (head), puis le CleanOffset est extrait via `Swing * Inverse(TipBoneRot)`. Ce CleanOffset est ensuite distribué via Slerp à chaque bone de la chaîne. Mais chaque bone a une orientation locale différente — appliquer le même offset "world-space-like" à des bones avec des axes locaux différents peut réintroduire du tilt. +Le tilt diagonal (ear-to-shoulder) est PLUS VISIBLE avec la neck bone chain qu'avec le mono-bone. ### Piste de fix -Faire le swing-twist **PER-BONE** : pour chaque bone de la chaîne, composer le FractionalRot avec le bone's own rotation, swing-twist autour du bone's own tilt axis, puis appliquer le swing seulement. +Faire le swing-twist **PER-BONE** : pour chaque bone de la chaîne, composer le FractionalRot avec le bone's own rotation, swing-twist autour du bone's own tilt axis. ### Fichiers concernés - `AnimNode_PS_AI_ConvAgent_Posture.cpp` — Evaluate_AnyThread, section multi-bone chain -- Commit actuel: `8df6967` sur main -### Config actuelle neck chain (BP_Taro) -neck_01=0.25, neck_02=0.35, head=0.40 - -## Architecture Posture -- **PS_AI_ConvAgent_PostureComponent** (game thread) : cascade Eyes→Head→Body, produit FQuat + eye curves +## Architecture Posture (ConvAgent) +- **PS_AI_ConvAgent_PostureComponent** (game thread) : cascade Eyes→Head→Body - **AnimNode_PS_AI_ConvAgent_Posture** (anim thread) : applique rotation sur bone(s) + injecte curves -- Pipeline 100% FQuat (pas de round-trip FRotator) -- Thread safety via FCriticalSection -- ARKit eye curves normalisées par range fixe (40°/35°), pas par MaxEye threshold -- Body drift compensation: applied ONLY on first chain bone, AFTER swing-twist -- Debug gaze: per-eye lines from Face mesh using Z-axis (GetAxisZ()) +- Pipeline 100% FQuat, Thread safety via FCriticalSection +- ARKit eye curves normalisées par range fixe (40°/35°)