Files
ProjectFGame/Architecture_Projet.md
T
2026-09-21 13:23:13 +02:00

190 KiB
Raw Blame History

đŸ—ïž Architecture du Projet — ProjectF

Ce document est la rĂ©fĂ©rence d'architecture du projet, destinĂ©e en prioritĂ© aux modĂšles d'IA (Claude, etc.) qui vont lire, modifier ou crĂ©er du contenu dans ce projet Unreal Engine. Il doit permettre de comprendre oĂč se trouve chaque systĂšme, quel fichier est responsable de quoi, et oĂč ajouter du nouveau contenu — sans avoir Ă  explorer tout le projet Ă  chaque session.

⚠ Ce document doit rester Ă  jour. Voir la section 10. Maintenir ce document Ă  jour et le skill maintain-architecture-doc.


1. Vue d'ensemble du projet

1.1 Nature du projet

  • Moteur : Unreal Engine 5.8.
  • Aucun code C++ : il n'y a pas de dossier Source/. Tout le gameplay est Ă©crit en Blueprint visuel, dans Content/.
  • Genre : jeu de survie / extraction en vue 3e personne avec un inventaire en grille façon "Escape from Tarkov" (armure, sac Ă  dos, armes, munitions, craft sur feu de camp/fonderie, gĂ©nĂ©rateurs, lecteurs de carte magnĂ©tique, coffres, PNJ pillables, vĂ©hicules).
  • Multijoueur : le systĂšme d'inventaire est rĂ©pliquĂ© (RPC client/serveur visibles partout dans Inventory_Player, ex. Request Switch Weapon SERVER, Disarm Request SERVER). Le projet doit donc ĂȘtre pensĂ© serveur-autoritaire pour tout ce qui touche Ă  l'inventaire, aux stats et au combat.

1.2 Les grandes couches du projet

Le projet est construit par empilement de trois grands blocs de contenu, plus une couche d'outillage IA :

  1. Framework de personnage / locomotion ("Sandbox Character") — Content/Systems/Blueprints/ BasĂ© sur le sample officiel Epic "Motion Matching" (plugins Mover, MotionWarping, MotionTrajectory, Chooser, AnimationLocomotionLibrary, AnimationWarping). GĂšre le mouvement, la camĂ©ra, le Motion Matching, le traversal (vault/mantle/climb), les modes de mouvement personnalisĂ©s. Ce framework est en grande partie template/tiers : n'y toucher qu'en connaissance de cause.

  2. SystĂšme d'inventaire AGIS ("Advanced Grid Inventory System", asset marketplace) — Content/Core/Coreinventory/, Content/Systems/Inventory/, Content/UI/Inventory_UI/, Content/Data/Inventory_Data/. C'est le cƓur du gameplay : inventaire en grille, Ă©quipement, craft, loot, sauvegarde. La quasi-totalitĂ© des systĂšmes de jeu ajoutĂ©s par l'Ă©quipe (stats, mort, sĂ©lection rapide d'Ă©quipement, interactables) se branchent sur ce systĂšme.

  3. SystĂšmes de jeu spĂ©cifiques au projet, ajoutĂ©s par-dessus AGIS — Content/Systems/Stats/, Content/Systems/Scent/, Content/Systems/Movable_Object/, Content/Systems/Door/, Content/PCG/, Content/Items/, Content/UI/Widgets/ (HUD, pause menu). C'est ici que la majoritĂ© des Ă©volutions de gameplay futures doivent ĂȘtre ajoutĂ©es.

  4. Outillage IA — plugins VibeUE, EditorToolset, ModelContextProtocol, Terminal (dĂ©clarĂ©s dans ProjectFv1.uproject) + .mcp.json Ă  la racine. Ils exposent l'Ă©diteur Unreal (Blueprints, Widgets, Input, PCG, Landscape, Niagara, etc.) Ă  un serveur MCP local (http://127.0.0.1:8000/mcp) pilotĂ© par des agents Claude. C'est le mĂ©canisme par lequel un modĂšle d'IA lit/modifie ce projet — voir la section 9. Notes pour les IA pour les piĂšges connus.

En plus de cela, deux couches d'assets tiers volumineuses sont présentes mais ne contiennent pas de logique de gameplay propre au projet : le pack météo UltraDynamicSky (Content/Systems/Weather/UltraDynamicSky/) et diverses bibliothÚques d'assets 3D Fab/Megascans/Quixel (Content/Fab/, Content/Megaplant_Library/, une bonne partie de Content/Animations/ et Content/Characters/).

1.3 Dépendances principales entre systÚmes

