890 lines
190 KiB
Markdown
890 lines
190 KiB
Markdown
# đïž 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](#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](#9-notes-pour-les-ia-piĂšges-connus-de-loutillage) 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
|
||
|
||
```text
|
||
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" :
|
||
|
||
```text
|
||
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.
|
||
|
||
```text
|
||
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
|
||
|
||
```text
|
||
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.
|
||
|
||
```text
|
||
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).
|
||
|
||
```text
|
||
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)
|
||
|
||
```text
|
||
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
|
||
|
||
```text
|
||
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
|
||
|
||
```text
|
||
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/`
|
||
|
||
```text
|
||
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.
|
||
|
||
```text
|
||
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.*
|