Character (Pawn, géré par le framework "Sandbox Character")
 │
 ├─ Composant Inventory_Player          (Content/Core/Coreinventory/Inventory_Player)
 │   └─ hĂ©rite de Inventory_Equipper    (Ă©quipement d'armes/objets)
 │       └─ hĂ©rite de Inventory__Main   (cƓur gĂ©nĂ©rique AGIS : slots, containers, rĂ©seau)
 │
 │   ⚠ Pour un item (`_BP_ItemBase` et enfants) qui a besoin de chercher/consommer un item dans
 │   l'inventaire de son porteur (ex. l'arc qui cherche des flĂšches), utiliser sa propriĂ©tĂ© hĂ©ritĂ©e
 │   `Owner Inventory` (fonction `Variables|Runtime|GetOwnerInventory`, self implicite) plutît que de
 │   reconstruire `GetOwnerCharacter → Cast SandboxCharacter_CMC → GetInventoryPlayer → GetListeningInventory` :
 │   cette derniĂšre chaĂźne se rĂ©sout Ă  `None` tant que le joueur n'a pas ouvert son Ă©cran d'inventaire au
 │   moins une fois (`Listening Inventory` est un Ă©tat d'UI, pas l'inventaire persistant). `Owner Inventory`
 │   est typĂ©e `Inventory_Equipper` mais accepte directement les pins `Inventory__Main` (ex. `BOTH|FindItem`)
 │   grĂące Ă  cette hiĂ©rarchie d'hĂ©ritage — aucun cast nĂ©cessaire. DĂ©couvert et corrigĂ© dans
 │   `BP_Item_Bow::CountArrows/ConsumeArrow` (voir §7).
 │
 │   Inventory_Player pilote/possùde :
 │   ├─ WB_InventoryScreen (UI d'inventaire complĂšte, créée Ă  la demande)
 │   │   └─ WB_InventoryPart1 / WB_InventoryPart2
 │   │       └─ WB_EquipSlot → WB_Container → WB_InventorySlot → WB_Item
 │   ├─ WB_QuickSelect (roue de sĂ©lection rapide d'Ă©quipement, 4 slots)
 │   └─ Les Input Actions IA_*AGIS via l'IMC_AGIS_Character / IMC_AGIS_InventoryTab
 │
 ├─ Composant AC_Stats                  (Content/Systems/Stats/AC_Stats)
 │   └─ Vie, mort (OnDeath), Revive → dĂ©clenche WB_YouDied et le respawn du Character.
 │       TakeDamage(BodyPart, DMGValue) est le point d'entrĂ©e UNIQUE de toute cause de mort :
 │       utilisĂ© Ă  la fois par la mort par chute et par la touche de debug K (SandboxCharacter_CMC/EventGraph).
 │
 ├─ Armes (Content/Systems/Weapons/, voir §4.3)
 │   └─ AC_Weapon, ActorComponent ajoutĂ© Ă  chaque Blueprint d'arme (BP_Item_Bow, BP_Item_AdvancedRifle) :
 │       s'auto-abonne (EventBeginPlay, cast Owner → BP_Item_HoldableBase) au dispatcher
 │       `BP_Item_HoldableBase::OnHeldStateChanged(bIsHeld)` — PAS à `_BP_ItemBase::OnOwnerChanged`
 │       (2026-09 : bug corrigĂ© — OnOwnerChanged se dĂ©clenche pour TOUT changement de propriĂ©taire,
 │       y compris le simple ramassage/rangement dans un slot d'inventaire non tenu en main, ce qui
 │       causait "2 armes Ă©quipĂ©es en mĂȘme temps" dĂšs que 2 armes Ă©taient prĂ©sentes dans l'inventaire.
 │       OnHeldStateChanged ne se dĂ©clenche que sur le VRAI changement d'Ă©tat main/pas-en-main, via
 │       `BPI_HoldableItem::On Item Attached(ShouldHold)` dĂ©jĂ  implĂ©mentĂ© par BP_Item_HoldableBase).
 │       HandleHeldStateChanged(bIsHeld) → Equip(Owner)/Unequip() selon bIsHeld, qui pilotent `bIsEquipped`.
 │       Expose CanUse()/TryUsePrimary()/StopPrimary() (cooldown gĂ©nĂ©rique) que chaque item interroge dans ses
 │       overrides `Custom|PrimaryUse`/`StopPrimaryUsing` existants (voir §7). BFL_WeaponDamage::ApplyPointDamage
 │       route les dĂ©gĂąts d'un projectile vers `AC_Stats::TakeDamage` (mapping nom d'os → E_BodyPart).
 │       **SĂ©lection d'animation (2026-09-06)** : `Equip`/`Unequip` pilotent aussi `SandboxCharacter_CMC::Weapon`
 │       (enum `Weapon_Equip` : None/Bow/OneArmPistol/TwoArmPistol/Riffle/Bat — lu par la Pose Search Database
 │       `CHT_PoseSearchDatabases_Dense` pour sĂ©lectionner le pool d'animations armĂ©es/dĂ©sarmĂ©es de Motion
 │       Matching) et `isArmed` (bool) — ces deux variables existaient dĂ©jĂ  sur le personnage mais n'Ă©taient
 │       JAMAIS renseignĂ©es avant ce fix (dette du template de base), donc la locomotion restait toujours
 │       "à mains nues" quelle que soit l'arme tenue. `AC_Weapon` porte une variable `WeaponTypeByte` (byte,
 │       PAS l'enum directement — UserDefinedEnum non utilisable comme type de variable membre via les outils,
 │       voir §9) configurĂ©e par arme sur le composant (1=Bow sur `BP_Item_Bow`, 4=Riffle sur
 │       `BP_Item_AdvancedRifle`), convertie via `Utilities|Enum|BytetoEnumWeapon_Equip` avant d'ĂȘtre assignĂ©e.
 │       **Support du personnage Mover (2026-09-19)** : `Equip`/`Unequip` ne faisaient qu'un `Cast To
 │       SandboxCharacter_CMC`. Sur `SandboxCharacter_Mover` (parent `Pawn`, aucune classe commune avec le CMC)
 │       le cast Ă©chouait silencieusement → `Weapon`/`isArmed` jamais Ă©crits, donc arme en main mais locomotion
 │       toujours dĂ©sarmĂ©e. Les deux fonctions ont dĂ©sormais une branche `Cast Failed` → `Cast To
 │       SandboxCharacter_Mover` → `SetEquippedWeapon(WeaponTypeByte)` (nouvelle fonction du pion Mover, voir §4.2.3).
 │       **Bras armĂ© qui reste bloquĂ© en pose par dĂ©faut Ă  l'Ă©quipement (2026-09-06, CORRIGÉ)** : deux causes
 │       distinctes cumulĂ©es, toutes deux dans `SandboxCharacter_CMC_ABP` :
 │       (1) `Get_MMInterruptMode` (utilisĂ©e par `Update_MotionMatching` pour choisir le `PoseSearchInterruptMode`
 │       passĂ© Ă  `MotionMatchingAnimNodeLibrary.SetDatabasesToSearch`) ne testait QUE MovementMode/MovementState/
 │       Gait — jamais `Weapon_Equip` (variable ABP, distincte de `SandboxCharacter_CMC::Weapon`, alimentĂ©e depuis
 │       celle-ci via PropertyAccess dans `Update_States`, qui a bien SON PROPRE tracker `Weapon_Equip Last Frame`
 │       dĂ©jĂ  prĂ©sent mais jamais branchĂ©). RĂ©sultat : passer armĂ©/dĂ©sarmĂ© EN RESTANT IMMOBILE ne changeait ni
 │       MovementMode/State/Gait, donc `Get_MMInterruptMode` retournait toujours `DoNotInterrupt` et Motion
 │       Matching continuait indĂ©finiment l'ancienne pose (`bIsContinuingPoseSearch=True`) sans jamais essayer
 │       la nouvelle base de donnĂ©es pourtant correctement sĂ©lectionnĂ©e dans `ValidDatabases`/`DatabasesToSearch`.
 │       Fix : condition supplĂ©mentaire `Weapon_Equip != Weapon_Equip Last Frame` ajoutĂ©e au `OR` racine de
 │       `Get_MMInterruptMode` (3ᔉ pin ajoutĂ©e au nƓud `ORBoolean` existant via `add_node_pin`, PAS une réécriture
 │       DSL complĂšte — voir §9 pour le piĂšge du wildcard enum). (2) Une fois l'interruption forcĂ©e, la recherche
 │       Ă©chouait quand mĂȘme : `PSD_Dense_Stand_Bow_Idles`/`_Bow_Aim_Idles`/`PSD_Walk_Bow`/`PSD_Crouch_Bow`
 │       (toutes sous `/Game/Animations/humain/Armed_mov/Bow/`) avaient leur `PoseSearchMode` sur `PCAKD_TREE`
 │       et leur build d'index Ă©chouait dĂšs le chargement (`LogPoseSearch: Error: ... BuildIndex Failed because
 │       of 'No Convergence' while calculating PCA data`) — passĂ©es en `BRUTE_FORCE` (pas besoin de PCA, dataset
 │       de toute façon minuscule), ce qui a dĂ©bloquĂ© la recherche. (3) **Lignes armĂ©es manquantes dans le
 │       chooser (CORRIGÉ 2026-09-06)** : la colonne `Is Armed` de `CHT_PoseSearchDatabases_Dense` (seule des 4
 │       tables LOD à en avoir une) n'avait que DEUX lignes `MatchTrue` — "Stand Idles Bow" (ligne 1) et "Stand
 │       Walks Armed" (ligne 3). Toutes les autres (courses 4-5, sprint 6, InAir 7, accroupi 8-9, prone 10-11,
 │       nage 12-17) exigeaient `MatchFalse`, donc AUCUNE ligne ne correspondait dùs qu'on courait/sautait/
 │       s'accroupissait armĂ© → chooser vide → Motion Matching gardait la derniĂšre pose (symptĂŽme : "mĂȘme
 │       animation en marchant, courant et accroupi"). Fix : ces lignes passĂ©es de `MatchFalse` Ă  `MatchAny`
 │       (repli propre sur l'animation non-armĂ©e au lieu du gel ; les lignes 0 et 2 DOIVENT rester `MatchFalse`
 │       sinon elles masqueraient les lignes arc 1 et 3, l'Ă©valuation Ă©tant descendante premier-match-gagne).
 │       Aucun sous-chooser concernĂ© n'a de colonne d'arme, le repli est donc sans effet de bord.
 │       ⚠ **RÉGRESSION 2026-09-13 (voir §8.2)** : `CHT_PoseSearchDatabases_Dense` a Ă©tĂ© ÉCRASÉ par la migration depuis
 │       `Project_F` — les lignes armĂ©es Bow (`PSD_Dense_Stand_Bow_Idles`, `_Bow_Aim_Idles`, `PSD_Walk_Bow`) et le passage
 │       `MatchFalse`→`MatchAny` dĂ©crits ci-dessus avaient disparu. **RESTAURÉ le 2026-09-14** : la version du commit `d29748b`
 │       a Ă©tĂ© remise (lignes Bow, Prone, nage, cover accroupi et Push revenues, contexte `Systems/Blueprints/SandboxCharacter_CMC_ABP`)
 │       puis le fix MatchAny a Ă©tĂ© refait par script : colonne `Is Armed` : lignes 0 et 2 en `MatchFalse`, 1 et 3 en `MatchTrue`, lignes 4 Ă  17 passĂ©es de `MatchFalse` Ă  `MatchAny` (la ligne 18 l'Ă©tait dĂ©jĂ ), vĂ©rifiĂ© aprĂšs rechargement.
 │       **Reste un problĂšme de contenu NON corrigĂ©** (voir §9) : `PSD_Dense_Stand_Bow_Idles` — et ELLE SEULE
 │       (`_Bow_Aim_Idles`/`PSD_Walk_Bow`/`PSD_Crouch_Bow` sont sains) — a ses 4 entrĂ©es
 │       `DatabaseAnimationAssets[i].SamplingRange` rĂ©glĂ©es sur `(longueur_du_clip, longueur_du_clip)`, une
 │       fenĂȘtre de largeur nulle placĂ©e Ă  la toute FIN du clip. Or Pose Search ne traite un asset comme
 │       bouclable que si sa plage vaut `(0,0)` (= « tout le clip ») : d'oĂč `bLoopAnimation=False` + fenĂȘtre de
 │       lecture nulle = une seule frame figĂ©e, alors mĂȘme que les AnimSequences sources sont bien `Loop=True`.
 │       Correction = remettre chaque `Sampling Range` Ă  `0 / 0` dans l'Ă©diteur Pose Search Database — Ă  faire Ă 
 │       la main : la propriĂ©tĂ© n'est exposĂ©e par AUCUNE API (absente de `ObjectTools.list_properties`, refusĂ©e
 │       par `get/set_editor_property` ET `ObjectTools`, et le `SET` console ne cible qu'une classe entiùre donc
 │       toutes les databases chargĂ©es). C'est aussi ce dataset dĂ©gĂ©nĂ©rĂ© (4 poses uniques) qui faisait Ă©chouer
 │       le PCA du point (2).
 │       `PSD_Crouch_Bow` existe mais n'est rĂ©fĂ©rencĂ©e par AUCUN chooser (contenu orphelin) : une fois les
 │       SamplingRange corrigĂ©es, on pourra lui dĂ©dier une vraie ligne armĂ©e accroupie plutĂŽt que le repli.
 │
 ├─ Composants de mouvement            (Content/Systems/Movement/, Systems/Blueprints/MovementModes/)
 │   └─ AC_ClimbingComponent, AC_Cover, AC_TraversalLogic, AC_PreCMCTick, AC_VisualOverrideManager

 │
 ├─ Composant AIPerceptionStimuliSourceComponent (2026-09-05)
 │   └─ AjoutĂ© sur SandboxCharacter_CMC pour que le joueur soit dĂ©tectable par la vue de l'IA
 │       (AISense_Sight, auto_register_as_source=true). Sans lui, AUCUN AIPerceptionComponent
 │       ne peut jamais dĂ©tecter le joueur, quels que soient rayon/FOV/LOS configurĂ©s cĂŽtĂ© IA.
 │
 └─ Autres composants gameplay         (BP_ScentPoint, etc. — voir Systems/Scent/ §4.3 et Systems/Wildlife/ §4.4)

Interactables (Content/Systems/Inventory/Interactables/*)
 └─ ImplĂ©mentent BPI_Interactable, exposent un inventaire via un composant
    Inventory_Storage / Inventory_Vendor / Inventory_Crafting (mĂȘmes bases AGIS que le joueur)
    → consultĂ©s par Inventory_Player lors d'une interaction (touche IA_InteractAGIS)

Données d'items (Content/Data/Inventory_Data/, Content/Items/)
 └─ DT_Items (DataTable), ItemDefaults / ItemInfo (structs), DD_Item (DataAsset par item)
    alimentent Ă  la fois l'UI d'inventaire ET les Blueprints d'objets sous Content/Items/BP_Item_*

Faune sauvage (Content/Systems/Wildlife/, voir §4.4)
 └─ BP_AnimalBase (Character) rĂ©utilise TEL QUEL AC_Stats (vie/dĂ©gĂąts/mort, §1.3 ci-dessus) et
    BP_ScentPoint (Systems/Scent/, §4.3) — aucun systĂšme de vie ni d'odeur parallĂšle n'a Ă©tĂ© créé.
    BFL_WeaponDamage::ApplyPointDamage fonctionne automatiquement sur un animal (résout AC_Stats
    par GetComponentByClass) : aucune adaptation nécessaire cÎté systÚme d'armes.

1.4 Conventions de nommage des assets

Préfixe Signification Exemple
BP_ Blueprint d'acteur BP_Campfire, BP_Item_Helmet
WB_ / WBP_ Widget Blueprint (UMG) WB_InventoryScreen, WBP_PauseMenu
AC_ ActorComponent AC_Stats, AC_ClimbingComponent
IA_ Input Action (Enhanced Input) IA_InteractAGIS, IA_QuickSelectAGIS
IMC_ Input Mapping Context IMC_AGIS_Character
E_ / EM_ Enum E_MovementMode, EM_Road_Type
S_ / ST_ Struct S_TraversalCheckInputs, ST_Weather_Zone_forecasts
M_ Material M_Road, M_Campfire
MI_ Material Instance MI_Black, MI_Bottle
SM_ Static Mesh SM_Campfire, SM_RifleAdvanced
SKM_ Skeletal Mesh SKM_BodyArmor
PA_ Physics Asset PA_BodyArmor
T_ Texture T_Helmet
RT_ Render Target RT_InspectRenderer
DT_ Data Table DT_Items
DD_ Data Definition (DataAsset) DD_Item
ML_ Macro Library (Blueprint) ML_InventoryMacros
SG_ SaveGame SG_AGIS_UID, SG_AGIS_World
GM_ / PC_ GameMode / PlayerController GM_Sandbox, PC_Sandbox
CR_ Control Rig CR_ClimbingGraphV2
ABP_ Animation Blueprint ABP_GenericRetarget
AM_ Anim Modifier / Anim Montage AM_ReloadHip
NS_ Niagara System NS_Tornado
BPI_ Blueprint Interface BPI_Interactable

Le suffixe AGIS sur beaucoup d'assets (IA_InteractAGIS, WB_...AGIS, fonctions "Target is Inventory Player") signale qu'ils appartiennent au socle marketplace AGIS, par opposition aux ajouts spécifiques au projet.

1.5 Conventions importantes Ă  respecter

  • Ne jamais renommer/dĂ©placer les assets du socle AGIS (Content/Core/Coreinventory/, une bonne partie de Content/Systems/Inventory/, Content/UI/Inventory_UI/Widgets/WB_Container|WB_EquipSlot|WB_InventorySlot|WB_Item) sans nĂ©cessitĂ© — de nombreuses rĂ©fĂ©rences internes au plugin marketplace en dĂ©pendent.
  • Nouveau systĂšme de gameplay → crĂ©er un dossier dĂ©diĂ© sous Content/Systems/<NomDuSysteme>/, Ă  l'image de Systems/Stats/, Systems/Scent/, Systems/Movable_Object/.
  • Nouvel objet d'inventaire (item) → suivre le patron existant dans Content/Items/ : un Blueprint BP_Item_<Nom> (hĂ©ritant de _BP_ItemBase ou d'une base spĂ©cialisĂ©e dans Items/BaseBlueprints/), ses assets (mesh/matĂ©riau/texture) dans un sous-dossier Content/Items/<Nom>/ ou Content/Items/Resources/<Nom>/, et une entrĂ©e dans DT_Items / les DataAssets sous Content/Data/Inventory_Data/DataAssets/.
  • Nouvel Input Action liĂ© Ă  l'inventaire → Content/Systems/Inventory/Other/Inputs/Actions/, mappĂ© dans IMC_AGIS_Character ou IMC_AGIS_InventoryTab. Input Action de dĂ©placement/camĂ©ra gĂ©nĂ©rique → Content/Core/PlayerController/Input/, mappĂ© dans IMC_Sandbox.
  • Nouveau widget d'inventaire → Content/UI/Inventory_UI/Widgets/. Nouveau widget hors inventaire (HUD, menus) → Content/UI/Widgets/.
  • Le clavier cible est AZERTY ; privilĂ©gier des touches identiques physiquement sur QWERTY/AZERTY pour les nouveaux raccourcis (ex. V, B).
  • RĂ©plication rĂ©seau : toute action qui modifie l'Ă©tat du jeu cĂŽtĂ© inventaire/stats doit suivre le patron Request X SERVER (Custom Event ...SERVER, Replicated From Client, Executes On Server) dĂ©jĂ  prĂ©sent dans Inventory_Player.

2. Vue d'ensemble de l'arborescence racine

ProjectF/
├── .gitattributes              → Rùgles Git (LFS, line-endings)
├── .gitignore                  → Exclut Binaries/, Intermediate/, Saved/, DerivedDataCache/, .vscode/

├── .mcp.json                   → DĂ©clare le serveur MCP "unreal-mcp" (http://127.0.0.1:8000/mcp) utilisĂ© par les agents IA
├── ProjectFv1.uproject           → Fichier projet UE5.8 : liste des plugins activĂ©s (voir §1.2/§8)
├── README.md                   → Description minimale du projet
├── Architecture_Projet.md      → CE DOCUMENT
│
├── .claude/                    → Skills et configuration Claude Code pour ce projet
│   └── skills/
│       └── maintain-architecture-doc/SKILL.md   → Skill de maintenance de ce document (voir §10)
│
├── .codex/, .cursor/, .gemini/, .vscode/   → Configuration d'IDE / d'agents IA tiers (mcp.json, config.toml
)
│
├── Config/                     → Configuration moteur & jeu (voir dĂ©tail §7)
├── Content/                    → Tous les assets du jeu (voir dĂ©tail §3 Ă  §6)
│
├── Binaries/, Intermediate/, Saved/, DerivedDataCache/   → GĂ©nĂ©rĂ©s par l'Ă©diteur, exclus de Git, jamais Ă  Ă©diter/documenter

2.1 ⚠ Fichiers centraux autrefois isolĂ©s Ă  la racine de Content/ (rangĂ©s le 2026-09-13)

Quelques fichiers importants vivent directement sous Content/, hors de toute organisation par dossier — Ă  connaĂźtre avant de chercher "oĂč est le personnage" ou "oĂč est le GameInstance" :

Content/
├── Core/Character/SandboxCharacter_CMC.uasset   → (dĂ©placĂ© depuis la racine le 2026-09-13) ⭐ Le Blueprint du PERSONNAGE JOUEUR lui-mĂȘme (Character/Pawn). RĂ©fĂ©rencĂ© par GM_Dev, GM_Sandbox, PC_Sandbox, Gamemode_AGIS, WB_InventoryScreen, WBP_PauseMenu, BP_Moveble_Object, BP_Simply_Door, AC_PreCMCTick, AC_ClimbingComponent et son propre Anim BP (Systems/Blueprints/SandboxCharacter_CMC_ABP). C'est le point d'entrĂ©e central de tout le gameplay. Son EventGraph contient aussi : la dĂ©tection de mort par chute (suivi tick de `IsFalling`/`FallStartZ`, calcul de hauteur Ă  `OnLanded`, dĂ©gĂąts scalĂ©s via `AC_Stats.TakeDamage` au-delĂ  de 300 unitĂ©s, lĂ©tal au-delĂ  de 800) et une touche de debug K (InputDebugKey) qui force la mort via ce mĂȘme `TakeDamage` — ajoutĂ©s le 2026-09-04.
├── Core/Character/SandboxCharacter_Mover.uasset + _Mover_Ragdoll.uasset   → Personnage alternatif basĂ© sur le plugin **Mover** (pion par dĂ©faut de `GM_Dev` ; en PIE c'est la variante `_Ragdoll` qui est possĂ©dĂ©e). DĂ©crits avec le reste du framework Mover en §4.2.1, et leurs systĂšmes cover/prone/nage en §4.2.2.
├── Core/BP_GameInstance.uasset   → (dĂ©placĂ© depuis la racine le 2026-09-13 ; `Config/DefaultEngine.ini` → `GameInstanceClass=/Game/Core/BP_GameInstance.BP_GameInstance_C`) GameInstance rĂ©ellement utilisĂ© par le projet (Ă  ne pas confondre avec `Core/Coreinventory/GameInstance_AGIS`, la base du plugin — vĂ©rifier lequel des deux est configurĂ© comme GameInstance par dĂ©faut avant de supposer que c'est l'un ou l'autre).
└── Data/DT_DemoTags.uasset   → (dĂ©placĂ© depuis la racine le 2026-09-13 ; l'export texte `DT_DemoTags.T3D` a Ă©tĂ© supprimĂ©) ⚠ **À NE PAS SUPPRIMER** : DataTable de gameplay tags du socle AGIS, dĂ©clarĂ©e dans `Config/DefaultGameplayTags.ini` (`+GameplayTagTableList=/Game/Data/DT_DemoTags`). Elle dĂ©finit `General Inventory Slot` (indispensable Ă  l'inventaire), `Human.*`, `Attachment.*` (singulier), `Flashlight.Battery`, `Other.*`, `Vehicle.*`. (CorrigĂ© le 2026-09-13 : l'ancienne mention « aucune rĂ©fĂ©rence trouvĂ©e » Ă©tait fausse — la rĂ©fĂ©rence passe par la config, invisible pour l'Asset Registry.) Dette connue : `DT_Items`, `Inventory_Player` et `AttachmentData_AdvancedRifle` utilisent `Attachments.*` (pluriel, tags inexistants → avertissements « Invalid GameplayTag »), antĂ©rieur au commit du 2026-09-04.

3. Content/Core/ — Socle inventaire (AGIS) + Player Controller + Tick

Le cƓur technique de l'inventaire et des entrĂ©es gĂ©nĂ©riques du joueur.

Content/Core/
├── Coreinventory/                        → CƓur du plugin AGIS (composants, donnĂ©es, sauvegarde)
│   ├── Inventory__Main.uasset            → ActorComponent BASE : logique gĂ©nĂ©rique de containers/slots, rĂ©plication rĂ©seau. Racine de la hiĂ©rarchie d'inventaire.
│   ├── Inventory_Equipper.uasset         → hĂ©rite de Inventory__Main : ajoute la logique d'Ă©quipement (armes/objets tenus en main)
│   ├── Inventory_Player.uasset           → hĂ©rite de Inventory_Equipper : composant d'inventaire du JOUEUR. Contient toute la logique spĂ©cifique projet ajoutĂ©e cette session (SelectQuickSlot, ToggleQuickEquip, GetQuickSlotItemInfo, graphe INPUTS avec tous les bindings Enhanced Input du joueur). (2026-09-05) `ToggleQuickEquip`/`GetQuickSlotItemInfo` (touches V/B) Ă©taient des stubs de prototype (PrintString uniquement, aucun appel d'Ă©quipement rĂ©el, plus un bool `bQuickSlotArmed` inversĂ©) — corrigĂ©s pour appeler rĂ©ellement `Inventory_Equipper::SwitchWeaponByUID`/`EmptyHands` (hĂ©ritĂ©s). `GetQuickSlotItemInfo` retourne dĂ©sormais aussi le `ContainerUID` du slot (WEAPON/WEAPON2/Speed1/Speed2) via `WBContainer::GetContainerUID`, nĂ©cessaire pour cibler `SwitchWeaponByUID`. B Ă©quipe/dĂ©sĂ©quipe donc rĂ©ellement l'item du slot prĂ©sĂ©lectionnĂ© par V (le slot doit dĂ©jĂ  contenir un item via le drag&drop du paperdoll — la roue V/B ne fait que choisir PARMI les 4 emplacements dĂ©jĂ  Ă©quipĂ©s, elle ne pioche pas dans l'inventaire gĂ©nĂ©ral). Nouvelle fonction `CycleQuickSlot()` (Weapon→Weapon2→Speed1→Speed2→Weapon→
) ajoutĂ©e pour fiabiliser la sĂ©lection : `WB_QuickSelect::EventConstruct` (Content/UI/Inventory_UI/Widgets/Other/WB_QuickSelect.uasset) l'appelle dĂ©sormais automatiquement Ă  chaque pression de V (donc Ă  chaque crĂ©ation de la roue), sans dĂ©pendre du clic sur un bouton de la roue (`BtnWeapon1` etc. — dont le fonctionnement en jeu n'a pas pu ĂȘtre confirmĂ©). Les boutons de la roue restent cĂąblĂ©s Ă  `SelectQuickSlot` en plus, au cas oĂč le clic fonctionne rĂ©ellement.
│   ├── Inventory_Storage.uasset          → Inventaire des containers de stockage (coffres, trunk, etc.)
│   ├── Inventory_Vendor.uasset           → Inventaire des PNJ vendeurs
│   ├── Inventory_Crafting.uasset         → Inventaire des stations de craft (campfire, smelter, gĂ©nĂ©rateur)
│   ├── BP_AttachmentHandler.uasset       → ActorComponent gĂ©rant les attachements sur les armes (silencieux, lampe, chargeur
)
│   ├── CombatComponent.uasset            → ActorComponent : logique de combat (tir, dĂ©gĂąts) liĂ©e aux armes AGIS
│   ├── BP_SM_DroppedMesh.uasset          → Acteur reprĂ©sentant un objet lĂąchĂ© au sol (mesh statique + interaction de ramassage)
│   ├── ItemMesh_STATIC.uasset / ItemMesh_Skeletal.uasset  → Acteurs gĂ©nĂ©rant le rendu 3D d'un item tenu/lĂąchĂ© (mesh statique ou squelettal)
│   ├── DD_Item.uasset                    → DataAsset dĂ©crivant un item (rĂ©fĂ©rencĂ© par ItemDefaults)
│   ├── FL_AGIS.uasset                    → Function Library : fonctions statiques utilitaires du plugin AGIS
│   ├── ML_AGISDefaults.uasset            → Macro Library : macros par dĂ©faut du plugin
│   ├── ML_AGIS_UMG.uasset                → Macro Library : macros dĂ©diĂ©es Ă  l'UI (UMG)
│   ├── ML_InventoryMacros.uasset         → Macro Library : macros gĂ©nĂ©riques d'inventaire
│   ├── GameInstance_AGIS.uasset          → GameInstance de base du plugin (Ă©tat persistant entre les maps)
│   ├── Gamemode_AGIS.uasset              → GameMode de base du plugin (indĂ©pendant de GM_Sandbox, voir §4)
│   ├── PlayerController_AGIS.uasset      → PlayerController de base du plugin
│   └── SG_AGIS_UID.uasset / SG_AGIS_World.uasset  → SaveGame : compteur d'UID uniques / Ă©tat persistant du monde (sauvegarde)
│
├── PlayerController/                     → Input gĂ©nĂ©rique du joueur (mouvement, camĂ©ra), indĂ©pendant de l'inventaire
│   ├── IA_InitiateClimb / IA_LeapFromClimb / IA_MovingClimb.uasset   → Input Actions liĂ©es Ă  l'escalade
│   └── Input/
│       ├── IMC_Sandbox.uasset            → Input Mapping Context PRINCIPAL, ajoutĂ© dans `SetupInput` par `SandboxCharacter_CMC` ET (depuis le 2026-09-15) par `SandboxCharacter_Mover` (mouvement, camĂ©ra, saut, + actions AGIS : `IA_ToggleInventory` Tab, `IA_InteractAGIS`, `IA_QuickEquip/Select/GiveAGIS`, `IA_UseItemPrimary/SecondaryAGIS`). Mappings `IA_TriggerRagdoll` (R, X manette) et `IA_Takedown` (clic gauche, RT) ajoutĂ©s le 2026-09-15 pour le Mover ragdoll
│       └── IA_Move, IA_Look, IA_Jump, IA_Sprint, IA_Run, IA_Walk, IA_Crouch, IA_Prone, IA_Strafe,
│           IA_Aim, IA_Interact, IA_ESC, IA_NextPawn, IA_Traverse, IA_TeleportToTarget,
│           IA_SwimmingDeep, IA_TwinStick_AimDirection, IA_Move_WorldSpace, IA_Look_Gamepad,
│           IA_NextVisualOverride, IA_Takedown, IA_TriggerRagdoll, IA_rool.uasset   → Input Actions individuelles mappĂ©es dans IMC_Sandbox. Aussi Ă©coutĂ©es par la chaĂźne Mover (`SandboxCharacter_Mover`/`_Ragdoll`, `Systems/Mover/PC_Sandbox`, `Systems/Mover/SmartObjects/AC_SmartObjectAnimation`) ; le sprint du Mover Ă©coute `IA_Run` (Started/Completed). `IA_rool` et `IA_Traverse` ne sont Ă©coutĂ©s par aucun Blueprint
│
└── Tick/                                 → SystĂšme de gestion centralisĂ©e du Tick (perf)
    ├── BPI_TickManager.uasset            → Interface implĂ©mentĂ©e par les acteurs qui veulent ĂȘtre "tickĂ©s" par le manager
    ├── BP_TickManager.uasset             → Acteur central qui distribue les ticks (probablement Ă  frĂ©quence configurable)
    └── E_TickFrequency.uasset            → Enum des frĂ©quences de tick disponibles

4. Content/Systems/ — Systùmes de gameplay

4.1 Systems/Inventory/ — Extension du socle AGIS pour ce projet

Content/Systems/Inventory/
├── BP_Spawner.uasset                     → Acteur de spawn (probablement spawn d'items/loot en dĂ©but de partie)
├── DT_Items.uasset                       → DataTable listant tous les items du jeu (clĂ© pour crĂ©er/reconnaĂźtre un item)
│
├── Interactables/                        → Tout ce que le joueur peut "interagir" avec (touche IA_InteractAGIS)
│   ├── BP_EnemyPuppet.uasset             → PNJ/mannequin pillable
│   ├── BP_Vendor.uasset                  → PNJ vendeur (utilise Inventory_Vendor)
│   ├── CraftingInteractables/
│   │   ├── Campfire/BP_Campfire.uasset   → Station de cuisson/craft (feu de camp) + ses assets (mesh, matĂ©riaux)
│   │   └── Smelter/BP_Smelter.uasset     → Station de fonte de minerai + ses assets
│   ├── FuelGenerator/BP_Generator.uasset → GĂ©nĂ©rateur Ă©lectrique (consomme du carburant)
│   ├── KeycardReader/BP_KeycardReader.uasset → Lecteur de carte magnĂ©tique (dĂ©verrouillage)
│   ├── Other/BP_SimpleDoor.uasset        → Porte interactable simple
│   └── Storages/
│       ├── BP_StorageBox.uasset, BP_Trunk.uasset, BP_SphereStorage.uasset, _BP_StorageBase.uasset  → Coffres/contenants de stockage (hĂ©ritent de _BP_StorageBase)
│       └── Deadbody/BP_Deadman.uasset    → Cadavre pillable
│
├── Interfaces/                           → Interfaces Blueprint (contrats partagĂ©s)
│   ├── BPI_Interactable.uasset           → Contrat pour tout objet interactible (implĂ©mentĂ© par tous les Interactables ci-dessus)
│   ├── BPI_SlotWidgets.uasset            → Contrat pour les widgets de slot d'inventaire
│   ├── BPI_HoldableItem.uasset           → Contrat pour un item tenable en main
│   ├── BPI_WeaponAGIS.uasset             → Contrat pour les armes
│   ├── BPI_DamageFeedback.uasset         → Contrat de retour visuel/sonore lors de dĂ©gĂąts
│   └── BPI_GameInstance_AGIS.uasset      → Contrat exposĂ© par le GameInstance cĂŽtĂ© AGIS
│
├── Other/                                → Assets d'appoint de l'inventaire
│   ├── Animations/                       → Animations liĂ©es aux armes/mains nues (Jog, Rifle, TurnInPlace, WALK) — clips Motion Matching (MM_*) et montages (AM_*)
│   ├── Fonts/                            → Polices utilisĂ©es par l'UI d'inventaire
│   ├── Inputs/
│   │   ├── Actions/                      → **Toutes** les Input Actions liĂ©es Ă  l'inventaire (IA_*AGIS), y compris IA_QuickSelectAGIS et IA_QuickEquipAGIS (sĂ©lection rapide, ajoutĂ©es pour ce projet)
│   │   ├── IMC_AGIS_Character.uasset     → Mapping Context actif en jeu (personnage) : touches 1/2/3/4, F, V, B, etc.
│   │   └── IMC_AGIS_InventoryTab.uasset  → Mapping Context actif quand l'inventaire plein Ă©cran est ouvert
│   ├── InspectCapture/                   → Rendu d'inspection d'objet (RT_InspectRenderer + BP_InspectRenderer + M_Inspect)
│   └── Materials/                        → MatĂ©riaux gĂ©nĂ©riques rĂ©utilisĂ©s par les items (MI_Black, MI_Red, M_Metal, M_Outline
)
│
└── Utilities/                            → Outils d'Ă©diteur (Editor Utility Widgets) pour la crĂ©ation de containers/inventaires
    ├── EUW_ContainersCreator.uasset, EUW_WidgetToInventoryData.uasset
    └── Others/WB_ContainerSpecsUtility.uasset, WB_CreatorContainerUtility.uasset

4.2 Systems/Blueprints/ — Framework de personnage / locomotion ("Sandbox Character")

Contenu trĂšs largement issu du sample Epic Motion Matching (plugins Mover, MotionTrajectory, Chooser, AnimationLocomotionLibrary). À traiter comme un framework tiers : prĂ©fĂ©rer l'Ă©tendre plutĂŽt que le réécrire.

Content/Systems/Blueprints/
├── BPI_SandboxCharacter_Pawn.uasset      → Interface du Pawn joueur (point d'entrĂ©e du framework de locomotion). (2026-09-14) + fonctions du sample GASP pour le Mover : `AddTarget`, `RemoveTarget`, `Set_IsPlayingRootMotion`, `Set_PhysicsProfile`, sorties typĂ©es de `Get_MMIResult` / `Get_PropertiesForRagdoll`
├── BPI_SandboxCharacter_ABP.uasset       → Interface de l'Anim Blueprint du personnage. (2026-09-14) + `Get_Trajectory`, `Update_MMIConstraints`
├── AC_TraversalLogic.uasset              → ActorComponent : logique de traversal (vault/mantle/climb contextuel)
├── AC_PreCMCTick.uasset                  → ActorComponent : logique exĂ©cutĂ©e avant le tick du mouvement (Mover/CMC)
├── AC_VisualOverrideManager.uasset       → ActorComponent : gestion des overrides visuels du personnage
├── GM_Sandbox.uasset / PC_Sandbox.uasset → GameMode / PlayerController du framework de locomotion (indĂ©pendants de Gamemode_AGIS/PlayerController_AGIS, voir §3)
│
├── Cameras/                              → SystĂšme de camĂ©ra (Camera Rigs modulaires)
│   ├── CameraAsset_SandboxCharacter, CameraDirector_SandboxCharacter, CHT_CameraRig
│   ├── E_CameraMode.uasset, E_CameraStyle.uasset
│   └── Rigs/CameraRig_* (Close/Medium/Far × Aim/Freecam/Strafe, CrouchOffset, CollisionOffset, TwinStick
)
│
├── MovementModes/                        → Modes de mouvement personnalisĂ©s (plugin Mover)
│   ├── BP_MovementMode_Walking / _Falling / _Slide
│   ├── BP_MovementTransition_ToSlide / _FromSlide
│   └── BP_ClimbingMode.uasset
│
├── ControlRigs/CR_Biped_FootPlacement.uasset   → Control Rig : placement des pieds (foot IK)
├── RetargetedCharacters/ABP_GenericRetarget.uasset  → Anim BP gĂ©nĂ©rique pour le retargeting
│
├── AnimModifiers/                        → Anim Modifiers (post-traitement de clips d'animation à l'import)
├── AnimNotifies/                         → Anim Notifies personnalisĂ©es (BP_AnimNotify_FoleyEvent*, BP_NotifyState_EarlyTransition/MontageBlendOut) + enums associĂ©s
│
├── Data/                                 → Structs/Enums/Curves partagĂ©s par tout le framework de locomotion
│   ├── E_Gait, E_Stance, E_MovementMode, E_MovementState, E_MovementDirection(Bias), E_RotationMode,
│   │   E_AnalogStickBehavior, E_ExperimentalStateMachineState, E_TraversalActionType
│   │   (2026-09-14, convergence §8.2) valeurs du sample ajoutĂ©es EN FIN d'enum : E_MovementMode += Ragdoll, Flying ;
│   │   E_ExperimentalStateMachineState += Debug Flying Loop. S_CharacterPropertiesForAnimation += BasedMovementDelta,
│   │   Weapon_Type (`Data/Enums/E_WaponType`) ; S_BlendStackInputs += Blend Curve. Ne jamais rĂ©ordonner ces enums (valeurs stockĂ©es par nom interne).
│   ├── S_CharacterPropertiesForAnimation / _ForCamera / _ForTraversal, S_BlendStackInputs,
│   │   S_MoverCustomInputs, S_PlayerInputState, S_TraversalCheckInputs/Result,
│   │   S_TraversalChooserInputs/Outputs (contexte des choosers `CHT_TraversalMontages_CMC/_Mover`), S_ChooserOutputs
│   │   (contexte de `CHT_CMCCharacterAnimations`), S_MovementDirectionThresholds,
│   │   S_RotationOffsetCurveChooser_Inputs, S_DebugGraphLineProperties
│   ├── Curve_RotationOffset_* , Curve_StrafeSpeedMap, CHT_RotationOffsetCurve  → Curve Tables pilotant les offsets d'animation
│   └── BFL_HelpfulFunctions.uasset, BPI_InteractionTransform.uasset
│
├── SmartObjects/                         → IntĂ©gration du plugin SmartObject (points d'ancrage d'animation contextuelle)
│   ├── CHPA_SmartObject, AC_SmartObjectAnimation
│   └── SmartObjectAnimationPayload, SmartObjectSelectionInputs/Outputs
│
├── SandboxCharacter_CMC_ABP.uasset       → Anim Blueprint principal du personnage joueur (pilotĂ© par `/Game/Core/Character/SandboxCharacter_CMC`). Anciennement Ă©garĂ© dans un dossier `d/` mal nommĂ© — dĂ©placĂ© ici (nettoyage du 2026-09-04).
│
├── (SUPPRIMÉS de ce dossier) SandboxCharacter_Mover / _ABP / _Ragdoll → **Depuis le 2026-09-13 ces trois assets n'existent plus dans `Systems/Blueprints/`** : les versions actives (personnage Mover conservĂ© Ă  la demande de l'utilisateur) sont dans `Content/Systems/Mover/` (voir §4.2.1). `SandboxCharacter_CMC` (`Content/Core/Character/`) reste le personnage RÉEL du jeu. VĂ©rifiĂ© le 2026-09-14 : `GM_Dev` (GameMode de `MapDev1`), `Systems/Blueprints/GM_Sandbox` et `Core/Coreinventory/Gamemode_AGIS` ont `DefaultPawnClass = /Game/Core/Character/SandboxCharacter_CMC` ; `GM_Sandbox_Ragdoll` et `GM_MoverTest` (contenu de test du sample) restent Ă  `None` ; `Systems/Mover/GM_Sandbox` spawne `SandboxCharacter_Mover`.
│
├── GM_Sandbox_Ragdoll.uasset              → Variante de `GM_Sandbox` avec `SandboxCharacter_Mover_Ragdoll` comme pawn par dĂ©faut (contenu du sample, non utilisĂ©e par le jeu rĂ©el).
│
├── AI/StateTree/                          → **(2026-09-08)** StateTree + tĂąches pour l'interaction Smart Object du personnage (`ST_Player_SandboxCharacter_SmartObject`, `STT_CharacterIgnoreCollisionsWithOtherActor`, `STT_FindSlotTransforms`, `S_SmartObjectPayload`). Contenu du sample, AI/SmartObject non branchĂ© sur le gameplay AGIS.
│
└── (2026-09-08) Contenu supplĂ©mentaire fusionnĂ© depuis un import du sample officiel Epic **Game Animation Sample** (voir note globale en fin de §8) : `RetargetedCharacters/` (BP_Echo, BP_Manny, BP_Quinn, BP_Twinblast, BP_UE4_Mannequin — **supprimĂ©s le 2026-09-13** avec les personnages de dĂ©mo ; seul `ABP_GenericRetarget` subsiste), des `Cameras/Rigs/` et `MovementModes/` supplĂ©mentaires (`CameraRig_Far_Ragdoll`, `CameraRigPrefab_ThirdPerson`, `BP_MovementMode_Ragdoll`, `B_MovementMode_Flying`), des `Data/` supplĂ©mentaires (`S_RagdollProperties`, `S_MoverCustomInputs_Ragdoll`, `E_RagdollInjuryState`, `Ragdoll_Fall_to_Ground_BlendCurve`, variantes `S_CHT_*_IN/OUT` pour les choosers de traversal/interaction/get-up), des `AnimNotifies/` supplĂ©mentaires (`BP_NotifyState_MMI_IK`, `_MMI_MotionWarping`, `_OverrideCapsuleCollision`, `_OverrideMovementMode`, enums `E_EarlyTransition_*`/`E_FoleyEventSide`/`E_TraversalBlendOutCondition`), et des `SmartObjects/` supplĂ©mentaires (`Bench/`, `DistanceToSmartObject`, `PSS_SmartObject`, `TasksAndConditions/STT_ClaimSlot|ClearHandle|PlayAnimFromBestCost|PlayAnimMontage`).

4.2.1 Systems/Mover/ et Systems/Aiming/ — personnage Mover et framework du sample (isolĂ©s le 2026-09-14)

Copie du framework "Sandbox Character" du sample Epic Game Animation Sample, arrivĂ©e avec la migration Project_F (§8.2) et conservĂ©e pour le personnage alternatif basĂ© sur le plugin Mover et pour le systĂšme de visĂ©e. DĂ©placĂ©e SANS fusion depuis Content/Blueprints/ et Content/Input/. Beaucoup d'assets ont un homonyme dans Systems/Blueprints/ (AC_TraversalLogic, BPI_*, GM_Sandbox, PC_Sandbox, structs S_*, camĂ©ras
) : ce sont des doublons DIVERGENTS, Ă  ne pas confondre ni fusionner aveuglĂ©ment (voir §9, piĂšge consolidate_assets). Les enums, eux, sont partagĂ©s avec Systems/Blueprints/Data/ (fusionnĂ©s le 2026-09-14).

Content/Systems/Mover/
   ⚠ (2026-09-18) `SandboxCharacter_Mover`, `_Ragdoll` (et l'ABP du CMC) vivent en rĂ©alitĂ© dans `Content/Core/Character/` — les deux lignes ci-dessous y correspondent, elles restent dĂ©crites ici pour garder le framework Mover d'un seul tenant.
├── SandboxCharacter_Mover.uasset          → (dans `Content/Core/Character/`) Personnage basĂ© sur le plugin Mover. (VĂ©rifiĂ© le 2026-09-15) `GM_Dev` (GameMode de `MapDev1`) a `DefaultPawnClass = SandboxCharacter_Mover` ; en PIE sur `MapDev1` le pion obtenu est `SandboxCharacter_Mover_Ragdoll`. `SetupInput` ajoute `Core/PlayerController/Input/IMC_Sandbox` (mĂȘme IMC que le CMC, inputs AGIS/inventaire compris) ; il porte aussi `Inventory_Player`, dont la propriĂ©tĂ© `Input Mapping Context` DOIT valoir ce mĂȘme `IMC_Sandbox` (corrigĂ© le 2026-09-15, elle valait `IMC_AGIS_Character`) : Ă  la fermeture de l'inventaire, `WB_InventoryScreen.SwitchInput` fait `ClearAllMappings` puis ne rĂ©-ajoute QUE cette variable — une mauvaise valeur coupe tous les contrĂŽles (ZQSD, camĂ©ra) aprĂšs fermeture. MĂȘme piĂšge pour tout futur pion Ă©quipĂ© d'`Inventory_Player`. ImplĂ©mente `BPI_Interactable` depuis le 2026-09-17 (`GetTracePoint` = position/forward du composant `Camera`, comme `SandboxCharacter_CMC`) : sans cette interface, le trace d'interaction d'`Inventory_Player` (`Client Trace`, `Verify Trace`) part de (0,0,0) avec une direction nulle et aucun objet ne peut ĂȘtre ramassĂ©. Tout futur pion Ă©quipĂ© d'`Inventory_Player` doit aussi implĂ©menter `BPI_Interactable::GetTracePoint`
├── SandboxCharacter_Mover_Ragdoll.uasset  → Variante ragdoll du personnage Mover. ⚠ C'est LUI le pion rĂ©ellement possĂ©dĂ© en PIE ; il surcharge le composant `CharacterMover` (ses propres `MovementModes`, dont `Ragdoll`) et `ProduceInput`/`On_MovementModeChanged_PostFinalize`. Toute modification du parent qui touche Ă  ces Ă©lĂ©ments doit ĂȘtre vĂ©rifiĂ©e ici.
├── SandboxCharacter_Mover_ABP.uasset      → Anim Blueprint du Mover (utilise `Systems/Aiming/ABP_AimingMaster`). (2026-09-18) Deux corrections majeures : (1) les nƓuds `Evaluate Chooser` de `Update_MotionMatching` n'avaient AUCUN objet de contexte branchĂ© (au CMC il est reliĂ© Ă  `self`) → le chooser ne pouvait rĂ©soudre aucune de ses colonnes, `ValidDatabases` restait vide et la branche Motion Matching de l'`AnimGraph` Ă©tait morte ; `self` est dĂ©sormais branchĂ© sur les deux nƓuds. (2) Nouvelle variable `AnimBranchIndex` (affectĂ©e en fin d'`Update_Logic`) branchĂ©e sur l'`ActiveChildIndex` du *Blend Poses by int* de l'`AnimGraph`. Elle a d'abord pilotĂ© un hybride (Motion Matching en prone/nage, state machine GASP sinon) ; **depuis le 2026-09-18 elle vaut la constante `0`** : l'ABP du Mover est **100 % Motion Matching** (chooser `CHT_PoseSearchDatabases_Mover`), la state machine « State Controller » n'est plus jamais Ă©valuĂ©e. Le nƓud `Set AnimBranchIndex` et la variable sont conservĂ©s pour pouvoir rebasculer sur la voie 1 en changeant une seule valeur. Variables `Is Armed` et `IS Moving Object` ajoutĂ©es pour les colonnes du chooser copiĂ©.
├── GM_Sandbox.uasset / PC_Sandbox.uasset  → GameMode (pawn = SandboxCharacter_Mover) et PlayerController du Mover ; crĂ©ation du widget de dĂ©mo retirĂ©e le 2026-09-14
├── AC_TraversalLogic.uasset               → Traversal du personnage Mover (vault/mantle/hurdle/climb). (2026-09-15) La dĂ©tection de rebords du sample (limitĂ©e aux blocs de dĂ©mo `LevelBlock_Traversable`, retirĂ©e le 2026-09-14) est remplacĂ©e par celle de `Systems/Blueprints/AC_TraversalLogic` (CMC), portĂ©e Ă  l'identique : variables `Min Ledge Width`, `Min Front Ledge Depth`, `Max Ledge Sideways Depth`, `Trace Complex`, `Show Trace`, `Persistent Show Trace`, `RespectPlayersFacingDir`, `Banned Tags` (mĂȘmes valeurs par dĂ©faut) et fonctions `ComputeLedgeData`, `TraceAlongHitPlane`, `TraceCorners`, `TraceWidth`, `NudgeTraceTowardsObjectOrigin`, `Set Trace Hit Point`, `Tag Compare`. Dans `TryTraversalAction` : capsule trace sur `TraceTypeQuery1` (Visibility, au lieu du canal `Traversable`), `Hit` → tags acteur+composant → `ComputeLedgeData` → rebords avant/arriĂšre Ă©crits dans `TraversalCheckResult` (Ă©quivalent inlinĂ© de `TryAndCalculateLedges`, non recopiĂ©e car elle prend le struct Systems par rĂ©fĂ©rence), puis `Tag Compare` (tags bannis) avant le chooser `CHT_TraversalMontages_Mover`. Le dĂ©clenchement (`IA_Jump` → `CanDoTraversal` → `TryTraversalAction`) et l'exĂ©cution Mover (`PerformTraversalAction_Mover`, mode `Traversing`) sont inchangĂ©s. Les deux composants restent des doublons divergents (structs/BPI `Systems/Mover/` vs `Systems/Blueprints/`).
├── AC_PreCMCTick, AC_PostABPTick, AC_VisualOverrideManager  → Composants du sample (versions GASP, divergentes de celles de `Systems/Blueprints/`)
├── BPI_SandboxCharacter_Pawn / _ABP.uasset → Interfaces GASP implĂ©mentĂ©es par la chaĂźne Mover
├── AI/StateTree/                          → `ST_Player_SandboxCharacter_SmartObject` + tñches (copie GASP)
├── AnimModifiers/                         → `AM_BakePhaseCurveFromFootstepNotifies`, `AM_FootSteps_Run` (rĂ©fĂ©rencĂ©s par quelques anims `UEFN_Mannequin`)
├── Cameras/                               → `CameraAsset_SandboxCharacter`, `CameraDirector_SandboxCharacter`, `CHT_CameraRig`, `CameraShake_Basic`, `Rigs/CameraRig_*` (16)
├── ControlRigs/CR_Biped_FootPlacement.uasset
├── Data/                                  → Structs GASP (`S_CharacterPropertiesFor*`, `S_Traversal*`, `S_CHT_*` des choosers Mover/GetUp/Interaction, `S_Ragdoll*`, `S_MoverCustomInputs*`
), `Curve_RotationOffset_*`, `CHT_RotationOffsetCurve`, `BFL_HelpfulFunctions`, `BPI_InteractionTransform`
├── MovementModes/                         → `BP_MovementMode_Walking/Falling/Slide/Ragdoll`, `B_MovementMode_Flying`, `BP_MovementTransition_To/FromSlide`, **`BP_MovementMode_Swimming`** (2026-09-18). `BP_MovementMode_Walking` : la `Select` d'allure n'alimentait QUE Walk/Run/Sprint — les allures ajoutĂ©es (Prone, Swinning, SwinningSprint) donnaient vitesse ET accĂ©lĂ©ration = 0 (personnage figĂ©) ; ajout de la variable `ProneSpeed` (125) et cĂąblage des entrĂ©es manquantes (prone → `ProneSpeed`/`WalkAcceleration`, nage → Walk/Run). `BP_MovementMode_Swimming` : enfant de `SimpleFlyingMode` (comme le mode vol), tag `Mover.IsSwimming`, `MaxSpeedOverride = 1` (l'entrĂ©e devient un pur vecteur d'intention) ; sa fonction `ComputeSwimTarget` lit le personnage propriĂ©taire (cast `SandboxCharacter_Mover`) et produit la vitesse cible : en surface, Z = flottaison vers `WaterSurfaceZ - SurfaceOffset` (60) bornĂ©e par `MaxBobSpeed`, en plongĂ©e Z = intention camĂ©ra + `SwimVerticalInput` × `VerticalSpeed`, horizontal = intention × `SwimSpeed` (250) ou `SwimSprintSpeed` (450). ⚠ Le `SwimmingMode` natif du plugin Mover (UE 5.8) n'est PAS utilisable : son `SimulationTick` est vide et rien n'alimente ses donnĂ©es d'eau (`CommonBlackboard::LastWaterResult`).
└── SmartObjects/                          → `AC_SmartObjectAnimation` (version GASP, aussi utilisĂ©e par des STT de `Systems/Blueprints/`), `CHPA_SmartObject`, `PSS_SmartObject`, `Bench/`, `TasksAndConditions/STT_*`

Content/Systems/Aiming/                    → SystĂšme de visĂ©e dĂ©veloppĂ© dans Project_F : `ABP_AimingMaster`, `ABP_AimingMaster_UEFN` (aim offset), choosers `CH_AO`, `CH_Base_AO_Animechooser` (enum `Data/Enums/E_WaponType`)

Content/Blueprints/AnimNotifies/           → SEUL reste de `Content/Blueprints/` : 23 notifies du sample (`BP_AnimNotify_FoleyEvent*`, `BP_NotifyState_EarlyTransition`, `_MontageBlendOut`, `_MMI_*`, `BP_AnimNotify_TriggerRagdoll`, `_OverrideMovementMode`
) liĂ©s Ă  1278 animations de `Characters/UEFN_Mannequin`. LaissĂ©s en place volontairement : les dĂ©placer rĂ©enregistrerait 1,78 Go d'animations. Pour la plupart doublons de `Systems/Blueprints/AnimNotifies/`.

4.2.2 Cover / prone / nage portés du CMC vers le personnage Mover (2026-09-18)

Ces trois fonctionnalités n'existaient que sur SandboxCharacter_CMC (via le CharacterMovementComponent). Elles ont été reportées sur Core/Character/SandboxCharacter_Mover, en passant par les mécanismes du plugin Mover et non par des écritures directes sur la capsule.

  • Composants ajoutĂ©s au Mover : Systems/Movement/Cover/AC_Cover (le composant du CMC, gĂ©nĂ©rique : il travaille via GetOwner) et Arrow1 (ArrowComponent, (0,0,90) / yaw 90). ⚠ Arrow1 DOIT ĂȘtre attachĂ© au SkeletalMesh (comme au CMC) et non Ă  la capsule : le mesh porte un yaw −90, donc l'arrow attachĂ© au mesh se retrouve alignĂ© sur l'acteur (avant = avant de l'acteur, droite = droite de l'acteur), ce qu'attend le sphere trace de MoveAlongWall (il part de 55 uu sur le cĂŽtĂ© puis trace 60 uu vers l'avant, dans le mur). AttachĂ© Ă  la capsule, ses axes sont tournĂ©s de 90° : le trace part dans le vide, MoveAlongWall ne produit aucun AddMovementInput et on ne peut pas se dĂ©placer en couverture (bug corrigĂ© le 2026-09-18).
  • Variables ajoutĂ©es au Mover — catĂ©gorie Cover : In Cover, Cover (E_CoverD), Edge L, Edge R ; catĂ©gorie Prone : IsProne, ProneHalfHeight (40), CrouchHalfHeight (55) ; catĂ©gorie Swimming : CurrentWaterBodyComp, IsSwimming, IsUnderwater, SwimSprint, WaterSurfaceZ, WaterDepth, SwimVerticalInput, SwimStartDepth (95), SwimStopDepth (80), SwimmingModeClass.
  • Prone : IA_Prone → ToggleProne (bascule IsProne + WantsToCrouch/WantsToStrafe dans PlayerInputState), refusĂ© en nage ou en cover. La hauteur de capsule N'est PAS Ă©crite directement (contrairement au CMC qui fait SetCapsuleSize) : Apply_CrouchOrProne, appelĂ©e depuis On_PreSimulateTick, rĂšgle StanceSettings.CrouchHalfHeight (40 en prone, 55 accroupi) et force un cycle UnCrouch→Crouch quand la capsule courante ne correspond pas — c'est le FStanceModifier du plugin qui redimensionne la capsule, replace l'acteur et dĂ©cale le mesh. IA_Crouch en prone appelle ExitProneToCrouch (retour accroupi).
  • Nage : les overlaps de la capsule (OnComponentBegin/EndOverlap → cast WaterBody) renseignent CurrentWaterBodyComp ; Update_Swimming (appelĂ©e depuis On_PreSimulateTick, voir l'encadrĂ© « tick » plus bas) lit GetWaterSurfaceInfoAtLocation (surface + profondeur), met Ă  jour SwimSprint (depuis PlayerInputState.WantsToSprint) et SwimVerticalInput (valeurs brutes de IA_Jump − IA_Crouch), puis StartSwimming (profondeur ≄ SwimStartDepth → QueueNextMovementMode("Swimming")) / StopSwimming (< SwimStopDepth → Falling). IA_SwimmingDeep bascule IsUnderwater (plongĂ©e). Le mode « Swimming » est enregistrĂ© au BeginPlay par AddMovementModeFromClass (variable SwimmingModeClass) et non dans la map MovementModes du composant : une instance créée par script dans le template du parent est privĂ©e et empĂȘchait la sauvegarde de SandboxCharacter_Mover_Ragdoll (« Illegal reference to private object »).
  • Cover : l'Ă©vĂ©nement OnEntreredCover d'AC_Cover recopie InCover/cover/EdgeL/EdgeR sur le personnage puis ApplyCoverCrouch (accroupi et WantsToStrafe = en couverture tant qu'on y est) ; IA_Move appelle AC_Cover.MoveAlongWall quand In Cover. Comme le Mover ignore AddMovementInput, Get_MoveInput renvoie, en cover, ConsumeMovementInputVector (le vecteur accumulĂ© par le composant). Update_Cover (On_PreSimulateTick) met CharacterMover.bAcceptExternalMovement Ă  la valeur d'AC_Cover.InCover, sinon le MoveComponentTo de collage au mur serait annulĂ© par la simulation Mover. ⚠ Le mode strafe est indispensable en couverture : sans lui le Mover rĂ©oriente le personnage dans la direction du glissement dĂšs le premier pas, l'Arrow1 tourne avec, le trace de MoveAlongWall rate le mur et le dĂ©placement se bloque aprĂšs quelques centimĂštres (bug corrigĂ© le 2026-09-18). L'entrĂ©e en couverture reste sur la touche P : depuis le 2026-09-18 le corps de cet InputKey est dĂ©portĂ© dans l'Ă©vĂ©nement ToggleCover d'AC_Cover (la touche P l'appelle), ce qui permet de dĂ©clencher la couverture par script/test ou de la remapper plus tard sur une Input Action.
  • Alimentation de l'animation : Get_PropertiesForAnimation renvoie dĂ©sormais Stance = Swinning / SwinningDeep / Prone / Crouch / Stand, et Get_Gait renvoie Prone en prone, Swinning/SwinningSprint en nage. Get_MoveInput utilise la rotation camĂ©ra complĂšte (input 3D) en plongĂ©e comme en vol. Le chooser Characters/UEFN_Mannequin/Animations/MotionMatchingData/CHT_PoseSearchDatabases_Mover est une copie du _Dense du CMC dont le ContextData pointe sur SandboxCharacter_Mover_ABP ; ses deux colonnes boolĂ©ennes (Is Armed, IS Moving Object) sont dĂ©sactivĂ©es et la ligne « push » restreinte Ă  Stance = Stand.
  • Les deux moteurs d'animation de l'ABP (Motion Matching vs state machine) : l'AnimGraph (CMC comme Mover) contient un Blend Poses by int dont l'entrĂ©e 0 est le nƓud Motion Matching et l'entrĂ©e 1 la state machine « State Controller » + Blend Stack (la voie « expĂ©rimentale » du sample GASP). Voie 0 : Update_MotionMatching (fonction de nƓud) Ă©value un chooser qui renvoie une LISTE de PoseSearchDatabase, SetDatabasesToSearch les donne au nƓud, qui recherche chaque frame la meilleure pose d'aprĂšs la trajectoire (Update_Trajectory) — variables ValidDatabases, CurrentSelectedDatabase/Anim, MM Search Cost, rĂ©glages Get_MMBlendTime/Get_MMInterruptMode. Voie 1 : Ă  chaque entrĂ©e d'Ă©tat, SetBlendStackAnimFromChooser Ă©value CHT_MoverCharacterAnimations_PoseMatch (chooser par clip, une ligne = une animation) qui renvoie UNE anim + ses rĂ©glages de blend, poussĂ©e dans le Blend Stack — variables StateName, BlendStackInputs, Search Cost, NoValidAnim. Dans les deux ABP l'index valait la constante 0 (Motion Matching en permanence) ; sur le Mover il passe par la variable AnimBranchIndex, qui vaut elle aussi 0 en permanence depuis le 2026-09-18 (l'hybride state machine / Motion Matching a Ă©tĂ© abandonnĂ© Ă  la demande de l'utilisateur, voir §4.2.1). Les CVars GASP DDCvar.UseExperimentalStateMachine / DDCvar.ExperimentalStateMachine n'existent pas dans ce projet (avertissement « Failed to find console variable » en PIE) : elles ne commandent rien.
  • Correction de MovementModeMap : « Ragdoll » pointait sur Climbing et « Flying » sur SwimmingOnSurface (dĂ©calage laissĂ© par la fusion des enums GASP → projet, §8.2). Remis sur Ragdoll/Flying + ajout de Swimming → SwimmingOnSurface. Effet de bord bĂ©nĂ©fique : le ragdoll du pion refonctionne (son Tick et EnteredRagdollSuccessfullyCheck comparent le mode courant Ă  Ragdoll).
  • ⚠ Tick du personnage Mover (corrigĂ© le 2026-09-18) : SandboxCharacter_Mover et _Ragdoll avaient PrimaryActorTick.TickInterval = 30 s (le CMC est Ă  0). Tout leur Event Tick — CacheInputsFromMover, Update_FloorValues, Update_ControlRotationRate, Update_SlidingAudio, Update_TargetedActor, Update_TwinStickMode, Update_SmoothedAnalogInputAmount, DebugDraws — ne tournait donc qu'une fois toutes les 30 secondes (c'est ce qui empĂȘchait la nage de se dĂ©clencher : Update_Swimming y Ă©tait branchĂ©e). Intervalle remis Ă  0 sur les deux pions, et par sĂ©curitĂ© Update_Swimming + Update_Cover ont Ă©tĂ© dĂ©placĂ©es du Event Tick vers On_PreSimulateTick (dĂ©lĂ©guĂ© du CharacterMover, exĂ©cutĂ© Ă  chaque pas de simulation). Si un jour le tick de ces pions est de nouveau throttlĂ© (politique BP_TickManager), la nage et la couverture continueront de fonctionner, mais les Update_* du framework GASP, eux, en souffriront.
  • ⚠ Bases Pose Search de nage vides → T-pose (contournĂ© le 2026-09-18) : sur les 6 bases de nage, une seule est rĂ©ellement remplie, Animations/humain/SwimmingAnimation/Swimming_animation/Breastok/surface/PSD_SwimmingMoving (5 clips de brasse en surface). PSD_SwimmingIdle, PSD_SwimmingMovingSprint, PSD_SwimmingDeepIdle, PSD_SwimmingDeepMoving, PSD_SwimmingDeepMovingSprint ont des lignes dont l'AnimAsset est None (log : OnGetComplete - Database None entry N has no associated animation asset), et la table imbriquĂ©e SwimmingInDeepIdle du chooser n'a aucun rĂ©sultat. L'ABP Ă©tant dĂ©sormais 100 % Motion Matching, une base vide = aucune pose = T-pose, exactement le bug remontĂ©. Contournement appliquĂ© dans CHT_PoseSearchDatabases_Mover : les lignes qui pointent sur une base vide (12, 14, 15, 17) sont rendues inatteignables (Stance = Prone alors que Movement Mode = Swimming, combinaison impossible par construction) et les deux lignes qui pointent sur PSD_SwimmingMoving (13 pour Swinning, 16 pour SwinningDeep) passent Movement State et Gait en MatchAny pour couvrir tous les cas de nage. VĂ©rifiĂ© en PIE : nage de surface immobile, nage de surface en mouvement et nage profonde sĂ©lectionnent bien RM_Breastroke_overwater_01_*.
  • Vraie correction Ă  faire Ă  la main (impossible par script : la propriĂ©tĂ© DatabaseAnimationAssets d'un PoseSearchDatabase et le ResultsStructs d'un ChooserTable ne sont exposĂ©s ni au Python d'UE ni Ă  ObjectTools.set_properties — seules columnsStructs/contextData le sont) : ouvrir chaque base vide et y glisser les clips qui existent dĂ©jĂ  sous Animations/humain/SwimmingAnimation/ — IDLE/IP_idle_underwater_01_Retargeted + IDLE/RM_Idle_turn_* pour PSD_SwimmingIdle, Swimming_animation/Crawl/RM_Crawl_* pour PSD_SwimmingMovingSprint, Swimming_animation/Breastok/RM_Breastroke_underwater_* pour PSD_SwimmingDeepIdle/Moving/MovingSprint — puis remettre les lignes 12/14/15/17 du chooser sur leur Stance d'origine (3, 3, 4, 4) et donner un rĂ©sultat Ă  la table imbriquĂ©e SwimmingInDeepIdle.
  • Restes connus : le cover du Mover joue les anims accroupies GASP, pas les bases de couverture du CMC (PSD_Dense_Crouch_Idles_CoverLeft/Right) ni le nƓud Mirror de l'AnimGraph du CMC ; en couverture le personnage conserve un Ă©cart d'orientation d'une dizaine de degrĂ©s par rapport au mur (orientation strafe qui converge lentement).

4.2.3 SystÚme d'armes porté sur le personnage Mover (2026-09-19)

Ce qui marchait dĂ©jĂ  sur le Mover avant cette session (vĂ©rifiĂ© en PIE) : le ramassage (IA_InteractAGIS), le rangement au dos (socket SpineRifle), le passage en main par la roue V/B (IA_QuickSelectAGIS / IA_QuickEquipAGIS → socket Rifle), l'appel de AC_Weapon::Equip/Unequip via HandleHeldStateChanged, et le tir (IA_UseItemPrimaryAGIS → Inventory_Player::UseHeldPrimarySERVER → BP_Item_AdvancedRifle::EventPrimaryUse). Inventory_Equipper est gĂ©nĂ©rique : son OwnerMesh se rĂ©sout bien sur le composant SkeletalMesh du Mover.

Ce qui ne marchait PAS et a été corrigé :

  • AC_Weapon ne parlait qu'au CMC : Equip/Unequip faisaient un Cast To SandboxCharacter_CMC, qui Ă©choue sur le Mover (Pawn vs Character, aucune classe commune). RĂ©sultat : arme bien en main, mais Weapon et isArmed jamais Ă©crits → locomotion dĂ©sarmĂ©e en permanence. Une branche Cast Failed → Cast To SandboxCharacter_Mover a Ă©tĂ© ajoutĂ©e dans les deux fonctions ; le CMC est inchangĂ©.
  • Nouvelle fonction SandboxCharacter_Mover::SetEquippedWeapon(WeaponTypeByte) (appelĂ©e par AC_Weapon, 0 = dĂ©sĂ©quipement) : Ă©crit Weapon_Equip (nouvelle variable, enum Weapon_Equip), isArmed (= byte ≠ 0), WantToshot (remis Ă  false au dĂ©sĂ©quipement) et Weapon. ⚠ Trois enums d'arme coexistent dans le projet : Weapon_Equip (None/Bow/OneArmPistol/TwoArmPistol/Riffle/Bat — c'est l'espace de AC_Weapon::WeaponTypeByte et des colonnes du chooser de locomotion), E_WaponType (None/Riffle/Pistoll/Bow — c'est le type de SandboxCharacter_Mover::Weapon et du champ S_CharacterPropertiesForAnimation.Weapon_Type, lu par les choosers d'aim offset de Systems/Aiming/) et E_WeaponType (inutilisĂ© ici). SetEquippedWeapon fait donc la conversion 1(Bow)→3, 2/3(Pistol)→2, 4(Riffle)→1, reste→0.
  • IA_Aim renseigne WantToshot (nouvelle variable du pion) : WantToshot = ActionValue AND isArmed sur Triggered, remis Ă  false sur Completed. C'est ce bool que lit la colonne « Want Toshot » du sous-chooser Stand Idles Bow pour passer de l'idle arc Ă  l'idle arc en visĂ©e.
  • SandboxCharacter_Mover_ABP reçoit l'Ă©tat d'arme : nouvelles variables Weapon_Equip, Weapon_Equip Last Frame, Want Toshot (+ Is Armed et IS Moving Object dĂ©jĂ  prĂ©sentes), toutes alimentĂ©es en fin de Update_PropertiesFromCharacter (thread principal, comme le CMC le fait dans son EventBlueprintUpdateAnimation — surtout pas dans Update_Logic, qui peut tourner en thread-safe update).
  • Is Armed de l'ABP = isArmed ET Weapon_Equip == Bow — stopgap assumĂ© : l'arc est la SEULE arme qui possĂšde des bases Motion Matching armĂ©es (PSD_Dense_Stand_Bow_Idles, _Bow_Aim_Idles, PSD_Walk_Bow). Sans cette condition, un fusil mettait Is Armed = true, les lignes 0/2 du chooser (MatchFalse) Ă©taient rejetĂ©es, les lignes arc 1/3 Ă©chouaient sur leur colonne Weapon_Equip, et on retombait sur la ligne 18 « Push » (ou sur rien du tout). Avec la condition, fusil/pistolet jouent proprement la locomotion dĂ©sarmĂ©e, arme en main. À retirer le jour oĂč des bases fusil existeront.
  • Update_MotionMatching : le chooser CHT_PoseSearchDatabases_Mover n'Ă©tait consultĂ© que si Stance ∉ {Stand, Crouch} (prone/nage). La condition devient (Stance ≠ Stand ET ≠ Crouch) OU Is Armed, sinon les lignes arc — qui sont des lignes debout — n'Ă©taient jamais atteintes. La sortie False du Branch est en plus reliĂ©e Ă  SetDatabasesToSearch pour que les deux chemins poussent bien leur liste dans le nƓud MM.
  • Get_MMInterruptMode : ajout du terme Weapon_Equip ≠ Weapon_Equip Last Frame sur le OR racine. Sans lui, changer d'arme ne forcçait aucune interruption : Motion Matching gardait la pose continue (anim dĂ©sarmĂ©e) et ne basculait jamais sur la base arc, mĂȘme une fois celle-ci dans la liste (coĂ»t de continuitĂ© toujours plus bas). C'est le mĂȘme piĂšge que celui dĂ©crit en §1.3 pour le CMC.
  • CHT_PoseSearchDatabases_Mover : colonne Is Armed rĂ©activĂ©e (elle avait Ă©tĂ© dĂ©sactivĂ©e le 2026-09-18 faute de propriĂ©tĂ© correspondante sur l'ABP Mover), colonne IS Moving Object rĂ©activĂ©e aussi (sinon la ligne 18 « Push » devient un attrape-tout qui remporte tous les cas debout non couverts), et ligne 1 (« Stand Idles Bow ») : colonne Gait passĂ©e de MatchEqual Walk Ă  MatchAny. C'Ă©tait le dernier blocage : l'allure par dĂ©faut du personnage est Run, donc la ligne arc ne pouvait jamais matcher Ă  l'arrĂȘt. (Le mĂȘme dĂ©faut existe dans CHT_PoseSearchDatabases_Dense cĂŽtĂ© CMC, non corrigĂ© ici.)

VĂ©rifiĂ© en PIE, dans cet ordre : ramassage du fusil → dos ; V+B → main + Weapon = Riffle, Weapon_Equip = Riffle, isArmed = true cĂŽtĂ© pion ET cĂŽtĂ© ABP ; locomotion dĂ©sarmĂ©e propre avec le fusil en main (pas de T-pose) ; arc → PSD_Dense_Stand_Bow_Idles → StandingIdle01_UE_Anim3 ; arc + clic droit → Want Toshot = true → PSD_Dense_Stand_Bow_Aim_Idles ; arc en course → repli propre sur PSD_Dense_Stand_Run_Loops ; clic gauche → EventPrimaryUse du fusil (qui refuse de tirer faute de chargeur Ă©quipĂ© — comportement normal, non liĂ© au Mover) ; non-rĂ©gression prone (PSD_Dense_Prone_Idles) et nage (PSD_SwimmingMoving).

Restant Ă  faire :

  • Aucune base Motion Matching armĂ©e pour le fusil / le pistolet (seul l'arc en a) ; PSD_Crouch_Bow existe mais n'est rĂ©fĂ©rencĂ©e par aucune ligne de chooser.
  • SandboxCharacter_Mover n'a pas de composant AC_Stats (le CMC en a un) : BFL_WeaponDamage::ApplyPointDamage rĂ©sout AC_Stats sur la cible, donc le pion Mover ne peut pas encaisser de dĂ©gĂąts. Il lui manque aussi les capsules de hitbox et le PerceptionStimuliSource du CMC.
  • La visĂ©e n'a pas d'Ă©quivalent de SandboxCharacter_CMC::ISaiming sur le Mover (seuls PlayerInputState.WantsToAim et WantToshot existent).

4.2.4 MetaHuman en « visual override » du personnage Mover (2026-09-19)

Approche retenue (celle du sample GASP, cf. la vidĂ©o de rĂ©fĂ©rence) : le mannequin UEFN reste le mesh du pion et porte toute l'animation ; le MetaHuman est un acteur enfant qui le recopie par retarget IK. Le mesh du pion est simplement rendu invisible. Avantage : rien ne change cĂŽtĂ© Motion Matching, sockets, prone/nage, ragdoll — et on peut changer de « peau » Ă  chaud.

Le pipeline existait déjà dans le projet mais était incomplet : SandboxCharacter_Mover a son ChildActorComponent VisualOverride (tagué VisualOverride) et son AC_VisualOverrideManager, mais tous les acteurs de skin du sample (BP_Manny, BP_Quinn, BP_Echo, BP_Twinblast, BP_UE4_Mannequin) et l'AnimBP qui les pilote avaient été supprimés au nettoyage de la démo GASP.

Assets créés / restaurés, tous dans Content/Systems/Mover/VisualOverrides/ :

  • ABP_GenericRetarget — rĂ©cupĂ©rĂ© du commit initial (538ebd2a). C'est un Animation Blueprint Template (bIsTemplate, donc sans squelette cible : utilisable sur n'importe quel mesh). Son AnimGraph tient un seul nƓud Retarget Pose From Mesh ; son EventBlueprintUpdateAnimation choisit l'IKRetargeter dans la map IKRetargeter_Map en utilisant le premier Component Tag du composant qui l'hĂ©berge comme clĂ©. La map garde ses entrĂ©es d'origine (toutes Ă  None, les retargeters du sample ayant Ă©tĂ© supprimĂ©s) plus la nĂŽtre.
  • IK_MetaHuman_test — IK Rig sur /Game/test/Body/SKM_test_BodyMesh, gĂ©nĂ©rĂ© par IKRigController.apply_auto_generated_retarget_definition() (l'auto-caractĂ©risation reconnaĂźt le squelette MetaHuman : bassin = pelvis, 29 chaĂźnes standard).
  • RTG_UEFN_to_MetaHuman_test — source IK_UEFN_Mannequin, cible IK_MetaHuman_test. auto_map_chains(EXACT) mappe tout sauf deux chaĂźnes, l'auto-caractĂ©risation MetaHuman nommant LeftFoot/RightFoot ce que le mannequin appelle LeftToe/RightToe — mappĂ©es Ă  la main. ⚠ add_default_ops() ne crĂ©e PAS l'op des chaĂźnes IK. La pile par dĂ©faut est Pelvis Motion / FK Chains / Run IK Rig / Root Motion / Remap Curves ; or ABP_GenericRetarget::UpdateRetargetProfile va chercher l'op nommĂ©e « Retarget IK Goals » (GetOpControllerFromRetargetProfile → cast vers IKRetarget_IKChains_Controller) pour moduler l'alpha d'IK par chaĂźne. Sans elle, le cast renvoie None et SetSettings spamme un Blueprint Runtime Error Ă  chaque frame. Correctif : add_retarget_op("/Script/IKRig.IKRetargetIKChainsOp") — le chemin de classe complet est obligatoire, le nom court est refusĂ© (retourne -1). L'op arrive dĂ©jĂ  nommĂ©e « Retarget IK Goals » et se place juste avant « Run IK Rig » ; il faut ensuite refaire assign_ik_rig_to_all_ops + auto_map_chains (les mappings de chaĂźnes sont par op). RĂ©sultat : 4 chaĂźnes IK (LeftLeg, LeftArm, RightLeg, RightArm), plus aucune erreur en PIE.
  • BP_VisualOverride_MetaHuman — Actor : Body (racine, SKM_test_BodyMesh, AnimClass = ABP_GenericRetarget_C, Component Tag RTG_UEFN_to_MetaHuman_test) → Face (SKM_test_FaceMesh, ABP_Face_C) ; plus un MetaHumanComponentUE (BodyComponentName = "Body", FaceComponentName = "Face", post-process ABP_Clothing_PostProcess). Pas de grooms : ce MetaHuman n'en a aucun d'assignĂ©.

Cùblage de la sélection :

  • GM_Sandbox (Systems/Mover/) reçoit BP_VisualOverride_MetaHuman dans VisualOverrides_Soft.
  • GM_Dev est reparentĂ© sur GM_Sandbox. C'Ă©tait un GameModeBase totalement vide (aucune variable, aucun nƓud) qui ne servait qu'Ă  fixer DefaultPawnClass ; or AC_VisualOverrideManager::FindAndApplyVisualOverride fait un Cast To GM_Sandbox — sans ce reparentage, la DevMap n'appliquait jamais d'override (pire : le cast ratĂ© le remettait activement Ă  zĂ©ro). DefaultPawnClass, PawnClasses_Soft et VisualOverrides_Soft sont renseignĂ©s sur GM_Dev.
  • La sĂ©lection se fait par le CVar DDCvar.VisualOverride (index dans la liste, -1 = pas d'override). Son dĂ©faut est passĂ© de -1 Ă  0 dans Config/DefaultEngine.ini pour que le MetaHuman soit affichĂ© d'entrĂ©e. Repasser Ă  -1 (ou taper DDCvar.VisualOverride -1 en console) rend le mannequin.

VĂ©rifiĂ© en PIE : le mannequin passe invisible, BP_VisualOverride_MetaHuman est spawnĂ© dans le ChildActorComponent, le MetaHuman (corps + tĂȘte + matĂ©riaux) suit l'animation Ă  l'arrĂȘt comme en course, le Motion Matching continue de tourner normalement sur le mannequin cachĂ© (PSD_Relaxed_Stand_Idles → PSD_Relaxed_Stand_Run_F_Loops).

⚠ Limite structurelle de cette approche : les objets Ă©quipĂ©s s'accrochent aux sockets du mesh pilote cachĂ©, pas du MetaHuman (Inventory_Equipper attache sur OwnerMesh, qui est le composant SkeletalMesh du pion). MesurĂ© en PIE : ~12 cm d'Ă©cart entre hand_r du mannequin et hand_r du MetaHuman — une arme en main flottera d'autant. Correctif Ă  prĂ©voir : pointer OwnerMesh sur le composant Body de l'override quand un override est actif, ou n'utiliser l'override que pour des skins aux proportions du mannequin.

Autres points :

  • Portrait de l'inventaire (2026-09-21) : RefreshInventoryCapture (Mover) appelle en fin de chaĂźne le nouveau custom event AddAttachedActorsToInventoryCapture, qui ajoute Ă  la show-only list de SceneCaptureComponent2D les composants de chaque acteur attachĂ© au pion (rĂ©cursif). Sans ça, les objets Ă©quipĂ©s (vĂȘtements BP_Item_SurvivorOutfit_*, armes) n'apparaissaient pas dans le portrait : ils appartiennent Ă  l'acteur item, pas au pion ni Ă  ses child actors.
  • Le ragdoll n'a pas Ă©tĂ© testĂ© avec l'override actif (il simule sur le mesh cachĂ© ; le MetaHuman devrait suivre par retarget).
  • Les 13 sockets recopiĂ©es sur SKM_test_BodyMesh lors de la tentative prĂ©cĂ©dente ont Ă©tĂ© retirĂ©es : elles ne servent plus, les attaches restant sur le mannequin.
  • Pour ajouter une autre peau : crĂ©er IK_X + RTG_UEFN_to_X, ajouter l'entrĂ©e dans ABP_GenericRetarget.IKRetargeter_Map, dupliquer BP_VisualOverride_MetaHuman en changeant meshes et Component Tag, et l'ajouter Ă  VisualOverrides_Soft.

4.3 Autres systÚmes de gameplay (ajouts spécifiques au projet)

Content/Systems/
├── Stats/
│   └── AC_Stats.uasset                   → ActorComponent ACTIF : gĂšre la vie du personnage (Health), la mort (bIsDead, dispatcher OnDeath), Heal, Revive (voir §1.3). AjoutĂ© cette session pour le systĂšme de mort/respawn. (2026-09-05) Extension additive pour la faune : nouveau dispatcher `OnDamaged(BodyPart, DMGValue)`, diffusĂ© au point de convergence partagĂ© de `TakeDamage` (aprĂšs le switch par bodypart, avant le calcul de mort) — permet Ă  un consommateur (ex. BP_AnimalBase) de rĂ©agir Ă  CHAQUE coup reçu, pas seulement Ă  la mort, sans dupliquer la logique de dĂ©gĂąts.
│
├── Weapons/ (2026-09-05)                 → Architecture d'armes gĂ©nĂ©rique, rĂ©utilisable par toute arme (arc, arme Ă  feu, futur mĂȘlĂ©e). Voir §1.3 pour le mĂ©canisme d'Ă©quipement.
│   ├── AC_Weapon.uasset                  → ActorComponent commun Ă  TOUTE arme (ajoutĂ© Ă  BP_Item_Bow et BP_Item_AdvancedRifle). Ne contient AUCUNE logique spĂ©cifique Ă  un type d'arme. Variables : bIsEquipped, bIsBusy, CooldownDuration, LastUseTime, OwnerCharacter. Dispatchers : OnEquipped/OnUnequipped/OnPrimaryUse(Stopped)/OnSecondaryUse(Stopped). Fonctions : CanUse(), Equip/Unequip, TryUsePrimary/StopPrimary, TryUseSecondary/StopSecondary. Son EventGraph s'auto-abonne Ă  `OnOwnerChanged` de son propre acteur (pattern `Default|AssignOnOwnerChanged`) pour appeler Equip/Unequip automatiquement — zĂ©ro couplage avec Inventory_Player/Equipper.
│   ├── BFL_WeaponDamage.uasset            → Blueprint Function Library. `ApplyPointDamage(Target, Instigator, HitBoneName, Damage)` : rĂ©sout le composant `AC_Stats` de la cible (`GetComponentByClass` + cast, no-op silencieux si absent) et route vers `AC_Stats::TakeDamage`, en mappant le nom d'os touchĂ© (bones du squelette UEFN_Mannequin : head/neck_*→Head, thigh|calf|foot|ball_L/R→LeftLeg/RightLeg, clavicle|upperarm|lowerarm|hand_L/R→LeftArm/RightArm, tout le reste dont spine_*/pelvis/root→Torso par dĂ©faut). RĂ©utilisable par toute arme/projectile/piĂšge futur.
│   ├── BP_Projectile_Base.uasset          → Actor projectile gĂ©nĂ©rique : StaticMeshComponent racine `ArrowMesh` (mesh + collision, PAS de mesh par dĂ©faut — Ă  fournir par les enfants) + `ProjectileMovement`. `OnComponentHit` : ignore les hits sur son propre `Owner` (Ă©vite l'auto-hit au tir), appelle `BFL_WeaponDamage::ApplyPointDamage` puis `HandleImpact(Hit)` — fonction overridable (dĂ©faut : `DestroyActor`). Variable `BaseDamage` (instance-editable).
│   └── BP_Projectile_Arrow.uasset         → HĂ©rite de BP_Projectile_Base. Override du mesh `ArrowMesh` (mesh Fab `cc0_wooden_arrow`, collision `BlockAllDynamic`) via override de composant hĂ©ritĂ© (PAS le template du parent — voir piĂšge §9). Override `HandleImpact` : au lieu de se dĂ©truire, se fige (dĂ©sactive la simulation + la collision) et s'attache (KeepWorld) au composant touchĂ© pour rester plantĂ© visuellement dans le dĂ©cor/la cible.
│
├── Wildlife/ (2026-09-05)                → Premiers animaux sauvages (cerf mĂąle + biche). Architecture gĂ©nĂ©rique : toute la logique commune vit dans `BP_AnimalBase` + un unique StateTree partagĂ© ; une espĂšce (Content/Systems/Wildlife/BP_Deer_Stag, BP_Deer_Doe) ne fait qu'assigner mesh/anims/tunables — ajouter un sanglier ou un loup plus tard consiste Ă  crĂ©er UN NOUVEAU Character enfant de `BP_AnimalBase`, sans toucher au StateTree ni aux tĂąches. RĂ©utilise tel quel `AC_Stats` (vie/dĂ©gĂąts/mort) et `BP_ScentPoint` (odeurs) — voir §1.3. NĂ©cessite le plugin **GameplayStateTree** (ajoutĂ© Ă  `ProjectFv1.uproject` cette session, `StateTreeAIComponentSchema`/`StateTreeComponentSchema` indisponibles sans lui — seul le plugin `StateTree` de base Ă©tait actif auparavant) ; premier usage de StateTree dans ce projet (aucune Behavior Tree/Blackboard/AIController n'existait avant).
│   ├── E_AnimalState.uasset               → Enum (UserDefinedEnum, créé via `unreal.EnumStructService`) : Idle/Wander/Graze/Rest/Alert/Flee/Dead. Sert d'Ă©tiquette de debug + de sĂ©lecteur d'anim d'arrĂȘt (voir `BP_AnimalBase::ApplyIdleForState`) ; le StateTree stocke en interne l'Ă©tat courant sous forme de `byte` (les outils Blueprint disponibles ne permettent pas d'ajouter une variable membre ou un paramĂštre de fonction/dispatcher directement typĂ© sur un enum utilisateur — limitation dĂ©jĂ  documentĂ©e §9 pour AC_Stats, confirmĂ©e Ă  nouveau ici).
│   ├── AC_AnimalSenses.uasset              → ActorComponent gĂ©nĂ©rique (vue + odorat), ajoutĂ© Ă  `BP_AnimalBase`. Vue : ne fait AUCUNE dĂ©tection elle-mĂȘme — se contente de variables (`bCanSeePlayer`, `DistanceToPlayer`, `LastKnownPlayerLocation`) mises Ă  jour par `BP_AnimalAIController` via `ReportPlayerSighted`/`ReportPlayerLostSight`. Odorat : self-contained, `CheckScent` tourne sur un timer (`ScentCheckInterval`, 0.5s par dĂ©faut) dĂ©marrĂ© au `BeginPlay`, interroge `GetAllActorsOfClass(BP_ScentPoint)` et retient le plus proche (`bScentDetected`/`ScentSourceLocation` si distance ≀ `ScentDetectionRadius`, 800 par dĂ©faut). `DistanceToPlayer` est recalculĂ©e Ă  CHAQUE tick de `CheckScent` (pas seulement quand le joueur est vu) — nĂ©cessaire pour que le StateTree puisse dĂ©tecter le retour au calme (`DistanceToPlayer >= SafeDistance`) mĂȘme aprĂšs que l'animal ait fui hors de vue (bug rencontrĂ© et corrigĂ© en test PIE, voir §9). (2026-09-14) `CheckScent` réécrit : distance calculĂ©e par point d'odeur dans la boucle (l'ancienne version comparait une valeur hors boucle), pawn joueur relu Ă  chaque passe via `GetPlayerPawn(0)` (le cache du `BeginPlay` devenait invalide aprĂšs mort/respawn → fuite infinie), `LastKnownPlayerLocation` rafraĂźchie tant que le joueur est vu (la perception ne notifie qu'au gain/perte de vue), et `bCanSeePlayer=false` si aucun pawn.
│   ├── BP_AnimalAIController.uasset        → AIController, `AIPerceptionComponent` natif configurĂ© en Python (`AISenseConfig_Sight`, rayon 2500/3000, FOV 90°). `OnTargetPerceptionUpdated` relaie vers `AC_AnimalSenses` du pion possĂ©dĂ© (`ReportPlayerSighted`/`ReportPlayerLostSight` selon `Stimulus.WasSuccessfullySensed()`) — ne fonctionne QUE parce que le joueur porte un `AIPerceptionStimuliSourceComponent` (voir §1.3). (2026-09-14) Filtre ajoutĂ© : l'Ă©vĂ©nement ne relaie QUE si `Actor == GetPlayerPawn(0)` — sans lui, les autres animaux (pawns) perçus faisaient passer `bCanSeePlayer` Ă  vrai/faux et dĂ©clenchaient alertes/fuites entre cerfs. (2026-09-14) Le template `AIPerception` avait perdu son `AISenseConfig_Sight` (`SensesConfig = [None]` → aucune dĂ©tection) : recréé par Python (`unreal.new_object(AISenseConfig_Sight, outer=<template AIPerception_GEN_VARIABLE>)` via `SubobjectDataSubsystem`), rayon 2500/3000, angle pĂ©riphĂ©rique 90°, MaxAge 5, toutes affiliations. Le pawn joueur actuel (`SandboxCharacter_Mover`, pawn par dĂ©faut de `GM_Dev`) n'a pas de `AIPerceptionStimuliSourceComponent` mais est dĂ©tectĂ© via `AISense_Sight.bAutoRegisterAllPawnsAsSources` (vrai par dĂ©faut) ; en revanche il n'Ă©met PAS d'odeurs (`ScentFunct` n'existe que sur `SandboxCharacter_CMC`).
│   ├── BP_AnimalBase.uasset                → Character gĂ©nĂ©rique, base de TOUTE la faune. Composants : `Stats` (AC_Stats), `AnimalSenses` (AC_AnimalSenses), `StateTree` (StateTreeComponent, schema `StateTreeComponentSchema`, contexte = l'acteur lui-mĂȘme — PAS `StateTreeAIComponentSchema`, pour rester dĂ©tachĂ© de l'AIController et garder le StateTree simple). `AIControllerClass` = `BP_AnimalAIController`, `AutoPossessAI` = Placed in World or Spawned. Tunables instance-editable : WalkSpeed/RunSpeed, WanderRadius, IdleTime/GrazeTime/RestTime(Min/Max), AlertTime, FleeDistance (400-600 : distance de panique immĂ©diate si vu de prĂšs), SafeDistance (doit ĂȘtre largement > FleeDistance : distance Ă  atteindre pour se recalmer), HerdID (Name — animaux partageant le mĂȘme HerdID se relaient une alerte), DebugEnabled, Anim_Idle/Wander/Graze/Rest/Alert/Flee/Dead/Hit + Anim_RestEnter/Anim_RestExit (AnimSequence, un jeu Ă  fournir par espĂšce ; RestEnter/Exit optionnelles). Mouvement (2026-09-14) : `bOrientRotationToMovement=true`, `bUseControllerRotationYaw=false`, RotationRate 220, accĂ©lĂ©ration sur les chemins (`NavMovementProperties.bUseAccelerationForPaths`) ; mesh tournĂ© de Yaw −90 (les squelettes DeerStag/DeerDoe regardent +Y). Fonctions clĂ©s : `MoveTo`/`StopMovementAnimal` (wrappers autour de l'AIController cachĂ©, utilisĂ©s par les tĂąches StateTree), `SetCurrentState` (met Ă  jour l'Ă©tat, `bIsFleeing` (=Flee), `bInDeadState` (=Dead) et consomme `bHerdAlertReceived` Ă  l'entrĂ©e d'Alert/Flee — ne joue plus d'anim), animation (2026-09-14) : toujours **Single Node** (`SkeletalMeshComponent::PlayAnimation`, pas d'AnimBlueprint) mais pilotĂ©e par la VITESSE Ă  chaque tick via `DebugTick→UpdateAnimation` : course (`Anim_Flee`, play rate = vitesse/RunSpeed) au-delĂ  de (Walk+Run)/2, marche (`Anim_Wander`, play rate = vitesse/WalkSpeed) au-delĂ  de ~30, sinon `UpdateIdleAnimation` (Rest avec transitions RestEnter/RestExit verrouillĂ©es par `AnimLockUntil`, sinon `ApplyIdleForState` : Graze/Alert/Idle). `ApplyAnim(Anim, Loop, Rate)` ne relance l'anim QUE si elle change (`CurrentAnim`) — l'ancienne version relançait l'anim Ă  chaque changement d'Ă©tat. `PlayStateAnimation` n'est plus appelĂ©e (conservĂ©e, inutilisĂ©e), `GetThreatLocation` (position du joueur si vu, sinon source d'odeur, sinon position du pawn joueur, sinon position de l'animal), `BroadcastAlertToHerd`/`ReceiveHerdAlert` (alerte les autres membres du mĂȘme HerdID sans jamais lire une variable d'une AUTRE instance directement — le HerdID appelant est passĂ© en paramĂštre de fonction, voir piĂšge §9), `HandleDeath` (2026-09-14 : plus de ragdoll — `DisableMovement`, arrĂȘt du polling de vie, capsule en `NoCollision`, `Anim_Dead` jouĂ© une fois et figĂ© sur sa derniĂšre frame ; liĂ© Ă  `AC_Stats::OnDeath` via un Custom Event `OnAnimalDeathEvt` — PAS un binding direct sur une fonction classique, voir piĂšge §9), `CheckHealthChanged` (polling toutes les 0.2s de `AC_Stats::GetHealth` : une baisse de vie hors mort → `HandleDamaged` : `bWasHitRecently=true`, remis Ă  false par le timer `ClearHitFlag` 6s aprĂšs le dernier coup (auparavant JAMAIS remis Ă  false → fuite relancĂ©e Ă  chaque tick), anim `Anim_Hit` verrouillĂ©e 0.4s ; prĂ©fĂ©rĂ© Ă  un binding direct sur le dispatcher `AC_Stats::OnDamaged`, qui provoque une erreur interne du compilateur Blueprint dans ce projet, voir piĂšge §9).
│   ├── ST_AnimalBase.uasset                → StateTree partagĂ© par toute la faune (schema `StateTreeComponentSchema`, contexte = `BP_AnimalBase`). États : `Normal` (groupe) {Idle→Wander→Graze→Rest→Idle, cycle via transitions `OnStateCompleted`/`NextState`}, `Alert` (hĂ©site `AlertTime` secondes puis retourne Ă  Idle si la menace n'est pas confirmĂ©e — deny-timeout), `Flee` (fuite), `Dead` (terminal). Transitions clĂ©s, TOUTES en conditions liĂ©es par binding direct au contexte (`bind_transition_condition_property_to_context`, propriĂ©tĂ©s imbriquĂ©es type `AnimalSenses.bCanSeePlayer` — inclure le prĂ©fixe `b` des boolĂ©ens, voir piĂšge §9), aucune n'exige de Blueprint condition custom : `Normal→Alert` (vue OU odorat OU alerte de horde, combinĂ©es en OR via `set_transition_condition_operand`), `Normal→Flee` et `Alert→Flee` (prioritĂ© High : vu ET distance ≀ FleeDistance — "trop prĂšs, panique immĂ©diate"), `Flee→Normal/Idle` (distance ≄ SafeDistance ET plus vu ET `bWasHitRecently` faux — fuite minimale de 6s aprĂšs un coup, mĂȘme tirĂ© de loin), transitions globales posĂ©es sur `Root` (s'appliquent depuis N'IMPORTE quel Ă©tat actif) : `→Flee` (prioritĂ© High, `bWasHitRecently` ET pas mort ET `bIsFleeing` faux — sans cette derniĂšre condition, la transition rĂ©-entrait dans Flee Ă  chaque tick) et `→Dead` (prioritĂ© Critical, `bIsDead` ET `bInDeadState` faux — mĂȘme raison que `bIsFleeing` : sans elle, Dead Ă©tait rĂ©-entrĂ© Ă  chaque tick).
│   └── Tasks/                             → StateTree Tasks en Blueprint (parent natif `StateTreeTaskBlueprintBase`), chacune rĂ©utilisĂ©e par PLUSIEURS Ă©tats via ses propriĂ©tĂ©s instance-editable liĂ©es au contexte (`bind_task_property_to_context`) :
│       ├── STT_SetAnimalState.uasset       → Appelle `BP_AnimalBase::SetCurrentState(NewState)` et ne se termine JAMAIS (2026-09-14 : l'ancien `FinishTask` immĂ©diat, avec `TasksCompletion=Any`, terminait chaque Ă©tat dans la frame mĂȘme de son entrĂ©e → Idle→Wander→Graze→Rest bouclaient Ă  chaque frame, animaux immobiles et anims relancĂ©es en permanence ; `set_task_considered_for_completion(false)` n'a PAS suffi, voir §9). C'est la tĂąche Wait/Move de l'Ă©tat qui le termine. Un exemplaire par Ă©tat-feuille, seul `NewState` diffĂšre.
│       ├── STT_Wait.uasset                 → Attend une durĂ©e alĂ©atoire entre `MinTime`/`MaxTime` (liĂ©s au contexte : IdleTimeMin/Max, GrazeTimeMin/Max, RestTimeMin/Max, ou AlertTime/AlertTime pour une durĂ©e fixe). NĂ©cessite `should_call_tick_only_on_events = true` sur la classe (sinon `ReceiveLatentTick` n'est jamais appelĂ© — propriĂ©tĂ© peu intuitive, voir piĂšge §9).
│       ├── STT_MoveToRandomPoint.uasset    → UtilisĂ© par `Wander`. Tire un point via `NavigationSystem::GetRandomReachablePointInRadius` autour de `HomeLocation` (capturĂ©e une fois au spawn), appelle `BP_AnimalBase::MoveTo`, termine en arrivant (≀120 en XY), si l'animal est bloquĂ© (vitesse < 5 aprĂšs 1.5s) ou aprĂšs 25s ; `ExitState` arrĂȘte le mouvement (une alerte interrompt proprement la marche).
│       └── STT_MoveAwayFromThreat.uasset   → UtilisĂ© par `Flee`. À l'entrĂ©e : diffuse l'alerte Ă  la horde puis `IssueFleeMove` : point Ă  1500 dans la direction opposĂ©e Ă  `GetThreatLocation` (XY), projetĂ© sur le NavMesh (extent 300/300/1000), sinon point atteignable alĂ©atoire dans 1500 autour de l'animal. RĂ©-Ă©mis tant que l'Ă©tat Flee est actif dĂšs que l'animal arrive (≀200) ou est bloquĂ© (vitesse < 20 aprĂšs 1s) — c'est la transition du StateTree qui termine la fuite. `ExitState` arrĂȘte le mouvement.
│
│   EspĂšces (enfants de BP_AnimalBase, aucun nouvel asset graphique créé — rĂ©utilisent les meshes/anims
│   dĂ©jĂ  prĂ©sents sous Content/Characters/Animal/DeerStagAndDoe/ et Content/Animations/DeerAndDoe/) :
│   ├── BP_Deer_Stag.uasset                 → SK_DeerStag + jeu d'anims ANIM_DeerStag_* (RestEnter/Exit = GoToRest/RestToGoBackUp), HerdID "DeerHerd_A".
│   └── BP_Deer_Doe.uasset                  → SK_DeerDoe + jeu d'anims ANIM_DeerDoe_* (`Anim_Rest`=IdleRest, manquante avant le 2026-09-14), HerdID "DeerHerd_A" (mĂȘme horde que le cerf → rĂ©activitĂ© croisĂ©e via BroadcastAlertToHerd/ReceiveHerdAlert).
│
│   Une instance de chaque a Ă©tĂ© placĂ©e dans `Content/Maps/DevMap/MapDev1` avec un `NavMeshBoundsVolume`
│   (`NavMeshBounds_Wildlife`, RuntimeGeneration = Dynamic — le mode par dĂ©faut `Static` ne (re)gĂ©nĂšre
│   JAMAIS le NavMesh automatiquement, voir piùge §9). Étend le NavMesh existant du niveau (aucun n'existait
│   avant cette session).
│
├── Door/
│   ├── Garage_Door/BP_Garage_door.uasset → Porte de garage interactable
│   └── Simply_Door/BP_Simply_Door.uasset → Porte simple interactable
│
├── Movement/
│   ├── Climbing/AC_ClimbingComponent.uasset, CR_ClimbingGraphV2.uasset (Control Rig), CR_Mannequin_BasicFootIK.uasset, ClimbingMaterial.uasset
│   └── Cover/AC_Cover.uasset              → ActorComponent : systĂšme de couverture (cover system). GĂ©nĂ©rique (tout passe par `GetOwner`) : portĂ© par `SandboxCharacter_CMC` ET, depuis le 2026-09-18, par `SandboxCharacter_Mover` (voir §4.2.2). EntrĂ©e/sortie de couverture sur la touche **P** gĂ©rĂ©e dans le composant lui-mĂȘme ; `MoveAlongWall` fait un sphere trace le long du mur, `AddMovementInput` sur le pion et diffuse `OnEntreredCover` (InCover, direction `E_CoverD`, EdgeL/EdgeR).
│
├── Scent/BP_ScentPoint.uasset            → Point Ă©metteur d'odeur, spawnĂ© par `SandboxCharacter_CMC::ScentFunct` (toutes les 2s pendant que le joueur se dĂ©place) et consommĂ© par `AC_AnimalSenses::CheckScent` (Systems/Wildlife/, §4.4). (2026-09-05) Deux bugs corrigĂ©s Ă  la rĂ©utilisation par la faune : (a) `ScentFunct` ne crĂ©ait le point QUE via `SpawnActorFromClass`, sans jamais appeler son Ă©vĂ©nement `Custom|Create(life)` — la durĂ©e de vie (`TimeToLife`) restait donc Ă  0 ; ajout d'un appel explicite `Create(life=20.0)` juste aprĂšs le spawn. (b) Le dĂ©compte de durĂ©e de vie (`Custom|CustomEvent(DeltaTime)`) existait dĂ©jĂ  mais n'Ă©tait appelĂ© par PERSONNE (`BeginPlay` enregistrait l'acteur auprĂšs de `BP_TickManager` mais rien n'invoquait rĂ©ellement l'event) — le point ne s'auto-dĂ©truisait donc jamais ; ajout d'un `EventTick` natif qui appelle directement ce Custom Event (Ă©vite de toucher au brancher `BP_TickManager` partagĂ©, hors-scope). Comparaison de fin de vie durcie de `== 0` Ă  `<= 0` (float exact-equality fragile). Aucune nouvelle logique d'odeur créée — uniquement rĂ©paration du mĂ©canisme existant.
├── Movable_Object/BP_Moveble_Object.uasset → Objet physique dĂ©plaçable par le joueur
├── Interact_Interface.uasset             → Interface d'interaction gĂ©nĂ©rique (racine de Systems/, Ă  distinguer de BPI_Interactable dans Inventory/Interfaces/)
│
└── Weather/
    ├── Tornado/BP_Tornado.uasset, NS_Tornado.uasset   → Tornade dynamique (acteur + systĂšme Niagara), spĂ©cifique au projet (`NS_Tornado.uasset`, supprimĂ© du disque avant le 2026-09-13 sans commit, restaurĂ© depuis git le 2026-09-14 Ă  la demande de l'utilisateur)
    └── UltraDynamicSky/                  → đŸ§© **Asset marketplace tiers complet** (~789 fichiers : Blueprints, matĂ©riaux, sons, textures de ciel/mĂ©tĂ©o dynamique). Ne pas modifier directement ; utiliser ses points d'extension documentĂ©s par le plugin (Weather_Presets, Climate_Presets, Sky_Modifiers). Structure interne : Blueprints/ (Enum, Functions, Occlusion, Sky_Modifiers, Sound, System, Tools, Utilities, Weather_Effects, Widgets), Materials/, Meshes/, Particles/, Sound/, Textures/, Maps/ (map de dĂ©mo du plugin). Les systĂšmes Niagara `Particles/` (Snow, Dust, Wind_Debris, Radial_Storm, Puddle_FluidGrid, DLWE_Interaction_System, VolumetricCloud_LightRays, Actor_Exposure_Test, Standalone/Dripping_*) rĂ©fĂ©rençaient encore l'ancien chemin `/Game/UltraDynamicSky/Particles/UDW_Niagara_Parameters` / `UDS_VolumetricClouds_Niagara_Properties` : `[CoreRedirects]` ajoutĂ© dans `Config/DefaultEngine.ini` + re-sauvegarde des 10 systĂšmes (2026-09-14).
        ⚠ **Exception — code mĂ©tĂ©o PROPRE AU PROJET rangĂ© dans ce dossier tiers** (Ă  ne pas confondre avec le plugin) :
        ├── Blueprints/WB_WeatherControl.uasset → Acteur contrĂŽleur mĂ©tĂ©o (1 par map, porte UDS/UDW en ChildActor). Tick via `BP_TickManager` : fait avancer la saison (`DT_Season`, durĂ©e en minutes via `SeasonDurationScale`=60), puis si le joueur est dans une zone (`ActiveZone`) pousse la mĂ©tĂ©o de cette zone vers UDW, sinon `GetNearZone` choisit les 2 zones les plus proches (poids inversement proportionnels Ă  la distance) et `setWeatherbetweenZone` mĂ©lange leurs Ă©tats dans UDW.
        └── Blueprints/WB_WeatherZone.uasset   → Zone mĂ©tĂ©o (Box). `WeatherData` (ST_Weather_ZoneData : temp/humiditĂ©/vent/sable) = climat de base. `MakeForcast` gĂ©nĂšre 16 prĂ©visions (`ST_Weather_Zone_forecasts`, pas de 60–240 s via `ForecastStepMin/Max`) avec `makestate` (nuages `SetNuage`, tempĂ©rature `MakeTemp` tirĂ©e vers la moyenne de saison, neige/pluie/orage/vent/brouillard/poussiĂšre) ; `StepForecast(Delta)` interpole l'Ă©tat courant et rĂ©gĂ©nĂšre en fin de sĂ©quence ; `ApplyToUDW` pousse l'Ă©tat dans UDW ; `GetInflueZone` liste les zones voisines dans `InfluenceRadius` (15000 uu) non masquĂ©es (lissage entre zones via `GetZoneState`). Overlap filtrĂ© sur le pawn contrĂŽlĂ© par un joueur. Fonction `Trie zone` restĂ©e dans le BP mais plus appelĂ©e (2026-09-14).

5. Content/Data/ — Structures de donnĂ©es globales

Content/Data/
├── DataTable/DT_Season.uasset            → DataTable des saisons (mĂ©tĂ©o)
│
├── Enums/
│   ├── E_CoverD.uasset, E_WeaponType.uasset
│   ├── E_WaponType.uasset                → (2026-09-14, venu de `Characters/UEFN_Mannequin/Animations/Props/`) type d'arme lu par les choosers d'aim offset de `Systems/Aiming/` et par `S_CharacterPropertiesForAnimation.Weapon_Type` ; volontairement NON fusionnĂ© avec `E_WeaponType`
│   ├── Enums/E_BodyPart.uasset
│   └── Movement_enum/Weapon_Equip.uasset
│   (⚠ Ă  ne pas confondre avec Data/Inventory_Data/Enumerations/ ci-dessous — deux emplacements d'enums coexistent)
│
├── Structure/Weather/                    → Structs mĂ©tĂ©o (ST_Season, ST_WeatherZoneState, ST_Weather_Zone_CurentWeather/forecasts/_Data, ST_Zone_Influance)
│
└── Inventory_Data/                       → DonnĂ©es du systĂšme d'inventaire AGIS
    ├── DataAssets/
    │   ├── AttachmentData/               → AttachmentData (base) + AttachmentData_AdvancedRifle, AttachmentData_Flashlight : configuration des attachements d'armes
    │   ├── ContainerGroupData/           → Un DataAsset par "groupe de containers" (Backpack BIG/SMALL, Box/Chest Storage, Vest_1/2, ExampleStorage
) : dĂ©finit la mise en page des slots d'un contenant
    │   └── InventoryData/                → Un DataAsset par inventaire prĂ©dĂ©fini (PlayerInventory, PlayerInventoryPart1/2, CardReader_Inventory, Generator_Inventory, Vehicle_Inventory). `PlayerInventory` (2026-09-16) = inventaire du JOUEUR : widget `WB_InventoryPlayer`, containers = les 12 de PlayerInventoryPart1 puis les 3 de PlayerInventoryPart2 (mĂȘme ordre que `WB_InventoryPlayer::GetAllContainerWidgets`) ; le container 12 (poches) est en 4×3 / 12 slots depuis le 2026-09-17 pour correspondre Ă  `PocketContainer` (il Ă©tait en 2×2 → seule la 1re ligne Ă©tait utilisable ; `PlayerInventoryPart2`, utilisĂ© par le pillage, a toujours ce dĂ©faut). `PlayerInventoryPart1/2` restent utilisĂ©s par les PNJ/cadavres fouillables (`BP_Deadman`, `BP_EnemyPuppet` → `WB_LootingHuman`)
    ├── Enumerations/                     → Enums spĂ©cifiques AGIS : EAnimOverlayState, EBallDirections, EFourDirections/ETwoDirections, EInteractionType, EItemActions, ENestingRules, EPrintType, EReloadType, EServerVerificationType, ESlotAppearance, EVendorBuyOption
    └── Structures/                       → Structs spĂ©cifiques AGIS
        ├── ItemDefaults.uasset           → Struct CENTRALE dĂ©crivant un item (Name, etc.) — lue par WB_Item et par la logique de sĂ©lection rapide (Inventory_Player)
        ├── ItemInfo, SlotInfo, SlotAddress, SlotAppearance, SubItemInfo, RandomSubItem
        ├── ContainerInfo, ContainerAppearance
        ├── AttachmentInfo, EquipSlot_KeySettings/_OwnContainersSettings/_TextureSettings/_TitleSettings
        ├── ClientWidgetData, CombinedTexturesInfo, TextureInfo
        ├── CraftingSlotRowInfo, DragSounds, DebugPrint, FindResult, InspectCameraInfo, InteractCosmetics, ItemActorInfo, MenuActions
        └── SaveStructures/SaveData_Player, SaveData_Storages, Savedata_ItemActor   → Structures de sauvegarde (non encore branchĂ©es Ă  un vrai systĂšme de save, voir §1.3 du systĂšme de mort)

6. Content/UI/ — Interfaces utilisateur

Content/UI/
├── Inventory_UI/                         → TOUTE l'UI de l'inventaire (socle AGIS + ajouts projet)
│   ├── MaterialResources/                → MatĂ©riaux/Material Instances de fond des slots (MI_Background_*, M_RuntimeItemMaterial
)
│   └── Widgets/
│       ├── WB_Container.uasset           → Widget reprĂ©sentant un container (grille de slots) — contient SlotWidgets[]. `CreateSlots` construit la grille d'aprĂšs la `Container Size` DU WIDGET (les SlotInfo du DataAsset doivent avoir la mĂȘme taille, sinon seules les premiĂšres cases sont utilisables). `GetParentEquipSlot` (corrigĂ© le 2026-09-17) ne renvoie l'EquipSlot englobant (Outer.Outer) que si ce container EST son `Container` principal : les sous-containers d'un sac/gilet affichĂ©s ailleurs (sous les poches) gardent leur taille et leurs cases de 75 px au lieu d'ĂȘtre rĂ©duits Ă  1×1 en taille d'EquipSlot
│       ├── WB_EquipSlot.uasset           → Widget d'un slot d'Ă©quipement (arme/speed) — contient Container. Var `OwnContainersHost` (2026-09-04, typĂ©e `WB_InventoryPlayer` depuis 2026-09-16) : si dĂ©finie, `OnContainerUpdate` ajoute les sous-containers de l'item Ă©quipĂ© (ex. grille du sac Ă  dos) dans ce widget via `AddContainerBelowPockets` au lieu de son propre `ContainersCanvas` interne. CĂąblĂ©e uniquement pour `EquipSlotBACKPACK` par `WB_InventoryScreen::InitializeWidgets`.
│       ├── WB_InventorySlot.uasset       → Widget d'un slot individuel dans une grille — expose "ItemWidget On Slot"
│       ├── WB_Item.uasset                → Widget reprĂ©sentant un item posĂ© dans un slot — expose "Item Defaults" (struct ItemDefaults)
│       │
│       ├── InventoryMenu/
│       │   ├── WB_InventoryScreen.uasset → Widget racine de l'inventaire plein Ă©cran. Depuis 2026-09-16 contient un seul panneau joueur `Part2Box → OutlinePart2 → BackgroundPart2 → InventoryPlayer` (WB_InventoryPlayer : Ă©quipements Ă  gauche, poches + sac Ă  dos dĂ©filants Ă  droite ; plus de ScrollBox extĂ©rieur depuis 2026-09-17, sinon la colonne de droite n'a pas de hauteur bornĂ©e) ; `InitializeWidgets` initialise `InventoryPlayer` et cĂąble `EquipSlotBACKPACK.OwnContainersHost = InventoryPlayer`. `Inventory_Player::GetQuickSlotItemInfo` lit les slots WEAPON/WEAPON2/Speed1/Speed2 via `InventoryScreen.InventoryPlayer`. **Overlay personnage (2026-09-21)** : `Border_184` (→ `Overlay_261` : portrait `Image_163`, textes h/hunger, `WB_stat_player_Body`) est repliĂ© (`Collapsed`) dĂšs qu'un inventaire tiers est ouvert (corps, coffre, feu de camp
) : `CreateLootingWidget` appelle `HideCharacterOverlay` aprĂšs avoir affichĂ© `LootWindow` ; `ShowCharacterOverlay` (appelĂ© aprĂšs `AddToViewport` dans `ToggleScreen` et dans `Clear Looting Widget Panel`) le remet `Visible` seulement si `LootWindow` n'est pas visible (une fermeture sans fondu laisse le panneau de loot en place — comportement d'origine)
│       │   ├── WB_InventoryPlayer.uasset → (2026-09-16) Fusion de WB_InventoryPart1 + WB_InventoryPart2 pour l'inventaire du joueur, dans un seul cadre en deux colonnes (2026-09-17) : `EquipsVertical` → `ColumnsBox` (HorizontalBox, Fill) → [`EquipSlotsBox` (SizeBox 760×866) → `SlotsCanvas` avec les 12 EquipSlots] + [`PocketsScroll` (ScrollBox, barre visible) → `VerticalBox_0` (titre Pockets + `PocketContainer`, puis les containers du sac Ă  dos ajoutĂ©s dessous par `Add Container Below Pockets`)]. `EquipSlotBACKPACK` et `EquipSlotVEST` ont `Item Containers Settings.ShowInventory = True` et `OwnContainersHost = InventoryPlayer` (cĂąblĂ© dans `WB_InventoryScreen::InitializeWidgets`) (dĂ©faut de WB_EquipSlot = False : sans ça, `OnContainerUpdate` ne crĂ©e jamais les grilles du sac). `GetAllEquipSlots` = mĂȘme ordre que Part1 ; `GetAllContainerWidgets` = containers des Ă©quipements puis PocketContainer. DonnĂ©es : DataAsset `PlayerInventory`
│       │   ├── WB_InventoryPart1.uasset  → (utilisĂ© seulement par WB_LootingHuman depuis 2026-09-16) Contient les 4 slots d'Ă©quipement (EquipSlotWEAPON, EquipSlotWEAPON2, EquipSlotSpeed1, EquipSlotSpeed2) + autres slots d'Ă©quipement (casque, gilet, gants, sac Ă  dos
)
│       │   └── WB_InventoryPart2.uasset  → (utilisĂ© seulement par WB_LootingHuman depuis 2026-09-16 ; sa fonction `Add Container Below Pockets` n'est plus appelĂ©e, WB_EquipSlot pointe dĂ©sormais WB_InventoryPlayer) Grille(s) d'inventaire principale(s) (PocketContainer + titre, dans `VerticalBox_0`). Fonction `Add Container Below Pockets(Container)` (2026-09-04) : insĂšre un WB_Container juste aprĂšs le bloc Pockets (`PocketContainer.GetParent().GetParent()`) — utilisĂ©e par `WB_EquipSlot` (sac Ă  dos) pour afficher ses slots supplĂ©mentaires sous les slots Pocket plutĂŽt que dans son propre canvas.
│       │
│       ├── ItemActionsMenu/WB_ItemMenu.uasset, WB_GeneralButton.uasset   → Menu contextuel d'actions sur un item
│       │
│       ├── LootWidgets/                  → FenĂȘtres de pillage, une par type de source (Human, Storage, Vendor, Vehicle, Generator, KeycardReader) hĂ©ritant de _WB_LootWidgetBASE ; LootingCrafting/ pour les stations de craft
│       │
│       ├── MovableWindows/               → SystĂšme de fenĂȘtres dĂ©plaçables (_WB_Window_Base) : ItemInspect/ (inspection 3D d'un item), ItemInventory/ (fenĂȘtre d'inventaire flottante), WB_TitleBar_Window (barre de titre commune)
│       │
│       └── Other/
│           ├── WB_QuickSelect.uasset     → 🆕 Roue de sĂ©lection rapide (4 slots : Arme1/Arme2/Speed1/Speed2 + "Aucun"). RĂ©sout seule son Inventory_Player propriĂ©taire au Construct (GetOwningPlayerPawn → GetComponentByClass). Ouverte/fermĂ©e depuis Inventory_Player (touche V maintenue). Le graphe `INPUTS` d'Inventory_Player bascule aussi Input Mode/curseur/Ignore Look Input Ă  l'ouverture/fermeture (mĂȘme pattern que `ToggleInventory`) — fix du 2026-09-04. **Cause rĂ©elle du bug (2026-09-04, deuxiĂšme fix)** : IA_QuickSelectAGIS/IA_QuickEquipAGIS (touches V/B) n'Ă©taient mappĂ©es QUE dans `IMC_AGIS_Character` (Systems/Inventory/Other/Inputs/), un Input Mapping Context jamais ajoutĂ© au joueur nulle part dans le projet (seule une variable `Input Mapping Context` orpheline sur Inventory_Player y faisait rĂ©fĂ©rence, sans AddMappingContext associĂ©) — donc l'input V n'atteignait mĂȘme pas l'Enhanced Input, avant tout problĂšme de widget. Fix : V et B ajoutĂ©s directement dans `IMC_Sandbox` (Core/PlayerController/Input/), l'unique IMC rĂ©ellement ajoutĂ© au joueur (via SandboxCharacter_CMC/SetupInput). `IMC_AGIS_Character` reste inutilisĂ©e — Ă  nettoyer/fusionner un jour si confirmĂ© obsolĂšte.
│           ├── WB_QuickGive.uasset       → 🆕 (2026-09-05) Menu debug "Quick Give" (touche F9, mappĂ©e dans `IMC_Sandbox` via `IA_QuickGiveAGIS`). Champ Item ID + Amount + bouton "Give" gĂ©nĂ©rique, plus des boutons raccourcis "Give Bow"/"Give 20 Arrows". Fonction `GiveItem(ItemID, Amount)` : rĂ©sout l'`Inventory_Player` du joueur possĂ©dant (`GetOwningPlayerPawn`+`GetComponentByClass`), construit un item via `FL_AGIS::Create Item Structure`, trouve un slot libre via `Inventory__Main::Find Space For Item`, puis le pose via `Inventory__Main::Set Item On Container` — mĂȘme chaĂźne AGIS bas niveau que celle utilisĂ©e en interne par `Reload Graph` de `BP_Item_AdvancedRifle`. Toggle (crĂ©er/`AddToViewport`+InputMode GameAndUI vs `RemoveFromParent`+InputMode GameOnly) cĂąblĂ© dans `SandboxCharacter_CMC::EventGraph` sur `IA_QuickGiveAGIS` (Started), variable `QuickGiveWidget` sur le Character. Outil de test, pas une fonctionnalitĂ© shippable.
│           ├── WB_YouDied.uasset         → Écran "Vous ĂȘtes mort" (systĂšme de mort/respawn)
│           ├── WB_ActionScreen, WB_InteractScreen, WB_InteractBall, WB_PickupDisplay   → Feedback d'interaction/pickup au sol
│           ├── WB_CombatHUD, WB_DisplayHUD, WB_WeaponAmmoInfo   → HUD de combat/munitions
│           ├── WB_InventoryBackground, WB_ItemInfo, WB_SlotTitle   → ÉlĂ©ments visuels d'appoint
│           └── WidgetTextures/           → IcĂŽnes des slots d'Ă©quipement (T_EquipSlot_*) et textures d'UI diverses
│
├── TextureUI/M_CharacterUI.uasset, RT_CharacterView.uasset   → Rendu de la vue personnage dans l'UI (ex. Ă©cran d'inspection du personnage)
│
└── Widgets/                              → UI HORS inventaire
    ├── HUD/WB_HUD.uasset, WB_New_HUD.uasset, WB_New_InterfacePlayer.uasset
    ├── PauseMenu/WBP_PauseMenu.uasset, WBP_Options.uasset
    └── interaction/WB_Interact.uasset

7. Content/Items/, Content/PCG/, Content/Maps/, Content/VFX/, Content/Prop/

Content/Items/                            → Objets ramassables/Ă©quipables du jeu
├── BaseBlueprints/
│   ├── _BP_ItemBase.uasset               → Blueprint BASE de tout item (racine de hiĂ©rarchie). Event `Custom|UpdateCollisionandPhysics` (appelĂ© Ă  l'attache/au drop) bascule aussi la rĂ©ponse au canal `Visibility` (Ignore quand Ă©quipĂ© / Block quand lĂąchĂ©) du mesh principal ET de tous les `WidgetComponent` de l'item (ex. `AmmoUI`) — fix du 2026-09-04 : un item Ă©quipĂ© bloquait les BoxTrace (canal Visibility) du systĂšme de grimpe/parkour (`AC_ClimbingComponent`), empĂȘchant de grimper une fois une arme en main.
│   ├── BP_Item_HoldableBase.uasset       → Base des items tenables en main. ImplĂ©mente `BPI_HoldableItem::On Item Attached(ShouldHold)` (seul signal fiable du VRAI Ă©tat main/pas-en-main) et diffuse ce boolĂ©en via son propre dispatcher `OnHeldStateChanged(bIsHeld)` (2026-09) — c'est CE dispatcher (et non `_BP_ItemBase::OnOwnerChanged`, qui se dĂ©clenche aussi pour un simple rangement en inventaire) qu'`AC_Weapon` Ă©coute pour piloter Equip/Unequip, voir §4.3.
│   ├── BP_Item_Armor_Base.uasset         → Base des items d'armure/Ă©quipement portĂ©
│   ├── BP_Item_Skeletal_Base.uasset      → Base des items avec mesh squelettal
│   └── BP_Item_OutfitPiece_Base.uasset   → (2026-09-21) Base des vĂȘtements MetaHuman Ă©quipables (hĂ©rite `BP_Item_Armor_Base`). `ItemMesh_STATIC` (tag ItemMeshAGIS = mesh au sol) + `OutfitCloth` (ChaosClothComponent, asset `OA_SurvivorOutfit`, cachĂ© par dĂ©faut). BeginPlay → `SetupOutfitBinding` (ignorĂ© pour les acteurs de prĂ©visualisation d'icĂŽne) : s'abonne Ă  `OnOwnerChanged` → `RefreshOutfit`, puis `ApplyVisibleSlots`. `RefreshOutfit` : avec propriĂ©taire, attache `OutfitCloth` au mesh enfant du ChildActorComponent taguĂ© `VisualOverride` (le `Body` du MetaHuman ; Ă  dĂ©faut le 1er SkeletalMeshComponent du pion) + `SetLeaderPoseComponent`, montre le cloth, cache le mesh statique ; sans propriĂ©taire, l'inverse. `ApplyVisibleSlots` : si `VisibleMaterialSlots` (Name[]) n'est pas vide, remplace le matĂ©riau de chaque autre slot par `M_OutfitPieceHidden` → une piĂšce = mĂȘme tenue complĂšte dont on n'affiche que ses matĂ©riaux. CoĂ»t : chaque piĂšce Ă©quipĂ©e simule la tenue entiĂšre (3 simulations cloth si les 3 sont portĂ©es). ⚠ Tenue taillĂ©e pour le corps `Bof2` : la peau du MetaHuman `test` traverse le pantalon aux cuisses (correctif propre = garde-robe du MetaHuman Creator).
│
├── BP_Item_AdvancedRifle / _Backpack_Camper / _Backpack_Sport / _BodyArmor / _Flashlight /
│   _Gloves / _Helmet / _KevlarVest / _LightVest / _Siren / _Bow.uasset     → Blueprints d'items "portĂ©s" (racine d'Items/). `BP_Item_Bow` (hĂ©rite `BP_Item_HoldableBase`) porte un composant `ItemMesh_STATIC` (mesh Fab `survival_kit_bow_fixed` — voir §8 pour l'incident de corruption/rĂ©-import du 2026-09-05 —, socket `ArrowSocket` ajoutĂ© pour l'encoche — position approximative, Ă  ajuster visuellement), Ă©quipĂ© sur le socket `weapon_l` (Spine `SpineRifle`, rĂ©utilisĂ© faute de socket dĂ©diĂ©). `BP_Item_AdvancedRifle` a reçu le mĂȘme composant `AC_Weapon` (2026-09-05, retrofit de validation) pour l'Ă©quipement/dĂ©sĂ©quipement gĂ©nĂ©rique ; sa cadence de tir reste pilotĂ©e par sa propre macro interne `Weapon|FiringGate` (non branchĂ©e sur `AC_Weapon.CanUse()` — dette technique documentĂ©e, voir §9).
│
│   **Gameplay de l'arc** (`BP_Item_Bow`, 2026-09-05/06) — override des hooks existants `Custom|PrimaryUse`/`StopPrimaryUsing` de `_BP_ItemBase`, sans nouveau systĂšme d'input : `PrimaryUse` vĂ©rifie `AC_Weapon->CanUse()` ET `CountArrows() >= 1` (fonction propre, voir §1.3 pour `Owner Inventory`) avant de dĂ©marrer la tension (horodatage `DrawStartTime`, pas de Timeline), puis joue `Draw Montage` (`AM_Bow_Draw`, voir ci-dessous) sur le mesh du personnage. `StopPrimaryUsing` calcule la puissance (`Clamp((Now-DrawStartTime)/MaxDrawTime, MinDrawPower, 1.0)`), joue `Fire Montage` (`AM_Bow_Fire`), appelle `ConsumeArrow()` et, si rĂ©ussi, spawn `BP_Projectile_Arrow` au socket `ArrowSocket` avec vitesse/dĂ©gĂąts scalĂ©s par la puissance, puis appelle `AC_Weapon->TryUsePrimary()`.
│   **`ConsumeArrow()` — fix du 2026-09-06** : retrouve le stack "Arrow" via `BOTH|FindItem`, puis rĂ©duit son montant via `Inventory__Main::AddItemAmount(ItemAddress, -1)` — une opĂ©ration purement sur les DONNÉES de l'inventaire, par adresse, ne nĂ©cessitant aucun acteur monde. L'implĂ©mentation d'origine appelait `Utilities|GetItemActor` (macro `ML_InventoryMacros::Get Item Actor`) puis `SERVER|ReduceAmount` sur cet acteur — ce qui Ă©choue TOUJOURS silencieusement pour un item empilĂ© passif comme "Arrow" qui, tant qu'il n'est pas Ă©quipĂ©/lĂąchĂ© dans le monde, n'a jamais d'acteur spawnĂ© (`GetItemActor` retourne systĂ©matiquement invalide). SymptĂŽme observĂ© : le tir semblait dĂ©marrer (logs "TIR EN COURS") mais aucune flĂšche ne partait et aucune munition n'Ă©tait consommĂ©e. Voir aussi §9 pour la mĂȘme leçon appliquĂ©e Ă  toute consommation de stock passif (ne jamais utiliser `GetItemActor`+fonction-sur-acteur pour un item qui n'est pas garanti d'ĂȘtre spawnĂ© dans le monde — utiliser `Inventory__Main::AddItemAmount` par adresse Ă  la place).
│   **Animations de l'arc** (2026-09-06) — `AM_Bow_Draw`/`AM_Bow_Fire.uasset` (`Content/Items/`) sont des `AnimMontage` Ă  piste unique gĂ©nĂ©rĂ©s depuis `standingdrawarrow_UE`/`standingaimrecoil_UE` (`Content/Animations/humain/Armed_mov/Bow/`), assignĂ©s au **slot `UpperBody`** (voir `SandboxCharacter_CMC_ABP` ci-dessous — PAS `DefaultSlot`). Variables `Draw Montage`/`Fire Montage` sur `BP_Item_Bow`, jouĂ©es via un nƓud natif `Animation|Montage|PlayMontage` sur le mesh du personnage (`Cast Owner Character → Character → GetMesh`). Appel direct (pas de variante Multicast `...CLIENTS` comme pour `PlayReloadMontageCLIENTS` du fusil) — suffisant en PIE solo ; Ă  revoir si une rĂ©plication multijoueur de l'anim est nĂ©cessaire plus tard.
│   **IntĂ©gration Ă  la locomotion (2026-09-06)** — un montage plein-corps sur `DefaultSlot` remplaçait TOUT le squelette (jambes comprises) par la pose figĂ©e de l'animation source, ce qui semblait correct Ă  l'arrĂȘt (la pose "debout" du montage coĂŻncide avec Motion Matching Ă  l'arrĂȘt) mais cassait la marche/course/crouch (jambes figĂ©es dans la pose d'arc "debout" enregistrĂ©e). Fix : ajout d'un **`Slot 'UpperBody'`** + nƓud **`Layered Blend Per Bone`** dans l'`AnimGraph` de `SandboxCharacter_CMC_ABP`, avec un filtre de branche sur l'os `spine_01` (BlendDepth=-1 → toute la branche colonne+bras+tĂȘte, jambes/bassin exclus) — voir §9 pour le dĂ©tail technique (le skeleton `SK_UEFN_Mannequin` avait dĂ©jĂ  un Blend Profile "UpperBody" masquant exactement les mĂȘmes os, confirmant que `spine_01` est le bon point de coupure, mais ce Blend Profile n'est pas directement utilisable par ce nƓud en 5.8 — filtre de branche manuel utilisĂ© Ă  la place). Le `DefaultSlot` existant (plein corps) n'est pas touchĂ©, rĂ©utilisable tel quel pour de futures actions plein-corps. Motion Matching, Pose Search, Aim Offset (`Enable_AO`/`Get_AOValue`), Foot/Leg IK et Orientation Warping — tous dĂ©jĂ  prĂ©sents dans cet AnimBP — continuent de piloter le bas du corps et la visĂ©e sans changement.
├── BP_Item_SurvivorOutfit_Top / _Pants / _Boots.uasset → (2026-09-21) Les 3 piĂšces de la tenue MetaHuman « SurvivorOutfit », enfants de `BP_Item_OutfitPiece_Base`. Lignes DT_Items `SurvivorOutfit_Top` (`Human.Body` → EquipSlotBODY, partagĂ© avec BodyArmor), `SurvivorOutfit_Pants` (`Human.Pant` → EquipSlotPANTS), `SurvivorOutfit_Boots` (`Human.Shoes` → EquipSlotSHOES) ; icĂŽnes gĂ©nĂ©rĂ©es au runtime. Chaque enfant ne fixe que `VisibleMaterialSlots` (Top = MI_Survivor_Coat + MI_Survivor_Tshirt, Pants = MI_Survivor_Pant, Boots = MI_Survivor_Boot) et l'override du mesh au sol `ItemMesh_STATIC` (SM_SurvivorOutfit_Coat/Pant/Boot). `BP_Spawner5` de MapDev1 pointe sur `SurvivorOutfit_Top`.
├── Attachments/BP_Item_MagazineBase, BP_Item_RifleFlashlight, BP_Item_Suppressor.uasset  → Attachements d'armes
├── ItemObjects/BPI_MergeableItemObject, ItemObject__BASE, ItemObject_ConsumableBASE, ItemObject_Magazine.uasset  → Objets "monde" associĂ©s aux items (empilables, consommables, munitions)
│
├── Ammo/ (Arrow), Weapon/ (Base_Bow, Base_knife), Tool/ (saucepan), Water/ (water_bottle),
│   Food/ (Red_Apple, meat, cooked_Meat, Burnt_Meat), Resource/ (Stick, Stone)
│   → Chaque sous-dossier contient les assets (mesh/matĂ©riau/texture/Thumbnail) d'un item ; les Blueprints correspondants sont soit Ă  la racine d'Items/, soit dans Resources/. `Weapon/Base_Bow/Thumbnail` et `Ammo/Arrow/Thumbnail` ne contenaient que des icĂŽnes prĂ©parĂ©es Ă  l'avance (2026-09-04) — item "Bow" et "Arrow" ajoutĂ©s dans DT_Items pour les utiliser (voir §5).
│
├── Resources/                            → Assets 3D (mesh/matĂ©riau/texture) groupĂ©s par Ă©quipement portĂ©, + cas particuliers
│   ├── Backpack_Camper/, Backpack_Sport/, BodyArmor/, Gloves/, Helmet/, KevlarVest/, LightVest/, Rifle/
│   ├── Outfits/M_OutfitPieceHidden.uasset → (2026-09-21) MatĂ©riau masquĂ© Ă  opacitĂ© 0, utilisĂ© par `BP_Item_OutfitPiece_Base` pour cacher les piĂšces d'une tenue qui n'appartiennent pas Ă  l'item
│   ├── _Others/                          → Assets des petits objets (Keycard, Log, Meat, AmmoBox, Battery, Flashlight, FuelCanister, GoldIngot/GoldOre, Headphone, MoneyBag, WaterBottle)
│   └── ABP_SkeletalEquippables.uasset    → Anim Blueprint partagĂ© par les items squelettaux Ă©quipĂ©s
│
└── ItemTextures/                         → Textures d'icînes/inventaire communes à tous les items (T_*)

Content/PCG/                              → GĂ©nĂ©ration procĂ©durale de contenu (plugin PCG)
├── Road/
│   ├── PCG_Road.uasset                   → Graphe PCG gĂ©nĂ©rant la route procĂ©durale (matĂ©riaux vieillis/mousse/humiditĂ©, potholes via GeometryScript)
│   ├── BP_AbandonedRoad.uasset           → Acteur portant le graphe PCG
│   ├── M_Road.uasset, ST_Road_data.uasset, EM_Road_Type.uasset   → MatĂ©riau, struct de donnĂ©es et enum de types de route
├── Vegetation/TreeTest.uasset            → Graphe PCG de placement de vĂ©gĂ©tation (arbres, gĂ©nĂ©rĂ©s via PVE pour la route)
└── test/NewPCGGraph1.uasset              → Graphe de test/brouillon

Content/Maps/DevMap/
├── MapDev1.umap                          → đŸ—ș Map de dĂ©veloppement PRINCIPALE (GameDefaultMap / EditorStartupMap, voir Config/DefaultEngine.ini)
├── GM_Dev.uasset                         → GameMode utilisĂ© sur MapDev1 (hĂ©rite directement de GameModeBase, indĂ©pendant de GM_Sandbox/Gamemode_AGIS)
├── pcg_Test_Dev.umap                     → Map de test PCG
└── PCG_Test_Dev_HLODLayer_*, Untitled_HLOD0_Instancing.uasset   → Assets HLOD gĂ©nĂ©rĂ©s pour les maps de test

Content/VFX/
├── Firetrail/BP_FireTrail.uasset, Effects/P_BulletTrail.uasset, Materials/M_BulletTrail.uasset   → TraĂźnĂ©e de balle
└── MI_MuzzleFlash, M_MuzzleFlash, MuzzleFlash, P_MuzzleFlash   → Effet de tir (bouche de canon)
├── M_Blood.uasset, T_Blood.uasset        → Effet de sang
└── crosshair.uasset, hitmarker.uasset    → ÉlĂ©ments de HUD de tir

Content/Prop/Wooden_Door/                 → Prop de porte en bois (mesh + matĂ©riaux), utilisĂ© par les BP de porte interactable

8. Assets tiers / bibliothĂšques (peu ou pas de logique de gameplay)

Ces dossiers contiennent des assets achetĂ©s/importĂ©s (Marketplace, Fab/Quixel Megascans, Megaplant, packs d'animation mocap). Ils sont volumineux (des centaines de fichiers) et ne sont volontairement pas dĂ©taillĂ©s fichier par fichier ici — voir §10 pour la rĂšgle sur quand les documenter.

Content/Animations/          → Clips de mocap tiers : DeerAndDoe/, Fox/, Wolf/, humain/ (Armed_mov, Avoid, Carrying, Cover,
                                Effect_Animation, INteraction, Prone, Push, SwimmingAnimation
)
Content/Characters/          → Meshes/matĂ©riaux/textures des personnages et animaux (Animal/DeerStagAndDoe|Fox|Wolf,
                                UEFN_Mannequin/ avec ses données de Motion Matching : AimOffset, Crouch, Idle, Jump,
                                MotionMatchingData/ [Channels, Databases, Normalization_Sets, Schemas], Poses, Run, Slide,
                                Sprint, Traversal, Walk, Rigs, Materials, Meshes, Textures)
Content/Fab/                 → Assets Fab/Quixel Megascans : MaterialFunctions/, MaterialParameterCollection/, Materials/
                                (Standard/VT), Megascans/Plants/ (Common_Hemp_Nettle, Wild_Grass ×2), Megascans/Surfaces/
                                (Damaged_Asphalt, Dirt_Ground, Forest_Floor), Textures/ (Standard/VT)
                                MetaHuman/ (2026-09-21) : tenue MetaHuman « SurvivorOutfit » (manteau+t-shirt+pantalon+bottes)
                                — `OA_SurvivorOutfit` (ChaosOutfitAsset, 4 slots de matĂ©riaux = 4 piĂšces, portĂ© par `BP_Item_OutfitPiece_Base` et ses 3 enfants, §7),
                                `WI_OA_SurvivorOutfit` (Wardrobe Item du MetaHuman Creator), cloth assets/Dataflow,
                                SM_SurvivorOutfit_Coat/Pant/Boot (meshes statiques, servent d'objet au sol), textures.
                                Le SkeletalMesh `bodyShapeBof2_CombinedSkelMesh` est le CORPS de référence du fitting, pas la tenue.
                                Survival_Kit_-_Bow/ et CC0_-_Wooden_Arrow/ (StaticMesh + Textures + MI_SurvivalBow/MI_WoodenArrow,
                                utilisĂ©s par les items Bow/Arrow, voir §4.4) — ⚠ ces deux imports glTF avaient leurs slots de
                                matériau pointant vers un `MaterialInstanceDynamic` transitoire (jamais sauvegardable, cause
                                d'échecs d'auto-save « Illegal reference to private object »). Corrigé le 2026-09-04 en créant de
                                vraies `MaterialInstanceConstant` (parent `/InterchangeAssets/gltf/Substrate/M_GLTF`) avec les
                                mĂȘmes textures. Si un futur import Fab/glTF Ă©choue Ă  l'auto-save de la mĂȘme façon, vĂ©rifier le(s)
                                slot(s) de matĂ©riau du StaticMesh importĂ© pour ce mĂȘme symptĂŽme.
                                ⚠ **2026-09-05** : aprĂšs une coupure de courant, `survival_kit_bow.uasset` (StaticMesh) s'est retrouvĂ©
                                avec 0 vertex/0 triangle/bounds nuls (asset vidé, probablement une sauvegarde tronquée en cours
                                d'Ă©criture) — l'arc n'avait plus de mesh visible ni de collision en jeu. Diagnostic : toujours
                                vérifier `mesh.get_num_vertices(0)` / `get_bounds()` aprÚs une fermeture anormale de l'éditeur sur
                                un asset suspect avant de chercher ailleurs. Fix : ré-import depuis la source Fab d'origine
                                (chemin retrouvé via `mesh.get_editor_property("asset_import_data").extract_filenames()`, cache
                                `%LOCALAPPDATA%/Temp/FabLibrary/<guid>/`) vers un dossier scratch, puis renommage vers
                                `.../StaticMeshes/survival_kit_bow_fixed` (le nom d'origine `survival_kit_bow` n'a pas pu ĂȘtre
                                réutilisé : `delete_asset`/`consolidate_assets` échouaient silencieusement sur l'asset corrompu
                                malgrĂ© 0 rĂ©fĂ©renceur restant — laissĂ© orphelin en l'Ă©tat, sans danger). Toutes les rĂ©fĂ©rences
                                (`BP_Item_Bow::ItemMesh_STATIC`, `DT_Items` ligne "Bow" → `Spawner Preview Mesh`) repointĂ©es vers
                                `survival_kit_bow_fixed`. Le socket `ArrowSocket` a dĂ» ĂȘtre recréé (perdu avec l'ancien asset).
Content/Megaplant_Library/   → VĂ©gĂ©tation Megaplant : Plant_Bilberry/, Tree_European_Aspen/, Tree_Hornbeam/
                                (chacun avec Instances/, Materials/, Textures/)
Content/Audio/Foley/         → **(2026-09-08)** Systùme de sons de pas/foley du sample Game Animation Sample :
                                `AC_FoleyEvents` (ActorComponent, ajouté à `SandboxCharacter_Mover`, voir §8.2),
                                `S_FoleyEventParams`, `DefaultFoleyEventAudioBank`. Reste du dossier `Content/Audio/` :
                                sons/bancs audio divers du sample, non branchés sur le gameplay AGIS.
Content/MetaHumans/ et Content/Characters/Echo|Paragon|UE4_Mannequin|UE5_Mannequins/  → **SUPPRIMÉS le 2026-09-13**
                                (nettoyage) : assets MetaHuman et personnages de démonstration du sample Game Animation
                                Sample (~2,6 Go), utilisés uniquement par les BP de démo `RetargetedCharacters/BP_*`
                                (supprimés aussi). Copie de sauvegarde : `E:\projet\ProjectFv1_backup_migration_2026-09-13\nettoyage_etape1_demo\`.
                                `UEFN_Mannequin` reste le seul squelette de personnage humanoĂŻde du projet.
Content/Levels/, Content/Widgets/, Content/dev_map  → **SUPPRIMÉS le 2026-09-14** : dĂ©mo du sample Game Animation Sample (kit de blockout
                                LevelPrototyping, widgets et map de démo). Seul lien avec le projet : le cast vers
                                `LevelBlock_Traversable` dans `Systems/Mover/AC_TraversalLogic`, retiré (voir §4.2.1).
                                Sauvegarde : commit git `6eb7516`.
Content/Thumbnails/          → Miniatures gĂ©nĂ©rĂ©es pour la Content Browser
Content/Misc/                → SandboxAnimCurveCompressionSettings.uasset (rĂ©glages de compression d'anim)
Content/__ExternalActors__/  → ⚙ GĂ©nĂ©rĂ© automatiquement par World Partition (donnĂ©es par-acteur des maps, ex. LocomotionAnimPack).
Content/__ExternalObjects__/ → ⚙ GĂ©nĂ©rĂ© automatiquement par World Partition (objets externes liĂ©s aux maps).
                                → Ces deux derniers dossiers ne doivent JAMAIS ĂȘtre Ă©ditĂ©s ou documentĂ©s Ă  la main :
                                  leur contenu suit automatiquement les maps et les acteurs qu'elles contiennent.

8.1 Import du sample Epic "Game Animation Sample" (2026-09-07/08)

L'utilisateur a importĂ© le contenu brut du sample officiel Epic Game Animation Sample directement dans Content/Blueprints/ (structure de dossier d'origine du sample), dans le but de disposer d'une rĂ©fĂ©rence complĂšte/fonctionnelle du framework "Sandbox Character" (voir §4.2) pendant que sa migration vers le plugin Mover Ă©tait en cours. Ce sample est la source originelle du framework Systems/Blueprints/ dĂ©jĂ  prĂ©sent dans ce projet : l'import a donc créé 95 collisions de nom exactes (mĂȘmes noms : SandboxCharacter_CMC, AC_TraversalLogic, BP_MovementMode_Walking, E_Gait, IMC_Sandbox, tous les IA_* gĂ©nĂ©riques, etc.) entre le contenu fraĂźchement importĂ© et les versions dĂ©jĂ  personnalisĂ©es de ce projet.

Politique appliquĂ©e (dĂ©cision utilisateur explicite) : garder la version du projet partout, ne conserver du nouvel import que le contenu rĂ©ellement nouveau (RetargetedCharacters, SmartObjects/AI supplĂ©mentaires, Ragdoll, Audio/Foley, MetaHumans, Characters de dĂ©mo — voir §4.2/§8). Les 95+17 doublons (17 supplĂ©mentaires dĂ©couverts aprĂšs coup sous Content/Input/ et Content/Data/, dont IMC_Sandbox lui-mĂȘme) ont Ă©tĂ© fusionnĂ©s via EditorAssetLibrary.consolidate_assets() (redirecteur automatique + suppression du doublon) quand c'Ă©tait possible, ou supprimĂ©s directement (delete_asset) quand rien ne rĂ©fĂ©rençait plus la copie importĂ©e. Le contenu unique restant a ensuite Ă©tĂ© dĂ©placĂ© vers son emplacement dĂ©finitif (Content/Systems/Blueprints/, Content/Core/PlayerController/Input/) via AssetToolsHelpers.get_asset_tools().rename_assets() (dĂ©placement avec réécriture de toutes les rĂ©fĂ©rences, pas un dĂ©placement de fichier brut).

Reste Ă  faire / connu (2026-09-08) :

  • Content/Systems/Mover/SmartObjects/AC_SmartObjectAnimation (anciennement Content/Blueprints/SmartObjects/, dĂ©placĂ© le 2026-09-14) : un doublon n'a pas pu ĂȘtre fusionnĂ©/supprimĂ© (l'outil consolidate_assets fait planter l'Ă©diteur sur cet ActorComponent prĂ©cis, voir §9) — laissĂ© en l'Ă©tat intentionnellement, sans impact gameplay (fonctionnalitĂ© SmartObject annexe).
  • ⚠ ObsolĂšte depuis le 2026-09-13 (voir §8.2) — Content/Blueprints/ contenait alors de nombreux fichiers ObjectRedirector (rĂ©sidus de consolidate_assets) — passer un "Fixup Redirectors" manuel (clic droit sur le dossier dans le Content Browser) quand pratique ; aucune API Python trouvĂ©e pour cette opĂ©ration, et forcer une suppression brute des redirecteurs risquerait de casser des rĂ©fĂ©rences logicielles (soft references) non encore réécrites.

8.2 Migration Project_F → ProjectFv1 (2026-09-13) — incident et Ă©tat aprĂšs rĂ©paration

E:\projet\Project_F est un autre dĂ©pĂŽt git (projet Game Animation Sample nettoyĂ©, oĂč l'utilisateur a dĂ©veloppĂ© un systĂšme de visĂ©e). Le 2026-09-13 (~22:00–22:12), l'Ă©diteur de Project_F a migrĂ© 3073 packages directement dans ProjectFv1/Content pendant que l'Ă©diteur de ProjectFv1 Ă©tait ouvert (preuve : Project_F/Saved/Logs/Project_F.log, lignes LogSavePackage: Moving ... to E:/projet/ProjectFv1/Content/...). ⚠ Ne jamais migrer vers ce projet avec son Ă©diteur ouvert.

DĂ©gĂąts constatĂ©s : 1449 assets suivis par git de Characters/UEFN_Mannequin/ Ă©crasĂ©s (animations + chooser tables, liĂ©es dĂ©sormais aux notifies/enums de Content/Blueprints/), 782 fichiers Systems/Weather/UltraDynamicSky/ Ă©crasĂ©s (widgets mĂ©tĂ©o sans leurs structs ST_Weather* → 149 erreurs), Content/Blueprints/ recréé comme copie complĂšte (137 vrais assets) du framework de Systems/Blueprints/. Les enums/structs des deux copies DIVERGENT (ex. E_MovementDirection : F/B/LL/LR/RL/RR vs Forward/Back/left/
, E_Gait sans Prone/Swimming) : ne JAMAIS les fusionner aveuglĂ©ment.

Réparation (décisions utilisateur) :

  • MĂ©tĂ©o : les 782 fichiers UltraDynamicSky restaurĂ©s depuis le commit d29748b (LFS). Versions migrĂ©es sauvegardĂ©es dans E:\projet\ProjectFv1_backup_migration_2026-09-13\.
  • Anims/choosers migrĂ©s conservĂ©s. Contexte (ContextData) des 7 chooser tables CMC/traversal remis aux valeurs du commit : CHT_PoseSearchDatabases(+_Dense/_Sparse/_ExtremeSparse) et CHT_CMCCharacterAnimations → Systems/Blueprints/SandboxCharacter_CMC_ABP (+ S_ChooserOutputs Systems) ; CHT_TraversalMontages_CMC/_Mover → Systems/Blueprints/Data/S_TraversalChooserInputs/Outputs. Lignes Bow du chooser Dense perdues (voir §1.3).
  • Structs strictement identiques fusionnĂ©es (consolidate_assets, redirecteurs laissĂ©s) : Content/Blueprints/Data/S_CHT_TraversalMontages_IN/OUT → Systems/.../S_TraversalChooserInputs/Outputs, Content/Blueprints/Data/S_ChooserOutputs → Systems/.../S_ChooserOutputs. Pins de Content/Blueprints/AC_TraversalLogic (traversal du Mover) rebranchĂ©es.
  • Doublon GASP du personnage CMC supprimĂ© : Content/Blueprints/SandboxCharacter_CMC + _ABP. RĂ©fĂ©rences de dĂ©mo redirigĂ©es vers /Game/SandboxCharacter_CMC (depuis dĂ©placĂ© dans /Game/Core/Character/) / l'ABP Systems (PC_Sandbox.Characters, AC_PreCMCTick, GM_Sandbox.PawnClasses_Soft, EUW_PawnOverrideButton.Object, variable locale de BP_NotifyState_EarlyTransition). (Content/Widgets/ a Ă©tĂ© supprimĂ© le 2026-09-14.)
  • STT_PlayAnimFromBestCost (Systems) pointe dĂ©sormais vers Systems/Blueprints/SmartObjects/AC_SmartObjectAnimation.
  • Config/DefaultGameplayTags.ini : ajout des tags du sample Foley.Event.* et SmartObject.ObjectType.Player/Bench (manquants → avertissements massifs + StateTree SmartObject non liable).

Contenu du framework du sample conservé volontairement (déplacé le 2026-09-14, voir §4.2.1 et « Convergence partielle » ci-dessous) :

  • Systems/Aiming/ (ABP_AimingMaster, ABP_AimingMaster_UEFN, CH_AO, CH_Base_AO_Animechooser) → systĂšme de visĂ©e/aim offset dĂ©veloppĂ© dans Project_F, utilisĂ© par SandboxCharacter_Mover_ABP.
  • Systems/Mover/SandboxCharacter_Mover / _ABP / _Ragdoll → personnage alternatif plugin Mover (+ Systems/Mover/GM_Sandbox/PC_Sandbox ; dev_map de dĂ©mo supprimĂ© le 2026-09-14).
  • le reste du framework dupliquĂ©, dans Systems/Mover/ (AC_TraversalLogic, BPI_*, Data/, Cameras/
) ; ses notifies restent dans Content/Blueprints/AnimNotifies/ (liĂ©s Ă  1278 animations). Chooser tables toujours liĂ©es Ă  ce framework : CHT_PoseSearchDatabases_Relaxed, CHT_MoverCharacterAnimations_PoseMatch, CHT_GetUpMontages, CHT_CharacterInteractionPSDs.

Convergence partielle (2026-09-14) :

  • Enums fusionnĂ©s : les 17 enums du sample de Content/Blueprints/Data|Cameras|AnimNotifies/ (E_Gait, E_Stance, E_MovementMode, E_MovementState, E_MovementDirection, E_MovementDirectionBias, E_RotationMode, E_AnalogStickBehavior, E_ExperimentalStateMachineState, E_RagdollInjuryState, E_TraversalActionType, E_CameraMode, E_CameraStyle, E_EarlyTransition_Condition, E_EarlyTransition_Destination, E_FoleyEventSide, E_TraversalBlendOutCondition) ont Ă©tĂ© fusionnĂ©s dans leurs jumeaux de Systems/Blueprints/ (17 redirecteurs laissĂ©s Ă  l'ancien emplacement). Valeurs propres au sample ajoutĂ©es en fin d'enum cĂŽtĂ© projet (voir §4.2) et pins/switchs de la chaĂźne Mover remappĂ©s dessus. Interfaces et structs Systems enrichies en consĂ©quence (§4.2).
  • RĂ©parations consĂ©cutives (piĂšge dĂ©crit en §9) : variables d'enum vidĂ©es retypĂ©es et liens rebranchĂ©s dans SandboxCharacter_Mover, SandboxCharacter_Mover_Ragdoll, SandboxCharacter_Mover_ABP (restaurĂ© depuis sauvegarde puis remappĂ©), BP_AnimNotify_TriggerRagdoll, AnimNotifies/BP_NotifyState_EarlyTransition et BP_NotifyState_MontageBlendOut (liens comparĂ©s un Ă  un Ă  leurs jumeaux Systems). Chaque asset validĂ© par rechargement de son package.
  • ArrĂȘt de la convergence (dĂ©cision utilisateur) : Ă  cause de ce piĂšge, le reste de Content/Blueprints/ (Mover, Aiming, AC/BPI/structs/notifies/camĂ©ras du sample) n'est PAS fusionnĂ©. Il a Ă©tĂ© seulement dĂ©placĂ©, sans fusion, le 2026-09-14 (voir §4.2.1) ; les doublons restants sont une dette connue.

Restauration Motion Matching (2026-09-14, dĂ©cision utilisateur) : un audit des 189 donnĂ©es Motion Matching modifiĂ©es depuis d29748b (comparaison des rĂ©fĂ©rences /Game/... des blobs git avant/aprĂšs) a trouvĂ© 7 assets dĂ©gradĂ©s par la migration, tous restaurĂ©s depuis d29748b (toutes leurs rĂ©fĂ©rences existent encore) : CHT_PoseSearchDatabases_Dense (19 bases perdues : Bow, Prone, nage, cover accroupi, Push ; colonnes E_CoverD/Weapon_Equip), Channels/PSC_Traversal_Head et _Pos (pointaient sur la BPI du sample au lieu de Systems/Blueprints/BPI_SandboxCharacter_ABP), Schemas/PSS_Default et PSS_Idle (table miroir Rigs/MDT_UEFN_Mannequin perdue), Normalization_Sets/PSN_Relaxed_All (le Mover y perd PSD_SM_Mover_TraversalTransitions), Databases/Dense/PSD_Dense_Stand_Idles (mesh d'aperçu). Seul autre Ă©cart trouvĂ©, conservĂ© : Traversal/CHT_TraversalMontages_Mover (montages Climb Relaxed → Neutral, chooser du Mover).

État vĂ©rifiĂ© en fin de rĂ©paration : passe de compilation complĂšte, 435 Blueprints, 0 erreur (non encore testĂ© en PIE). Dettes connues non liĂ©es Ă  la migration : tags Attachments.* (§2.1), animations AGIS sans squelette (voir §9 : Systems/Inventory/Other/Animations/DeathAnim_AGIS et Rifle/* — compatibles Ă  100 % avec SK_UEFN_Mannequin, Ă  assigner Ă  la main dans l'Ă©diteur ; Jog/, WALK/, TurnInPlace/, AIM_Rifle_Idle_ADS inutilisĂ©es et incompatibles), « Unknown structure » au chargement de Systems/Blueprints/BPI_SandboxCharacter_Pawn (antĂ©rieur au 2026-09-07).


9. Notes pour les IA : piĂšges connus de l'outillage

Ce projet est modifié via le plugin VibeUE (service MCP unreal-mcp, voir .mcp.json), qui expose des services Python (unreal.BlueprintService, unreal.WidgetService, unreal.InputService, unreal.EnumStructService, etc.) pour piloter l'éditeur Unreal sans l'ouvrir manuellement. Quelques piÚges rencontrés et leurs solutions :

  • PIÈGE — un nƓud Evaluate Chooser sans objet de contexte branchĂ© renvoie TOUJOURS une liste vide (2026-09-18) : constatĂ© sur SandboxCharacter_Mover_ABP::Update_MotionMatching, dont les deux nƓuds avaient leur pin de contexte (SandboxCharacter_Mover_ABP_C) laissĂ© vide — aucune colonne du chooser ne pouvait ĂȘtre rĂ©solue, ValidDatabases restait vide en permanence et toute la branche Motion Matching de l'AnimGraph Ă©tait inerte (MM Search Cost = FLT_MAX, CurrentSelectedAnim = None) sans qu'aucune erreur ne soit loguĂ©e. Toujours brancher self (type id crĂ©able : Variables|Getareferencetoself). SymptĂŽme jumeau Ă  surveiller : un chooser dupliquĂ© dont on a changĂ© le ContextData fonctionne, les liaisons se rĂ©solvant par NOM de variable sur la nouvelle classe de contexte.
  • PIÈGE — crĂ©er par script un sous-objet instanciĂ© dans un template de composant casse la sauvegarde des Blueprints ENFANTS (2026-09-17) : unreal.new_object(cls, outer=<template du composant>) (ici un mode de mouvement ajoutĂ© Ă  CharacterMover.MovementModes) produit un objet privĂ© ; l'enfant (SandboxCharacter_Mover_Ragdoll, qui surcharge le composant via son InheritableComponentHandler) le prend comme archĂ©type et sa sauvegarde Ă©choue avec Illegal reference to private object. PrĂ©fĂ©rer un enregistrement Ă  l'exĂ©cution (MoverComponent::AddMovementModeFromClass au BeginPlay) ou l'Ă©dition manuelle dans l'Ă©diteur.
  • PIÈGE — SubobjectDataSubsystem.rename_subobject juste aprĂšs BlueprintService.remove_component provoque une assertion fatale (2026-09-17) : Renaming an object (
Arrow_GEN_VARIABLE) on top of an existing object (
Arrow1_GEN_VARIABLE) is not allowed — l'ancien template n'est pas encore collectĂ©. L'interprĂ©teur Python est ensuite corrompu (0xC0000005 au premier accĂšs au Blueprint) et le MCP sauvegarde les packages modifiĂ©s Ă  chaque appel, donc l'Ă©tat intermĂ©diaire peut se retrouver sur disque : redĂ©marrer l'Ă©diteur et vĂ©rifier le Blueprint (composants, liaisons) aprĂšs ce type d'erreur. Corollaire : un composant ajoutĂ© par BlueprintService.add_component(..., parent_name="Capsule") reçoit un ParentComponentOrVariableName explicite qui dĂ©clenche l'avertissement Reparenting the 'X' component 
 possible cyclic linkage Ă  chaque compilation ; l'ajouter sans parent (comme les autres composants racine du SCS) Ă©vite l'avertissement.
  • Lire l'Ă©tat de jeu en PIE depuis Python est dĂ©calĂ© d'une frame ou deux (surtout pour les variables d'Anim Blueprint Ă©crites dans l'update thread-safe) : une mĂȘme valeur peut sembler « fausse » (allure restĂ©e Ă  Run, ValidDatabases vide) puis correcte Ă  l'appel suivant. Toujours relire dans un second appel avant de conclure Ă  un bug. De plus, BlueprintService.list_graphs/list_variables renvoient 0 Ă©lĂ©ment pendant une session PIE : arrĂȘter le PIE avant d'inspecter un graphe.
  • build_graph attend un champ "ref" pour identifier chaque nƓud dans la liste nodes (pas "id"). Un mauvais nom de champ Ă©choue silencieusement (retourne None sans erreur explicite).
  • Les variables locales Ă  une fonction (paramĂštres, locals créés via add_object_variable avec graph=...) ne sont pas fiables avec build_graph's variable_get/variable_set : prĂ©fĂ©rer des variables membres du Blueprint.
  • Un K2Node_VariableSet/Get créé via un spawner_key gĂ©nĂ©rique (discover_nodes + create_node_by_key) peut se rĂ©soudre sur la mauvaise classe si plusieurs Blueprints chargĂ©s ont une variable de mĂȘme nom affichĂ© (ex. "Owner Inventory" existe Ă  la fois sur WB_Container et sur un widget créé cette session) — toujours vĂ©rifier les pins du nƓud créé (get_node_pins) avant de cĂąbler, ou utiliser build_graph avec type: "variable_set" + params.variable en contexte "self" qui est fiable.
  • Appeler une fonction Blueprint prĂ©existante (créée dans une session antĂ©rieure/par le plugin marketplace) sur un autre Blueprint peut Ă©chouer silencieusement selon la mĂ©thode utilisĂ©e. PrivilĂ©gier l'accĂšs direct aux propriĂ©tĂ©s (member_get, fiable) plutĂŽt que l'appel de fonction cross-Blueprint quand c'est possible ; sinon tester add_function_call_on_variable et vĂ©rifier le rĂ©sultat via get_node_pins/get_nodes_in_graph.
  • Écrire une valeur littĂ©rale sur un pin de type Text, Object ou Class via set_node_pin_value Ă©choue souvent silencieusement Ă  l'affichage (get_node_pins renvoie toujours default_value: "") mĂȘme quand l'assignation a rĂ©ellement fonctionnĂ© — vĂ©rifier via une compilation (erreurs de compilation manquantes = probablement OK) plutĂŽt que via une relecture du pin.
  • Toujours compiler ET sauvegarder un Blueprint aprĂšs modification (BlueprintEditorLibrary.compile_blueprint + EditorAssetLibrary.save_loaded_asset), puis tester en PIE et lire les logs (EditorToolset.LogsToolset.GetLogEntries, filtrer sur "Blueprint Runtime Error") pour dĂ©tecter les erreurs Ă  l'exĂ©cution qu'une compilation rĂ©ussie ne rĂ©vĂšle pas (ex. accĂšs Ă  un Ă©lĂ©ment de tableau hors limites).
  • Le clavier cible du jeu est AZERTY : vĂ©rifier les mappings de touches existants (IMC_Sandbox, IMC_AGIS_Character, IMC_AGIS_InventoryTab) avant d'assigner une nouvelle touche, et choisir des touches physiquement identiques entre QWERTY/AZERTY.

PiÚges du toolset editor_toolset.toolsets.blueprint.BlueprintTools (create_node/connect_pins/write_graph_dsl/get_node_infos, utilisé depuis le systÚme d'armes du 2026-09-05) :

  • La DSL write_graph_dsl casse sur un type_id contenant une parenthĂšse fermante suivie d'autres caractĂšres (ex. BOTH|GetItem(copy)ByUID Ă©choue avec "does not exist" car le tokenizer coupe au premier )) ; un type_id se terminant PAR une parenthĂšse fonctionne (Utilities|Array|Get(acopy)). Dans ce cas, construire le nƓud Ă  la main (create_node/connect_pins) plutĂŽt que via la DSL.

  • Un type_id retournĂ© par find_node_types (ex. Variables|Default|GetACWeapon) peut diffĂ©rer du type_id affichĂ© ensuite par get_node_infos pour CE nƓud (ex. |GetAC_Weapon, avec underscore) : toujours utiliser la chaĂźne de find_node_types pour crĂ©er/rĂ©fĂ©rencer un nƓud dans la DSL, jamais celle affichĂ©e aprĂšs coup par get_node_infos.

  • Éditer une propriĂ©tĂ© d'un composant SCS hĂ©ritĂ© (ex. changer le mesh d'un StaticMeshComponent dĂ©fini dans une classe parente, depuis le Blueprint enfant) : SubobjectDataBlueprintFunctionLibrary.get_object/get_associated_object renvoient le template du PARENT (le modifier casse le parent pour toutes ses classes filles !). Utiliser get_object_for_blueprint(data, child_blueprint) qui crĂ©e correctement l'override propre Ă  l'enfant.

  • ItĂ©rer un Array[SubobjectDataHandle] avec for h in handles: casse get_data/get_variable_name (erreur de nativisation) ; indexer explicitement (for i in range(len(handles)): h = handles[i]) fonctionne.

  • Un Blueprint Function Library (BFL) se crĂ©e avec unreal.BlueprintFunctionLibraryFactory() (pas le BlueprintFactory gĂ©nĂ©rique + parent_class, qui Ă©choue avec "Cannot create a blueprint based on the class").

  • Depuis execute_python_code, appeler une fonction Blueprint sur une instance PIE via actor.call_method(...) nĂ©cessite le nom d'affichage exact avec ses espaces (ex. "Set Item Actor Owner", "Primary Use"), pas une version condensĂ©e/snake_case — sauf pour certains getters de variable auto-gĂ©nĂ©rĂ©s dont le nom interne rĂ©el ne correspond ni Ă  l'un ni Ă  l'autre (Ă  vĂ©rifier au cas par cas).

  • CrĂ©er un InputAction en Python : unreal.InputAction_Factory() (PAS unreal.InputActionFactory, qui n'existe pas) + AssetToolsHelpers.get_asset_tools().create_asset(...). Pour mapper une touche dans un InputMappingContext existant, prĂ©fĂ©rer unreal.InputService.add_key_mapping(imc_path, ia_path, "F9") (service VibeUE dĂ©diĂ©) plutĂŽt que d'Ă©diter la propriĂ©tĂ© dĂ©prĂ©ciĂ©e mappings de l'IMC directement en Python.

  • Construire un widget UMG en Python : unreal.WidgetService.add_component/set_property/bind_event fonctionnent bien pour la hiĂ©rarchie et les propriĂ©tĂ©s, mais il n'existe aucun unreal.WidgetBlueprintLibrary.create_widget exposĂ© pour instancier un widget Ă  la volĂ©e. Pour un test rapide en PIE, utiliser unreal.WidgetService.spawn_widget_in_pie(chemin) (retourne un handle qu'on repasse Ă  remove_widget_from_pie) — mais ce handle n'expose pas d'appel de fonction arbitraire sur l'instance ; il ne sert qu'Ă  l'afficher/la retirer et lire ses propriĂ©tĂ©s (get_live_property).

  • EditorToolset.EditorAppToolset.CaptureAssetImage/CaptureViewport sont le seul moyen fiable de voir un rĂ©sultat (mesh, matĂ©riau, scĂšne) : le retour JSON est trop volumineux pour ĂȘtre lu tel quel (limite de tokens) — toujours passer par un script Python (base64.b64decode du champ returnValue.data, Ă©crit dans le scratchpad) puis Read sur le PNG obtenu.

  • Un asset .uasset peut se retrouver corrompu Ă  vide (0 vertex/triangle, bounds nuls) aprĂšs une fermeture anormale de l'Ă©diteur (coupure de courant, crash) sans que sa taille de fichier ni son chargement ne signalent d'erreur — toujours vĂ©rifier get_num_vertices(0)/get_bounds() (StaticMesh) aprĂšs un redĂ©marrage suspect avant de chercher un autre bug. delete_asset/consolidate_assets peuvent Ă©chouer silencieusement (retour False, sans exception) sur un tel asset corrompu mĂȘme sans rĂ©fĂ©renceur restant — dans ce cas, renommer le nouvel asset importĂ© sous un autre nom plutĂŽt que de s'acharner Ă  rĂ©utiliser le chemin d'origine.

  • Toute variable membre boolĂ©enne (bXxx) affiche son nom SANS le prĂ©fixe b dans les nƓuds Get/Set gĂ©nĂ©rĂ©s par la DSL (GetCanSeePlayer, pas GetbCanSeePlayer) — mais son nom de propriĂ©tĂ© brut, tel qu'attendu par get_editor_property/set_editor_property en Python ET par StateTreeService.bind_*_property_to_context (chemins de contexte), conserve le prĂ©fixe b ("bCanSeePlayer", "AnimalSenses.bScentDetected"). Utiliser le nom sans b dans l'un de ces deux contextes Ă©choue silencieusement en DSL (nƓud introuvable) ou avec "Malformed target property path" cĂŽtĂ© StateTree.

  • delete_node sur un nƓud dont une pin est encore rĂ©fĂ©rencĂ©e par un AUTRE nƓud (ex. un nƓud Self/GetXxx pur, rĂ©utilisĂ© par plusieurs consommateurs) peut laisser une connexion fantĂŽme cĂŽtĂ© survivant : get_node_infos continue de lister une pin connectĂ©e vers le node supprimĂ© (qui n'apparaĂźt plus dans find_nodes), et la compilation Ă©choue avec l'erreur gĂ©nĂ©rique Internal compiler error inside CreateExecutionSchedule sans dĂ©signer le nƓud fautif. Diagnostic : dumper get_node_infos de TOUS les nƓuds du graphe et chercher une pin connectĂ©e vers un node absent de find_nodes ; le node fantĂŽme existe encore assez longtemps en mĂ©moire (non garbage-collectĂ©) pour que break_pins fonctionne dessus malgrĂ© tout — l'appeler explicitement sur cette connexion rĂšgle l'erreur.

  • Une UserDefinedEnum (créée via unreal.EnumStructService.create_enum) ne peut PAS servir de type Ă  une variable membre, un paramĂštre de fonction ou un paramĂštre de dispatcher via les outils disponibles (add_variable/add_function_param n'acceptent que bool/int/float/byte/name/string/text/Vector/Rotator/Transform/Vector2D/LinearColor) — limitation dĂ©jĂ  notĂ©e pour AC_Stats::OnDamaged, reconfirmĂ©e pour E_AnimalState. Contournement : stocker en byte et convertir Ă  l'affichage seulement si besoin (Utilities|String|ToString(Byte)).

  • Une StateTree Task Blueprint (StateTreeTaskBlueprintBase) ne tique QUE si sa CDO a should_call_tick_only_on_events = true — malgrĂ© son nom qui suggĂšre l'inverse ("seulement sur Ă©vĂ©nements"), c'est en rĂ©alitĂ© l'interrupteur gĂ©nĂ©ral qui active ReceiveLatentTick. Aucune property bShouldCallTick distincte n'est exposĂ©e.

  • ChaĂźner plus de deux concatĂ©nations (+ a b) de String dans une mĂȘme expression DSL imbriquĂ©e casse avec Could not connect pin ReturnValue to A (constatĂ© sur BP_AnimalBase::DebugTick) — mĂȘme en sĂ©parant chaque Ă©tape par un bind intermĂ©diaire. Contournement : limiter chaque nƓud + Ă  DEUX opĂ©randes littĂ©raux/variables simples, et multiplier les appels DrawDebugString/lignes plutĂŽt que de construire une seule chaĂźne longue.

  • Une donnĂ©e cross-instance (lire la variable d'un AUTRE acteur de mĂȘme classe, ex. le HerdID d'un autre BP_AnimalBase pendant BroadcastAlertToHerd) n'est PAS accessible via le getter Variables|Default|GetXxx gĂ©nĂ©rĂ© par la DSL (celui-ci n'a pas de pin self/cible, contrairement aux nƓuds Class|MaClasse|MaFonction qui, eux, exposent bien un self substituable). Solution : passer la donnĂ©e nĂ©cessaire en PARAMÈTRE de la fonction appelĂ©e sur l'autre instance plutĂŽt que de tenter de la lire directement (voir ReceiveHerdAlert(ThreatLocation, CallerHerdID)).

  • Une nouvelle StateTree (unreal.StateTreeService.create_state_tree) dĂ©marre SANS aucun Ă©tat racine : add_state(path, "Root", ...) Ă©choue silencieusement (retourne False) tant qu'un premier add_state(path, "", "Root", "State") (parent_path vide) n'a pas créé l'Ă©tat racine lui-mĂȘme.

  • Lier une AC_Stats::OnDamaged (dispatcher avec paramĂštres) directement Ă  une fonction Blueprint CLASSIQUE (pas un Custom Event) via K2Node_CreateDelegate.set_create_delegate_function compile sans erreur immĂ©diate mais casse la compilation Ă  la volĂ©e suivante avec Internal compiler error inside CreateExecutionSchedule — et peut mĂȘme faire apparaĂźtre des nƓuds AddEvent parasites (EventTick, EventActorBeginOverlap
) ailleurs dans le graphe. Un dispatcher avec paramĂštres doit ĂȘtre liĂ© Ă  un Custom Event (add_event avec un nom arbitraire crĂ©e un vrai K2Node_CustomEvent, contrairement Ă  write_graph_dsl's (event Nom ...) qui n'accepte que les noms d'Ă©vĂ©nements natifs "AddEvent|Nom" connus). Un dispatcher SANS paramĂštre (ex. AC_Stats::OnDeath) ne pose aucun problĂšme liĂ© Ă  une fonction classique.

  • (2026-09-14) BlueprintTools.write_graph_dsl Ă©choue en silence : en cas d'erreur (nƓud inexistant, pin incompatible) il ne lĂšve rien, retourne None et laisse le graphe inchangĂ© ou VIDE ; le vrai message n'apparaĂźt que dans Saved/Logs/ProjectFv1.log (LogScript: Warning: AssertionError: The node could not be created / 
 does not exist ou RuntimeError: Could not connect pin 
). Toujours vĂ©rifier chaque Ă©criture par read_graph_dsl (chercher un nƓud attendu) avant de sauvegarder. PiĂšges constatĂ©s : (a) Math|Byte|Equal(Byte) et Math|Vector|vector+vector sont RELUS par read_graph_dsl mais REFUSÉS Ă  l'Ă©criture — utiliser les opĂ©rateurs ==/+ ; (b) les appels de fonction du Blueprint lui-mĂȘme (CallFunction|MaFonction) ont une pin self en premiĂšre position : passer les arguments par mot-clĂ© (:Anim x :Loop true), sinon le premier argument est branchĂ© sur self ; (c) les getters de variables Ă  underscore perdent l'underscore dans le type_id (Anim_Idle → Variables|Default|GetAnimIdle), et find_node_types renvoie aussi CallFunction|ApplyIdleforState avec la casse de l'affichage ; (d) read_graph_dsl affiche parfois un nƓud sous une catĂ©gorie trompeuse (CustomizableObjectInstance|SetCurrentState pour un appel Ă  BP_AnimalBase::SetCurrentState) — vĂ©rifier avec get_node_infos avant de conclure Ă  un mauvais binding ; (e) BlueprintTools.create_node attend un unreal.IntPoint pour pos, pas un Vector2D.

  • (2026-09-14) StateTree : une tĂąche Blueprint qui appelle FinishTask dans EnterState termine l'Ă©tat dans la mĂȘme frame (TasksCompletion=Any), et StateTreeService.set_task_considered_for_completion(..., False) renvoie True mais n'a PAS empĂȘchĂ© ce comportement en PIE (UE 5.8). Pour une tĂąche « fire and forget » (ex. STT_SetAnimalState), ne PAS appeler FinishTask. Diagnostic : log LogStateTree Verbose en PIE puis compter les Enter state dans le log.

  • (2026-09-14) StateTree : une transition posĂ©e sur Root (trigger OnTick) reste Ă©valuĂ©e quand sa CIBLE est dĂ©jĂ  active et la rĂ©-entre Ă  chaque tick (Exit/Enter de toutes ses tĂąches). Toute transition globale doit donc porter une condition « pas dĂ©jĂ  dans cet Ă©tat » (ex. bIsFleeing == false pour Root→Flee).

  • Un NavMeshBoundsVolume ajoutĂ© par script (SceneTools.add_to_scene_from_class) ne gĂ©nĂšre PAS automatiquement de NavMesh : le RecastNavMesh-Default correspondant naĂźt avec RuntimeGeneration = Static (aucune rĂ©gĂ©nĂ©ration, ni en Ă©diteur ni au runtime, sans un "Build Paths" manuel — introuvable dans l'API Python exposĂ©e). Fix : recastNavMesh.set_editor_property("runtime_generation", unreal.RuntimeGenerationType.DYNAMIC) PUIS unreal.NavigationSystem.on_navigation_bounds_updated(nav_sys, volume) pour forcer une premiĂšre gĂ©nĂ©ration immĂ©diate (sans ce second appel, le volume reste sans tuiles jusqu'au premier changement de gĂ©omĂ©trie pertinent).

  • FAUX AMI corrigĂ© (2026-09-05) : read_graph_dsl insĂšre parfois un _ de lisibilitĂ© dans le nom affichĂ© d'une variable membre commençant par un prĂ©fixe court en majuscule (ex. la variable rĂ©elle LContainer s'affiche (|GetL_Container), PAS (|GetLContainer) — idem LItemName→L_ItemName). Utiliser cette forme AVEC underscore pour crĂ©er/Ă©crire un nƓud (create_node, write_graph_dsl) Ă©choue avec "... does not exist", ce qui peut faire croire Ă  tort Ă  une variable locale non-crĂ©able (variables locales et membres se comportent en rĂ©alitĂ© de façon identique cĂŽtĂ© crĂ©ation). Avant toute chirurgie sur un Get/Set qui Ă©choue ainsi, vĂ©rifier le nom SANS underscore via find_node_types (ex. filtrer "LContainer") plutĂŽt que de supposer une limitation de l'outil — le nom rĂ©el de la propriĂ©tĂ© (get_editor_property en Python inclus) ne contient jamais cet underscore ajoutĂ© par l'affichage.

  • Un Blueprint qui est la classe d'un composant actif dans une session PIE en cours peut compiler sans erreur mais Ă©chouer silencieusement Ă  la sauvegarde (save_loaded_asset renvoie False sans exception) tant que le PIE n'est pas arrĂȘtĂ© — toujours StopPIE avant de sauvegarder un asset qu'une session PIE utilise, et re-tenter la sauvegarde aprĂšs l'arrĂȘt.

  • CORROLAIRE DANGEREUX : aprĂšs tout Ă©chec de save_loaded_asset dĂ» au PIE, StopPIE PUIS ressauvegarder IMMÉDIATEMENT, et toujours revĂ©rifier via read_graph_dsl/find_nodes aprĂšs un redĂ©marrage/arrĂȘt du PIE qu'une Ă©dition rĂ©cente est bien encore prĂ©sente avant de continuer Ă  construire dessus — une Ă©dition compilĂ©e avec succĂšs pendant que le PIE tournait peut sembler perdue Ă  la prochaine lecture si la sauvegarde qui a suivi a Ă©chouĂ© silencieusement.

  • PIÈGE MAJEUR — graphe d'implĂ©mentation d'interface Blueprint fragile et auto-rĂ©gĂ©nĂ©rĂ© (2026-09-06) : le graphe qui implĂ©mente une fonction de Blueprint Interface (ex. BP_Item_HoldableBase:On Item Attached, implĂ©mentant BPI_HoldableItem::On Item Attached) peut revenir tout seul Ă  son Ă©tat d'origine aprĂšs une compilation ultĂ©rieure — de N'IMPORTE QUEL Blueprint de la hiĂ©rarchie, pas seulement celui qu'on Ă©dite — mĂȘme quand read_graph_dsl avait confirmĂ© l'Ă©dition juste aprĂšs une sauvegarde rĂ©ussie (save_loaded_asset → True, mtime du .uasset Ă  jour). Un reload_packages forcĂ© depuis Python confirme que c'est bien le contenu SUR DISQUE qui a rĂ©gressĂ©, pas juste l'Ă©tat en mĂ©moire — la persistance de ce type de graphe est donc bien plus fragile qu'une fonction normale. Reproduit 3 fois de suite sur le mĂȘme graphe dans cette session malgrĂ© des re-sauvegardes systĂ©matiques. Ne JAMAIS hĂ©berger de logique mĂ©tier propre (dispatcher broadcast, etc.) directement dans un graphe d'implĂ©mentation d'interface — s'en servir seulement comme passe-plat trivial si besoin, ou mieux : contourner entiĂšrement l'interface et appeler la fonction/le dispatcher cible directement depuis l'appelant via un Cast explicite vers la classe concrĂšte (ex. Inventory_Equipper::AttachItemToOwner caste Item en BP_Item_HoldableBase et appelle CallOnHeldStateChanged directement, sans jamais passer par l'interface) — cette approche s'est rĂ©vĂ©lĂ©e stable aprĂšs le contournement.

  • RĂ©fĂ©rence d'interface K2Node_Message/K2Node_CallFunction corrompue aprĂšs un renommage d'interface (2026-09-06) : un appel d'interface existant peut afficher un type_id/catĂ©gorie qui ne correspond Ă  AUCUN asset actuel du projet (ex. BPIEquippableItem|OnItemAttached alors que seule BPI_HoldableItem existe — probablement un renommage BPI_EquippableItem→BPI_HoldableItem fait avant cette session) tout en compilant sans erreur et en affichant des types de pins statiquement cohĂ©rents (get_node_type_pins montrait bien self: BPI Holdable Item Interface) — la compilation rĂ©ussit car un systĂšme de redirection (CoreRedirects ou Ă©quivalent) fait correspondre le nom au niveau des TYPES, mais l'appel ne dĂ©clenche RIEN Ă  l'exĂ©cution (confirmĂ© par prints de debug ne s'affichant jamais cĂŽtĂ© rĂ©cepteur, malgrĂ© la classe cible confirmĂ©e implĂ©menter l'interface via unreal.SystemLibrary.does_class_implement_interface). Un nƓud fraĂźchement créé avec le MÊME type_id peut mĂȘme se rĂ©soudre en un type de nƓud DIFFÉRENT (K2Node_CallFunction au lieu du K2Node_Message d'origine) — signe supplĂ©mentaire d'une rĂ©fĂ©rence historique corrompue plutĂŽt que d'un vrai type_id valide. Diagnostic : ajouter un print cĂŽtĂ© rĂ©cepteur et vĂ©rifier empiriquement qu'il se dĂ©clenche ; si l'appelant confirme passer par le nƓud (print juste avant) mais que le rĂ©cepteur reste silencieux, suspecter ce piĂšge. Fix : ne pas rĂ©utiliser l'ancien nƓud ni recrĂ©er un nƓud du mĂȘme type_id — contourner l'interface entiĂšrement (voir point ci-dessus).

  • Consommer un stock d'inventaire PASSIF (jamais Ă©quipĂ©/lĂąchĂ©) ne doit jamais passer par un acteur monde (2026-09-06) : la macro ML_InventoryMacros::Get Item Actor (et donc tout appel Utilities|GetItemActor) retourne TOUJOURS invalide pour un item empilĂ© qui n'a jamais Ă©tĂ© spawnĂ© comme acteur (ex. un stack de flĂšches "Arrow" qui reste en inventaire, jamais Ă©quipĂ©) — ce n'est pas un bug ponctuel, c'est le comportement normal : ces items n'ont simplement pas d'acteur tant qu'ils ne sont pas Ă©quipĂ©s/lĂąchĂ©s dans le monde. Une fonction du type ConsumeArrow/ReduceAmmo qui suit le patron FindItem → GetItemActor → SERVER|ReduceAmount(item_actor, ...) Ă©choue donc silencieusement (retourne false) pour ce genre d'item, mĂȘme quand FindItem a bien trouvĂ© le stack. Fix correct : opĂ©rer directement sur les DONNÉES via l'adresse de l'item, avec Inventory__Main::AddItemAmount(ItemAddress, DeltaAmount) (nĂ©gatif pour consommer) — une fonction RPC serveur qui gĂšre nativement le retrait de l'array si le montant tombe Ă  0, sans jamais nĂ©cessiter d'acteur. Le mĂ©canisme GetItemActor+fonction-sur-acteur reste correct UNIQUEMENT pour des items dont l'acteur est garanti d'exister (ex. un chargeur d'arme Ă©quipĂ©, actif comme Magazine Reference).

  • PIÈGE CRITIQUE — brancher UNE sortie de pose sur PLUSIEURS entrĂ©es dans un AnimGraph casse toute la locomotion (2026-09-06) : contrairement Ă  un graphe Blueprint normal, une sortie Pose Link (AnimGraphNode_*) qui alimente directement 2+ entrĂ©es fait ÉVALUER EN DOUBLE, Ă  chaque frame, TOUT le sous-graphe en amont — pas seulement recalculer une valeur, mais rĂ©ellement re-tick les nƓuds AVEC ÉTAT (State Machine, Motion Matching, Blend Space avec accumulation de temps, Inertialization) une deuxiĂšme fois. SymptĂŽme observĂ© : le personnage "bouge de façon bizarre" (mouvement erratique/saccadĂ©) dĂšs qu'un nƓud en amont d'un fan-out a un Ă©tat interne dĂ©pendant du temps — la Motion Matching et les State Machines de ce projet en amont de Slot 'DefaultSlot' Ă©taient tickĂ©es deux fois par frame aprĂšs l'ajout (sans prĂ©caution) d'un second consommateur sur la sortie de ce Slot. Fix obligatoire : ne jamais connecter directement une sortie de pose partagĂ©e Ă  plusieurs entrĂ©es — insĂ©rer un Save Cached Pose 'NomUnique' juste aprĂšs la source, puis un Use Cached Pose 'NomUnique' par consommateur (le projet utilise dĂ©jĂ  ce patron ailleurs dans SandboxCharacter_CMC_ABP, ex. cache MotionMachin consommĂ© par Mirror_0 ET BlendListByBool_3 — repĂ©rable via find_nodes/get_node_infos avant de dupliquer une sortie, pour voir si le patron existe dĂ©jĂ ). Une rĂ©gression de ce type NE PROVOQUE AUCUNE ERREUR DE COMPILATION — le graphe compile et sauvegarde sans avertissement, le bug n'est visible qu'en jouant.

  • CrĂ©er un nƓud de Get/Set VARIABLE d'une AUTRE classe (pas une fonction) via create_node (2026-09-06) : find_node_types avec context_pins pointant vers une pin dĂ©jĂ  castĂ©e Ă  la classe cible retourne bien le type_id correct (ex. Variables|Default|SetWeapon), mais ce type_id Ă©choue Ă  la crĂ©ation via create_node (does not exist) MÊME avec declaring_class renseignĂ© — declaring_class ne sert qu'Ă  dĂ©sambiguĂŻser un type_id dĂ©jĂ  trouvĂ©, pas Ă  Ă©largir la recherche. Fix : rappeler find_node_types avec context_pins: [] (SANS contexte) sur le mĂȘme filtre — la forme SANS contexte rĂ©vĂšle le type_id RÉELLEMENT crĂ©able, qui suit la convention Class|<NomClasseSansUnderscore>|<NomPropriĂ©tĂ©> (ex. Class|SandboxCharacterCMC|SetWeapon), diffĂ©rent de la forme Variables|Default|... que le contexte affichait. Une fois créé, le nƓud peut ensuite s'afficher avec un LABEL DSL trompeur (catĂ©gorie SandboxCharacterCMCABP au lieu de SandboxCharacterCMC par ex.) — vĂ©rifier le type rĂ©el de la pin self via get_node_infos (pas la catĂ©gorie DSL) pour confirmer la bonne classe cible.

  • Configurer un nƓud AnimGraphNode_* (Slot, LayeredBoneBlend, etc.) au-delĂ  de ses pins (2026-09-06) : le nom d'un Slot (SlotName) et les filtres de branche d'un Layered Blend Per Bone (LayerSetup[i].BranchFilters) ne sont PAS des pins — ce sont des propriĂ©tĂ©s du sous-struct Node (le FAnimNode_* runtime) portĂ© par le AnimGraphNode_*. Invisibles via get_node_infos/create_node/set_pin_value. AccĂšs uniquement via Python : node.get_editor_property("Node") renvoie le struct runtime, dont les champs se lisent/Ă©crivent avec get_editor_property/set_editor_property en snake_case (slot_name, layer_setup, blend_weights...) — mais pour un ARRAY de structs imbriquĂ©s (ex. layer_setup: [InputBlendPose], chaque InputBlendPose.branch_filters: [BranchFilter]), modifier un Ă©lĂ©ment en place ne suffit pas : construire les structs indĂ©pendamment (unreal.BranchFilter(), unreal.InputBlendPose()), les remplir via set_editor_property, PUIS rĂ©assigner le tableau complet sur le struct parent (ibp.set_editor_property("branch_filters", [bf]), puis node_struct.set_editor_property("layer_setup", [ibp]), puis node.set_editor_property("Node", node_struct)) — une mutation in-place sans cette rĂ©assignation finale ne persiste pas. to_dict() sur ces structs renvoie souvent {} de façon trompeuse mĂȘme quand les propriĂ©tĂ©s sont bien accessibles individuellement via get_editor_property — ne pas se fier Ă  to_dict() pour vĂ©rifier un struct AnimGraph, toujours relire chaque propriĂ©tĂ© nommĂ©ment.

  • Le cache de dĂ©couverte de find_node_types pour un AUTRE Blueprint rĂ©fĂ©rençant fraĂźchement une fonction ajoutĂ©e ailleurs (ex. Class|InventoryPlayer|MaNouvelleFonction cherchĂ© depuis un Widget qui possĂšde une variable de type Inventory_Player) peut rester pĂ©rimĂ© et ne rien retourner mĂȘme aprĂšs compilation+sauvegarde de la classe modifiĂ©e — create_node avec le type_id dĂ©duit par convention (Class|<NomClasseSansUnderscore>|<NomFonction>) fonctionne quand mĂȘme ; ne pas conclure Ă  une impossibilitĂ© sur la seule base d'un find_node_types vide.

  • unreal.get_editor_subsystem(unreal.EditorActorSubsystem).get_all_level_actors() (et plus gĂ©nĂ©ralement les APIs EditorActorSubsystem) redevient silencieusement vide pendant qu'une session PIE est active — ces APIs ciblent le monde Ă©diteur, pas le monde PIE. Pour inspecter/piloter des acteurs PENDANT une session PIE (vĂ©rifier qu'une IA se dĂ©place, lire une variable en temps rĂ©el), utiliser editor_toolset.toolsets.scene.SceneTools.find_actors (qui rĂ©sout correctement vers le monde UEDPIE_0_<NomNiveau>) puis unreal.load_object(None, refPath) sur le chemin PIE retournĂ©.

  • write_graph_dsl (réécriture complĂšte d'un graphe) casse sur 2 instances DIFFÉREMMENT TYPÉES d'un mĂȘme nƓud wildcard enum (2026-09-06) : Utilities|Enum|NotEqual(Enum)/Equal(Enum) sont des nƓuds gĂ©nĂ©riques dont le type se fixe au premier pin connectĂ© — un graphe EXISTANT peut trĂšs bien contenir plusieurs instances typĂ©es diffĂ©remment (constatĂ© sur Get_MMInterruptMode : 3× NotEqual(Enum) + 2× Equal(Enum), types E_MovementMode/E_MovementState/E_Gait mĂ©langĂ©s, qui coexistent sans problĂšme). Mais reconstruire ce mĂȘme graphe en un seul appel write_graph_dsl en y ajoutant une NOUVELLE instance sur un type enum diffĂ©rent (ex. Weapon_Equip) Ă©choue systĂ©matiquement avec Could not connect pin ReturnValue to B, quel que soit l'ordre des clauses — le compilateur DSL semble partager le typage wildcard entre toutes les instances créées dans une mĂȘme passe, contrairement au graphe dĂ©jĂ  compilĂ© oĂč chaque instance est indĂ©pendante. Heureusement l'Ă©chec est bien transactionnel (read_graph_dsl confirme le graphe intact aprĂšs l'erreur, aucun Ă©tat partiel). Fix : ne PAS passer par une réécriture DSL complĂšte pour ce genre d'ajout — construire les nƓuds un par un (create_node pour les 2 Variables|Default|GetXxx + le nouveau NotEqual(Enum), connect_pins pour les typer), puis brancher le rĂ©sultat sur le nƓud logique existant. Un nƓud Math|Boolean|ORBoolean/ANDBoolean (K2Node_CommutativeAssociativeBinaryOperator) accepte nativement un pin de PLUS via add_node_pin (retourne le nouveau PinID, ex. C aprĂšs A/B) — pas besoin de recrĂ©er tout l'arbre logique, juste ajouter le pin et y connecter la nouvelle condition. read_graph_dsl n'affiche ensuite QUE les 2 premiers pins d'un or/and Ă  3+ entrĂ©es (limite d'affichage du lecteur DSL) — vĂ©rifier un ajout de ce type via get_node_infos sur le nƓud lui-mĂȘme, pas via une relecture DSL qui semblerait ignorer l'Ă©dition.

  • Architecture Motion Matching — pourquoi une nouvelle base de donnĂ©es "valide" peut ĂȘtre ignorĂ©e indĂ©finiment (2026-09-06) : Update_MotionMatching (fonction ABP thread-safe, tourne chaque frame) fait EvaluateChooser → SetValidDatabases → MotionMatchingAnimNodeLibrary.SetDatabasesToSearch(node, databases, InterruptMode) — le 3ᔉ paramĂštre (Get_MMInterruptMode, une fonction sĂ©parĂ©e) contrĂŽle si le nƓud AnimGraphNode_MotionMatching a le DROIT de remettre en cause la pose en cours (DoNotInterrupt = non, il continue de jouer/boucler l'ancienne sĂ©lection MÊME SI elle n'appartient plus Ă  DatabasesToSearch ; InterruptOnDatabaseChange(AndInvalidateContinuingPose) = oui, force une recherche complĂšte). Changer ValidDatabases ne suffit donc JAMAIS Ă  lui seul Ă  faire rĂ©agir Motion Matching si Get_MMInterruptMode ne dĂ©tecte pas la transition responsable — vĂ©rifier scrupuleusement, pour TOUT nouveau contexte de sĂ©lection (nouvelle variable de state driving un chooser), qu'il existe bien une condition correspondante dans cette fonction (schĂ©ma dĂ©jĂ  en place : une paire GetXxx/GetXxxLastFrame, mise Ă  jour chaque frame dans Update_States, comparĂ©e avec Utilities|Enum|NotEqual(Enum) puis OR-Ă©e dans la condition racine). Diagnostic fiable : obj dump sur l'instance AnimInstance vivante en PIE (unreal.SystemLibrary.execute_console_command(actor, 'obj dump "<chemin_instance>"'), rĂ©sultat lu via EditorToolset.LogsToolset.GetLogEntries) expose le struct COMPLET AnimGraphNode_MotionMatching=(...), notamment MotionMatchingState.SearchResult.(SelectedAnim|SelectedDatabase|bIsContinuingPoseSearch|SearchCost) et AnimPlayers[].InternalTimeAccumulator (qui doit AVANCER entre deux dumps espacĂ©s dans le temps — sinon la pose est rĂ©ellement figĂ©e, pas juste "en cours de transition").

  • PoseSearchDatabase — Ă©chec silencieux de build d'index et non-avancement figĂ© sur une frame (2026-09-06) : un PoseSearchDatabase en mode PCAKD_TREE (valeur par dĂ©faut) peut Ă©chouer Ă  construire son index dĂšs le chargement du projet si son jeu d'animations sources est trop petit/peu variĂ© pour que le calcul PCA converge — log LogPoseSearch: Error: <hash> - <NomDatabase> BuildIndex Failed because of 'No Convergence' while calculating PCA data (visible uniquement via GetLogEntries sur LogPoseSearch, jamais remontĂ© cĂŽtĂ© Blueprint/PIE). Tant que l'index reste dans cet Ă©tat, TOUTE recherche dessus Ă©choue en silence (SearchCost=FLT_MAX, SelectedAnim=None) et spam LogPoseSearch: Warning: UPoseSearchLibrary::MotionMatch - some searches have been skipped, since databases AsyncBuildIndex are in still in progress or failed Ă  chaque tick. Fix testĂ© et qui fonctionne : db.set_editor_property("PoseSearchMode", unreal.PoseSearchMode.BRUTE_FORCE) (au lieu de PCAKD_TREE) + sauvegarde (EditorAssetLibrary.save_asset(path, only_if_is_dirty=False) — nĂ©cessite PIE ARRÊTÉ, sinon retourne False sans erreur) — BRUTE_FORCE n'a pas besoin de PCA et convient trĂšs bien Ă  une petite database (coĂ»t de recherche linĂ©aire nĂ©gligeable Ă  cette Ă©chelle). Second piĂšge indĂ©pendant, NON contournable trouvĂ© Ă  ce jour : le tableau DatabaseAnimationAssets (alias historique AnimationAssets) d'un PoseSearchDatabase est protĂ©gĂ© en lecture ET Ă©criture pour TOUTE mĂ©thode testĂ©e (get_editor_property/set_editor_property Python, ET ObjectTools.get_properties/set_properties en C++ natif — qui pourtant contournent d'autres restrictions Python) ; seule la lecture BRUTE via obj dump "<chemin>.<NomAsset>" (PAS juste <chemin> seul, qui ne dump que le Package) expose son contenu texte (DatabaseAnimationAssets(i)=(AnimAsset=...,SamplingRange=(Min=...,Max=...),...)), sans Ă©quivalent en Ă©criture connu. ATTENTION Ă  la sĂ©mantique de SamplingRange (erreur de diagnostic commise puis corrigĂ©e le 2026-09-06) : (Min=0, Max=0) ne signifie PAS « plage vide » mais « ÉCHANTILLONNER TOUT LE CLIP » — c'est la valeur NORMALE, utilisĂ©e par toutes les databases saines du projet (vĂ©rifiĂ© sur PSD_Dense_Stand_Walk_Loops, PSD_Dense_Stand_Idles). Le cas rĂ©ellement pathologique est Min == Max != 0, en particulier (longueur_du_clip, longueur_du_clip) : fenĂȘtre de largeur nulle collĂ©e Ă  la FIN du clip. Double consĂ©quence : (a) plus rien Ă  lire, et (b) FPoseSearchDatabaseSequence::IsLooping() exige SamplingRange == (0,0) EN PLUS de AnimSequence->bLoop, donc l'asset devient non-bouclable (bLoopAnimation=False dans le dump du nƓud) mĂȘme si l'AnimSequence source est bien Loop=True — d'oĂč un gel sur une frame unique. SymptĂŽme observable : AnimPlayers[].InternalTimeAccumulator identique entre deux obj dump espacĂ©s de plusieurs secondes rĂ©elles en PIE. Correction = remettre la plage Ă  0 / 0 Ă  la main dans l'Ă©diteur Pose Search Database.

  • PIÈGE CRITIQUE — EditorAssetLibrary.consolidate_assets() fait planter l'Ă©diteur sur certains types de classes (2026-09-08, dĂ©doublonnage de l'import Game Animation Sample) : cette fonction (fusionne toutes les rĂ©fĂ©rences d'un doublon vers l'asset gardĂ©, supprime le doublon, laisse un ObjectRedirector) est fiable Ă  100% sur les assets de donnĂ©es pures (UserDefinedEnum, UserDefinedStruct, CurveFloat, ChooserTable, CameraRigAsset, CameraAsset, ControlRigBlueprint, ProxyAsset — testĂ© sur ~85 assets sans un seul Ă©chec) mais crashe le processus Ă©diteur de façon reproductible (Assertion failed: NewEditorElement.Private_GetInternalData()->GetRefCount() <= 1 ... The old and new element both have external references!, LogPython: Error: Python execution caused a crash (exception code: 0xC0000005) — l'Ă©diteur entier finit par Engine exit requested, pas juste l'interprĂ©teur Python) sur les ActorComponent Blueprints activement utilisĂ©s comme composant (constatĂ© sur AC_PreCMCTick, AC_SmartObjectAnimation) et sur les Blueprint Interfaces largement implĂ©mentĂ©es (BPI_SandboxCharacter_Pawn). Les Blueprints "de classe" simples (GameMode, modes de mouvement Mover, transitions) consolident sans problĂšme. Ne jamais retenter consolidate_assets une seconde fois sur le mĂȘme asset aprĂšs un premier crash — utiliser Ă  la place, dans l'ordre de prĂ©fĂ©rence : (1) EditorAssetLibrary.delete_asset() en brut si AssetRegistry.get_referencers() confirme que plus rien ne rĂ©fĂ©rence le doublon (le plus sĂ»r, fonctionne mĂȘme sur les types Ă  risque — mais peut prendre 1 Ă  4 minutes sur un projet avec des dizaines de milliers d'assets, l'appel execute_python_code timeout cĂŽtĂ© client mais l'opĂ©ration continue et rĂ©ussit cĂŽtĂ© serveur : revĂ©rifier via does_asset_exist plutĂŽt que de conclure Ă  un Ă©chec sur un timeout) ; (2) si des rĂ©fĂ©rences externes subsistent, les repointer manuellement d'abord — BlueprintTools.set_parent() pour un reparentage, BlueprintTools.retarget_node_class(node, old_class, new_class) pour un nƓud de cast/appel de fonction/Ă©vĂ©nement avec une classe figĂ©e Ă  l'ancien doublon (fonctionne bien, contrairement Ă  consolidate_assets) — puis delete_asset une fois les rĂ©fĂ©renceurs Ă  zĂ©ro. Effet de bord du crash : le processus Ă©diteur entier redĂ©marre, ce qui remet l'interprĂ©teur Python Ă  zĂ©ro mais PAS l'Ă©tat sauvegardĂ© sur disque — toute opĂ©ration dĂ©jĂ  sauvegardĂ©e (compile+save) avant le crash est conservĂ©e ; seule la commande en cours au moment du crash est perdue. Toujours vĂ©rifier is_in_pie/un print("ping") trivial aprĂšs CE type d'erreur avant de continuer : contrairement Ă  une simple corruption d'interprĂ©teur (SystemError: unknown opcode, rĂ©cupĂ©rable seulement par redĂ©marrage Ă©diteur elle aussi), celle-ci relance le processus tout seul en quelques dizaines de secondes.

  • Corollaire — reparenter un Blueprint dont les enfants rĂ©fĂ©rencent des COMPOSANTS PAR NOM (2026-09-08) : si un Blueprint enfant (ex. SandboxCharacter_Mover_Ragdoll) a des nƓuds Variables|Default|GetXxx/SetXxx qui lisent des variables membres du PARENT (ex. SkeletalMesh, Capsule, CharacterMover — des variables de CACHE exposant les composants SCS rĂ©els, PAS les composants eux-mĂȘmes) et qu'on reparente vers un parent qui n'a pas ces variables sous ce nom exact, la compilation Ă©choue avec The property associated with <Nom> could not be found. Fix simple et Ă  fort effet de levier : ajouter au NOUVEAU parent des variables membres du mĂȘme nom/type exacts (BlueprintTools.add_object_variable/add_struct_variable/add_variable) — TOUS les nƓuds orphelins portant ce nom, dans TOUTES les fonctions de TOUS les enfants, se re-rĂ©solvent automatiquement Ă  la compilation suivante, sans toucher un seul nƓud individuellement (testĂ© sur ~90 rĂ©fĂ©rences rĂ©parties dans 28 fonctions, rĂ©solu par l'ajout de 8 variables). Il n'est PAS nĂ©cessaire que ces variables soient effectivement peuplĂ©es/cĂąblĂ©es pour que la compilation rĂ©ussisse — seule leur EXISTENCE avec le bon nom/type compte pour le compilateur ; les peupler (ex. dans EventBeginPlay) reste nĂ©cessaire pour un comportement correct Ă  l'exĂ©cution.

  • connect_pins/write_graph_dsl peuvent devenir silencieusement des no-op aprĂšs une session trĂšs longue avec plusieurs crashs Ă©diteur (2026-09-08) : en fin de session, aprĂšs plusieurs cycles crash/redĂ©marrage, connect_pins(PinID_output, PinID_input) a cessĂ© de produire une erreur mais aussi de produire un effet (get_node_infos confirme aprĂšs coup qu'aucune des deux pins n'est connectĂ©e) — reproduit mĂȘme sur une paire de nƓuds fraĂźchement créés dans le MÊME appel Python, et mĂȘme sur un Blueprint diffĂ©rent qui avait fonctionnĂ© plus tĂŽt dans la session. Aucune cause identifiĂ©e avec certitude (suspectĂ© : Ă©tat de l'Ă©diteur dĂ©gradĂ© par l'accumulation de crashs, pas un bug systĂ©matique de l'outil — connect_pins a fonctionnĂ© de façon fiable pendant le reste de la session). Si connect_pins semble rĂ©ussir sans erreur mais que get_node_infos ne montre ensuite AUCUNE connexion sur les pins concernĂ©es, ne pas insister : passer Ă  une mĂ©thode alternative (repenser le fix pour n'avoir besoin que d'ajouts de variables/fonctions, voir point ci-dessus) plutĂŽt que de perdre du temps Ă  re-essayer la mĂȘme primitive.

  • Écrire dans une ChooserTable (colonnes) depuis un script (2026-09-06) : ColumnsStructs se LIT en Python (get_editor_property + .export_text() sur chaque InstancedStruct) mais ne s'ÉCRIT PAS par cette voie — InstancedStruct.import_text(nouveau_texte) renvoie True en mentant (le contenu de l'Ă©lĂ©ment reste inchangĂ©), et le set_editor_property("ColumnsStructs", ...) qui suit ne remonte donc rien, sans lever d'exception. Voie qui fonctionne : le toolset Python editor_toolset.toolsets.object.ObjectTools (importable directement : from editor_toolset.toolsets.object import ObjectTools), qui expose la table en JSON — json.loads(ObjectTools.get_properties(chooser, ["ColumnsStructs"])), modification du dict (ex. col["rowValuesWithAny"][i] = "MatchAny"), puis ObjectTools.set_properties(chooser, json.dumps(data)) qui renvoie True et applique rĂ©ellement. ResultsStructs (rĂ©sultats des lignes) reste inaccessible par toutes les voies testĂ©es : on peut donc MODIFIER une ligne existante mais pas en AJOUTER une nouvelle par script.

  • EditorAssetLibrary.save_asset/save_loaded_asset peuvent renvoyer False alors que l'asset est parfaitement sauvegardable, PIE arrĂȘtĂ© et fichier non-verrouillĂ© (constatĂ© sur CHT_PoseSearchDatabases_Dense aprĂšs une Ă©criture via ObjectTools.set_properties, probablement parce que le package n'est pas marquĂ© dirty par cette voie). Ne pas en conclure Ă  un Ă©chec : passer par unreal.EditorLoadingAndSavingUtils.save_packages([obj.get_outermost()], False) qui renvoie True et met bien Ă  jour le mtime du .uasset (Ă  vĂ©rifier via os.path.getmtime, seule preuve fiable d'Ă©criture disque).

  • Outillage dĂ©couvert le 2026-09-13 (rĂ©paration post-migration) : (a) BlueprintEditorLibrary.compile_blueprint / BlueprintTools.compile_blueprint ne lĂšvent AUCUNE exception sur erreur de compilation — encadrer les compilations de marqueurs unreal.log_warning("MARQUEUR") puis lire Saved/Logs/ProjectFv1.log entre les marqueurs (LogBlueprint: Error). (b) BlueprintTools.set_pin_value (et d'autres outils du toolset) peut SAUVEGARDER l'asset sur disque sans le dire — sauvegarder le fichier avant d'expĂ©rimenter. (c) retarget_node_class / change_member_variable_type ne rafraĂźchissent pas les types de pins en cache (erreurs « X is not compatible with X ») : sauvegarder, EditorLoadingAndSavingUtils.reload_packages, recompiler — le rechargement reconstruit les nƓuds. (d) Le struct PinID n'est pas exposĂ© en Python : pour connect_pins/break_pins, passer par ProgrammaticToolset.execute_tool_script (appel get_execution_environment requis avant) avec des PinID JSON {direction, index_id, node:{refPath}}. (e) Les pins d'un nƓud Evaluate Chooser portent le NOM de l'asset struct de contexte : changer/renommer/fusionner la struct laisse des pins orphelines liĂ©es (« In use pin ... no longer exists ») Ă  rebrancher. (f) EditorAssetLibrary.consolidate_assets sur des UserDefinedStruct sauvegarde automatiquement les rĂ©fĂ©renceurs et crĂ©e les redirecteurs. (g) ChooserTable.ContextData s'Ă©crit via ObjectTools.set_properties (JSON _structType/class/struct → refPath) + EditorLoadingAndSavingUtils.save_packages. (h) Une rĂ©fĂ©rence passant par un .ini (ex. GameplayTagTableList) est invisible pour l'Asset Registry : vĂ©rifier Config/ avant de dĂ©clarer un asset « sans rĂ©fĂ©rence ».

  • PIÈGE CRITIQUE — consolidate_assets sur une UserDefinedEnum (probablement aussi une UserDefinedStruct) vide silencieusement les types de variables des rĂ©fĂ©renceurs (2026-09-14) : les rĂ©fĂ©rences dures sont réécrites, mais le PinSubCategoryObject des variables membres (et types de valeur de map) typĂ©es par l'enum fusionnĂ© tombe Ă  None : la variable devient un simple byte. La classe compilĂ©e garde le bon type, donc tout compile. Au rechargement suivant du package (les rĂ©fĂ©renceurs sont auto-sauvegardĂ©s par la fusion), les liens devenus incompatibles sont supprimĂ©s, des nƓuds Equal/NotEqual (Enum) redeviennent Wildcard et l'Ă©diteur insĂšre des CastByteToEnum. Une entrĂ©e qui garde une valeur littĂ©rale compile toujours : la logique est fausse SANS erreur (ex. SandboxCharacter_Mover_ABP : 19 variables vidĂ©es → 2259 erreurs au rechargement ; BP_NotifyState_EarlyTransition : 5 liens perdus dont 1 sans erreur). Les K2Node_SwitchEnum ne reconstruisent leurs sorties qu'au rechargement du package. ProcĂ©dure : sauvegarder tous les rĂ©fĂ©renceurs avant la fusion ; juste aprĂšs et AVANT tout rechargement, scanner BlueprintEditorLibrary.get_member_variable_type(bp, v).export_text() (PinSubCategoryObject=None) et retyper via change_member_variable_type ; si un rĂ©fĂ©renceur a dĂ©jĂ  Ă©tĂ© rechargĂ© cassĂ©, le restaurer depuis la sauvegarde (Ă©diteur fermĂ©) ou comparer ses liens Ă  un jumeau intact (BlueprintTools.get_node_infos), rebrancher et supprimer les casts (delete_node) ; valider par reload_packages d'UN seul package Ă  la fois (jamais un Blueprint en mĂȘme temps qu'un Blueprint dont il dĂ©pend). Pour des Blueprints entiers, prĂ©fĂ©rer un dĂ©placement Ă  une fusion.

  • CRASH ÉDITEUR — handles Python sur des nƓuds supprimĂ©s (2026-09-14) : BlueprintTools.delete_node puis compile_blueprint dans le MÊME exec, alors que des variables Python gardent les handles de nƓuds / structs de pins (get_node_infos) des nƓuds supprimĂ©s → EXCEPTION_ACCESS_VIOLATION dans python311.dll et fermeture de l'Ă©diteur. Fix qui a fonctionnĂ© : exĂ©cuter l'Ă©dition, la compilation/sauvegarde et tout ce qui dĂ©clenche un GC (suppression d'assets, reload_packages) dans des callbacks register_slate_post_tick_callback SÉPARÉS, chacun dans un dictionnaire de globals neuf, avec scope.clear() + gc.collect() entre les Ă©tapes et unreal.SystemLibrary.collect_garbage() au dĂ©but de l'Ă©tape suivante. Ne sauvegarder qu'aprĂšs une vĂ©rification : un crash ne laisse alors rien de corrompu sur disque. Relance : E:\UE_5.8\Engine\Binaries\Win64\UnrealEditor.exe "E:\projet\ProjectFv1\ProjectFv1.uproject" (MCP disponible ~20 s aprĂšs).

  • Asset Registry pĂ©rimĂ© aprĂšs sauvegarde + rechargement (2026-09-14) : get_dependencies/get_referencers peuvent encore lister une rĂ©fĂ©rence qu'un asset n'a plus (ex. PC_Sandbox → widget de dĂ©mo retirĂ©, alors que le .uasset ne contient plus ce nom). Forcer AssetRegistry.scan_paths_synchronous([dossier], True) avant de vĂ©rifier des rĂ©fĂ©renceurs.

  • EditorAssetLibrary.delete_asset sur une map non chargĂ©e (/Game/dev_map) peut renvoyer True en laissant le .umap sur disque et une dĂ©pendance fantĂŽme dans l'Asset Registry (qui ferait recharger/rĂ©enregistrer la map lors d'un renommage de ses dĂ©pendances). VĂ©rifier le fichier sur disque ; s'il reste, le supprimer puis scan_files_synchronous([fichier], True).

  • Assigner un squelette Ă  une animation qui n'en a pas (2026-09-14) : AnimSequence.Skeleton est en lecture seule pour set_editor_property ET refusĂ© par ObjectTools.set_properties ; aucun service VibeUE (SkeletonService, AnimSequenceService, AnimMontageService) ne l'expose (lecture/compatibilitĂ© seulement). Seule voie : ouvrir l'asset dans l'Ă©diteur, qui propose de choisir un squelette, puis sauvegarder. Avant, vĂ©rifier la compatibilitĂ© : AnimationLibrary.get_animation_track_names(anim) comparĂ© aux os du mesh cible (SkinnedMeshComponent.get_num_bones/get_bone_name sur le composant mesh du CDO du personnage).

  • DĂ©tecter des rĂ©gressions d'assets binaires via git : git show <commit>:<fichier> | git lfs smudge restitue l'ancien .uasset ; comparer l'ensemble des chaĂźnes /Game/... (table des noms) entre ancienne et nouvelle version rĂ©vĂšle les rĂ©fĂ©rences perdues (lignes de chooser, bases d'un schĂ©ma, BPI d'un canal) sans ouvrir l'Ă©diteur.

  • DĂ©placer un dossier via AssetTools.rename_assets (liste d'AssetRenameData, un seul appel pour tout le lot) réécrit et sauvegarde lui-mĂȘme les rĂ©fĂ©renceurs, sans laisser de redirecteur quand tous sont chargeables (112 assets en ~32 s le 2026-09-14). Le coĂ»t dĂ©pend du nombre de rĂ©fĂ©renceurs : un notify utilisĂ© par des milliers d'animations oblige Ă  toutes les rĂ©enregistrer.


10. Maintenir ce document Ă  jour

Ce document doit toujours reflĂ©ter l'Ă©tat rĂ©el du projet. Un skill dĂ©diĂ© — maintain-architecture-doc (.claude/skills/maintain-architecture-doc/SKILL.md) — rappelle systĂ©matiquement aux modĂšles d'IA de :

  1. Consulter ce document avant de modifier la structure du projet.
  2. Le mettre à jour aprÚs toute création/suppression/déplacement/renommage de fichier ou dossier important.
  3. Ajouter une description pour tout nouveau fichier important.
  4. Retirer les entrées obsolÚtes (fichiers supprimés).
  5. Corriger les chemins aprÚs un déplacement.
  6. Mettre à jour les descriptions quand un systÚme évolue significativement.
  7. Vérifier périodiquement la cohérence entre ce document et l'arborescence réelle.
  8. Ne jamais laisser ce document dans un état sciemment obsolÚte aprÚs une modification de structure.

RĂšgle de detail : un fichier "important" Ă  documenter est un Blueprint/Widget/Data Asset/Struct/Enum/Input Action qui porte de la logique ou des donnĂ©es de gameplay. Les assets purement artistiques individuels (textures, meshes, clips d'animation, miniatures) n'ont pas besoin d'entrĂ©e dĂ©diĂ©e — il suffit que leur dossier parent soit listĂ© et dĂ©crit (cf. §8).

Historique de nettoyage :

  • 2026-09-04 : Content/Systems/Blueprints/d/SandboxCharacter_CMC_ABP renommĂ©/dĂ©placĂ© vers Content/Systems/Blueprints/SandboxCharacter_CMC_ABP via l'outil de renommage Unreal (les 7 rĂ©fĂ©rences ont Ă©tĂ© recĂąblĂ©es automatiquement, compilation vĂ©rifiĂ©e OK).

  • 2026-09-04 : suppression de 8 redirecteurs Unreal morts (rĂ©sidus de renommages passĂ©s, 0 rĂ©fĂ©rence chacun, confirmĂ©s sans danger) : Content/Systems/Stats/ACStats.uasset, Content/Systems/Movement/BPC_ClimbingComponent.uasset, Content/Systems/Movement/ClimbingMaterial.uasset, Content/Systems/Movement/CR_ClimbingGraphV2.uasset, Content/Systems/Movement/CR_Mannequin_BasicFootIK.uasset, Content/BP_TickManager.uasset, Content/dqs.uasset, Content/E_WeaponType.uasset. Les vraies versions de ces assets restent Ă  Content/Systems/Movement/Climbing/, Content/Core/Tick/BP_TickManager et Content/Data/Enums/E_WeaponType.

  • 2026-09-13 : rĂ©paration aprĂšs la migration Project_F → ProjectFv1 (voir §8.2) — 782 fichiers UltraDynamicSky restaurĂ©s depuis git, contexte de 7 chooser tables remis sur Systems/Blueprints, 3 structs identiques de Content/Blueprints/Data/ fusionnĂ©es (redirecteurs), suppression de Content/Blueprints/SandboxCharacter_CMC + _ABP (doublon GASP), tags Foley.Event.*/SmartObject.ObjectType.* ajoutĂ©s. Compilation complĂšte : 435 Blueprints, 0 erreur.

  • 2026-09-13 (nettoyage, Ă©tapes 1-2) : suppression des personnages de dĂ©mo Echo/Paragon/UE4_Mannequin/UE5_Mannequins, de MetaHumans/ et des BP RetargetedCharacters/BP_* ; rangement de SandboxCharacter_CMC → Core/Character/, BP_GameInstance → Core/, DT_DemoTags → Data/ (config mise Ă  jour) ; suppression de DT_DemoTags.T3D et des dossiers vides (dont Content/Collections/, Content/Developers/). Compilation : 405 Blueprints, 0 erreur.

  • 2026-09-13/14 (nettoyage, Ă©tape 3) : suppression des redirecteurs morts aprĂšs re-sauvegarde de leurs rĂ©fĂ©renceurs (dont Animations/anim_Swim*, Core/PlayerController/IA_InitiateClimb|IA_LeapFromClimb|IA_MovingClimb, PSD_Relaxed_Stand_Sprint_Pivots, les redirecteurs du 2026-09-04 encore suivis par git, et les redirecteurs de structs de Content/Blueprints/Data/).

  • 2026-09-14 : convergence des enums du framework dupliquĂ© et rĂ©paration des Blueprints touchĂ©s (voir §8.2) ; GM_Dev → SandboxCharacter_CMC. Passe complĂšte : 405 Blueprints ; seule erreur restante BP_Item_AdvancedRifle (Reload_Rifle_Hip sans squelette, antĂ©rieure) + avertissement Ultra_Dynamic_Weather. Commit intermĂ©diaire (point de restauration) avant le dĂ©placement du reste de Content/Blueprints/ vers Content/Systems/Mover/.

  • 2026-09-14 (isolation du framework du sample) : dĂ©mo GASP supprimĂ©e (dev_map, Content/Levels/LevelPrototyping/, Content/Widgets/) aprĂšs avoir dĂ©tachĂ© AC_TraversalLogic (branche LevelBlock_Traversable) et PC_Sandbox (widget de dĂ©mo) ; 17 redirecteurs d'enum supprimĂ©s ; 112 assets dĂ©placĂ©s sans fusion (Content/Blueprints/ → Systems/Mover/ sauf AnimNotifies/, Aiming/ → Systems/Aiming/, Content/Input/ → Systems/Mover/Input/, E_WaponType → Data/Enums/), rĂ©fĂ©rences réécrites, aucun redirecteur restant. ContrĂŽle aprĂšs redĂ©marrage complet de l'Ă©diteur : liens de graphe, valeurs de pins et types de variables des 66 Blueprints concernĂ©s encore existants identiques au relevĂ© pris avant le dĂ©placement (seuls Ă©carts : chemins réécrits et artefacts de l'outil de comparaison). Compilation complĂšte : 379 Blueprints, seule erreur BP_Item_AdvancedRifle (Reload_Rifle_Hip sans squelette, antĂ©rieure).

  • 2026-09-14 (reprise) : test PIE sur MapDev1 — GM_Dev fait apparaĂźtre SandboxCharacter_CMC, aucune erreur de Blueprint Ă  l'exĂ©cution. Seuls messages, antĂ©rieurs : Systems/Weather/UltraDynamicSky/Particles/Snow rĂ©fĂ©rence encore l'ancien chemin /Game/UltraDynamicSky/Particles/UDW_Niagara_Parameters, et 4 avertissements Pose Search d'entrĂ©es vides dans PSD_SwimmingIdle/PSD_SwimmingMovingSprint (contenu inchangĂ© depuis d29748b, de nouveau chargĂ© grĂące au chooser restaurĂ©). Restauration depuis d29748b des 7 donnĂ©es Motion Matching dĂ©gradĂ©es par la migration (voir §8.2) avec fix MatchAny refait, et de NS_Tornado. Compilation complĂšte : 379 Blueprints, seule erreur BP_Item_AdvancedRifle (Reload_Rifle_Hip sans squelette, antĂ©rieure).

  • 2026-09-14 (mĂ©tĂ©o) : corrections du systĂšme mĂ©tĂ©o projet (WB_WeatherControl/WB_WeatherZone, voir §4 Weather). Bugs corrigĂ©s : setWeatherbetweenZone lisait deux fois Zone2 ; GetNearZone ne trouvait jamais de zone (distances locales Ă  0, poids 0/0 et inversĂ©s) ; SetNuage/MakeTemp retournaient 0 sans zone voisine (return dans la boucle) et clampaient la tempĂ©rature Ă  0–10 ; makestate renvoyait un Ă©tat vide (branche froide nuages ≄ 8) et ne calculait ni vent/brouillard/poussiĂšre ni humiditĂ© ; MakeForcast avait des pas de 0–1 s ; UpdateWeatherstate n'avançait jamais le temps (+0) ; rayon d'influence ≈ 900 uu et tri Trie zone pouvant boucler Ă  l'infini ; overlaps dĂ©clenchĂ©s par n'importe quel acteur ; saison en secondes. Nouveaux : fonctions StepForecast, ApplyToUDW, GetZoneState ; variables ForecastStepMin/Max, InfluenceRadius, LastUpdateTime (zone), SeasonDurationScale (contrĂŽleur). [CoreRedirects] UDS + 10 systĂšmes Niagara re-sauvegardĂ©s. PIE OK (zones prĂȘtes, 16 prĂ©visions, poids 0.52/0.48, UDW alimentĂ©, aucune erreur mĂ©tĂ©o). Restant : WeatherData des 2 zones de MapDev1 vide (0 °C / 0 %), BP_TickManager transmet un DeltaTime ~10× trop petit au contrĂŽleur (saison lente), avertissement d'attache des ChildActor UDS/UDW (mobilitĂ©). Sauvegarde des assets avant modification : E:\projet\ProjectFv1_backup_migration_2026-09-13\weather_before_fixes_2026-09-14\.

  • 2026-09-18 (migration cover / prone / nage du CMC vers le Mover, voir §4.2.2) : SandboxCharacter_Mover reçoit AC_Cover + Arrow1, les variables et fonctions de cover/prone/nage, l'enregistrement du mode « Swimming » au BeginPlay, et ses fonctions Get_Gait/Get_MoveInput/Get_PropertiesForAnimation/On_PreSimulateTick Ă©tendues. Nouveaux assets : Systems/Mover/MovementModes/BP_MovementMode_Swimming, Characters/UEFN_Mannequin/Animations/MotionMatchingData/CHT_PoseSearchDatabases_Mover. Corrections annexes : BP_MovementMode_Walking (vitesse/accĂ©lĂ©ration nulles pour les allures prone et nage), MovementModeMap (Ragdoll→Climbing et Flying→SwimmingOnSurface, sĂ©quelles de la fusion des enums — le ragdoll du pion refonctionne), SandboxCharacter_Mover_ABP (contexte self absent des Evaluate Chooser → branche Motion Matching inerte ; nouvelle bascule AnimBranchIndex). TestĂ© en PIE : prone (capsule 40 ↔ 86 via le StanceModifier, base PSD_Dense_Prone_Idles sĂ©lectionnĂ©e), nage dans WaterBodyLake_0 (entrĂ©e/flottaison Ă  la profondeur cible/plongĂ©e/sortie, PSD_SwimmingIdle sĂ©lectionnĂ©e), accroupi de couverture. NON testĂ© : entrĂ©e en couverture par la touche P et dĂ©placement le long d'un vrai mur. Sauvegarde des assets avant modification : E:\projet\ProjectFv1_backup_mover_migration_2026-09-17\.

  • 2026-09-18 (suite) : Ă  la demande de l'utilisateur, SandboxCharacter_Mover_ABP passe entiĂšrement en Motion Matching — Update_Logic ne calcule plus la bascule, AnimBranchIndex est fixĂ© Ă  0 (nƓuds Select / Not Equal (Enum) / AND / Get Stance supprimĂ©s, valeur par dĂ©faut de la variable mise Ă  0). Diagnostic de la T-pose en nage : ce n'Ă©tait pas l'ABP mais le contenu — 5 des 6 bases Pose Search de nage n'ont que des lignes Ă  AnimAsset = None et la table SwimmingInDeepIdle du chooser est vide ; seul PSD_SwimmingMoving est rempli. Contournement dans CHT_PoseSearchDatabases_Mover (lignes vers bases vides neutralisĂ©es, lignes 13/16 Ă©largies en MatchAny), dĂ©tail et procĂ©dure de correction dĂ©finitive en §4.2.2. VĂ©rifiĂ© en PIE avec MM permanent : idle debout (PSD_Relaxed_Stand_Idles), course avant (PSD_Relaxed_Stand_Run_F_Starts/Loops), prone (PSD_Dense_Prone_Idles → anim_Prone_Idle), nage surface immobile / en mouvement et nage profonde (PSD_SwimmingMoving → RM_Breastroke_overwater_01_right_turn_Retargeted).

  • 2026-09-19 (systĂšme d'armes sur le Mover, voir §4.2.3) : AC_Weapon::Equip/Unequip reçoivent une branche Cast Failed → SandboxCharacter_Mover (leur Cast To SandboxCharacter_CMC Ă©chouait en silence sur le Mover, d'oĂč Weapon/isArmed jamais renseignĂ©s). Nouvelle fonction SandboxCharacter_Mover::SetEquippedWeapon + variables Weapon_Equip/WantToshot sur le pion, Weapon_Equip/Weapon_Equip Last Frame/Want Toshot sur SandboxCharacter_Mover_ABP (alimentĂ©es dans Update_PropertiesFromCharacter, thread principal). IA_Aim renseigne WantToshot. Update_MotionMatching consulte aussi CHT_PoseSearchDatabases_Mover quand Is Armed, et Get_MMInterruptMode force l'interruption au changement d'arme. Dans CHT_PoseSearchDatabases_Mover : colonnes Is Armed et IS Moving Object rĂ©activĂ©es, ligne 1 (« Stand Idles Bow ») passĂ©e en Gait = MatchAny. TestĂ© en PIE de bout en bout (ramassage → main → anims arc → visĂ©e → tir) avec non-rĂ©gression prone/nage. Inventory_Equipper.uasset apparaĂźt modifiĂ© sans changement de contenu (resauvegarde automatique du MCP, mĂȘmes rĂ©fĂ©rences /Game/).

  • 2026-09-19 (MetaHuman en visual override, voir §4.2.4) : une premiĂšre tentative mettait le corps MetaHuman directement comme mesh du pion (squelettes dĂ©clarĂ©s compatibles + sockets recopiĂ©es) ; elle a Ă©tĂ© annulĂ©e au profit de l'approche du sample GASP. Restauration de ABP_GenericRetarget depuis le commit initial (supprimĂ© au nettoyage de la dĂ©mo GASP), crĂ©ation de IK_MetaHuman_test, RTG_UEFN_to_MetaHuman_test et BP_VisualOverride_MetaHuman dans Systems/Mover/VisualOverrides/, GM_Dev reparentĂ© sur GM_Sandbox (il Ă©tait vide) et VisualOverrides_Soft renseignĂ©, dĂ©faut du CVar DDCvar.VisualOverride passĂ© de -1 Ă  0. Limite connue : les objets Ă©quipĂ©s restent accrochĂ©s au mannequin cachĂ©, ~12 cm d'Ă©cart avec la main du MetaHuman.