Point de restauration : réparation post-migration, nettoyage démo, convergence des enums

- Réparation après la migration Project_F -> ProjectFv1 : météo restaurée depuis git,
  contexte des chooser tables CMC/traversal remis sur Systems/Blueprints, 3 structs
  identiques fusionnées, doublon GASP SandboxCharacter_CMC supprimé, tags
  Foley.Event.* / SmartObject.ObjectType.* ajoutés.
- Nettoyage : personnages de démo (Echo, Paragon, UE4/UE5 Mannequins), MetaHumans et
  BP RetargetedCharacters supprimés ; redirecteurs morts supprimés ;
  SandboxCharacter_CMC -> Core/Character, BP_GameInstance -> Core,
  DT_DemoTags -> Data (config mise à jour) ; ProjectF.uproject -> ProjectFv1.uproject.
- Convergence partielle : 17 enums du sample (Content/Blueprints) fusionnés dans
  Systems/Blueprints (valeurs Ragdoll/Flying/Debug Flying Loop ajoutées en fin d'enum),
  chaîne Mover et notifies réparés et validés par rechargement ; GM_Dev -> SandboxCharacter_CMC.
- Compilation : 405 Blueprints, seule erreur restante BP_Item_AdvancedRifle
  (Reload_Rifle_Hip sans squelette, antérieure).
- Architecture_Projet.md mis à jour.

Non inclus volontairement : suppression de Content/Systems/Weather/Tornado/NS_Tornado.uasset
(antérieure à cette session, à confirmer).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
DodoandClaude Opus 5 committed 2026-09-14 01:31:52 +02:00
1 parent d29748b8ab
commit 6eb751657f
2474 files changed
+6259 -3077

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
{
"mcpServers":
{
"unreal-mcp":
{
"url": "http://127.0.0.1:8000/mcp"
}
}
}
+281 -27
View File
@@ -28,7 +28,7 @@ Le projet est construit par empilement de **trois grands blocs** de contenu, plu
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 `ProjectF.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.
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/`).
@@ -41,6 +41,16 @@ Character (Pawn, géré par le framework "Sandbox Character")
│ └─ 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
@@ -49,12 +59,87 @@ Character (Pawn, géré par le framework "Sandbox Character")
│ └─ 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
│ └─ 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.
│ **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 N'EXISTENT PLUS dans l'asset actuel (seul son contexte a été remis sur
│ `Systems/Blueprints/SandboxCharacter_CMC_ABP`). À refaire à la main ; la version du commit `d29748b` (LFS) contient
│ encore les lignes Bow d'origine (sans le fix MatchAny du 2026-09-06).
│ **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…
│
└─ Autres composants gameplay (AC_ScentPoint, etc.)
├─ 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
@@ -64,6 +149,12 @@ Interactables (Content/Systems/Inventory/Interactables/*)
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
@@ -116,7 +207,7 @@ 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
├── ProjectF.uproject → Fichier projet UE5.8 : liste des plugins activés (voir §1.2/§8)
├── 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
│
@@ -132,15 +223,15 @@ ProjectF/
├── Binaries/, Intermediate/, Saved/, DerivedDataCache/ → Générés par l'éditeur, exclus de Git, jamais à éditer/documenter
```
### 2.1 ⚠️ Fichiers isolés directement à la racine de `Content/`
### 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/
├── SandboxCharacter_CMC.uasset → ⭐ 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.
├── BP_GameInstance.uasset → 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).
└── DT_DemoTags.uasset (+ .T3D) → DataTable de tags, probablement un reste de test/démo. Aucune référence trouvée dans le projet au 2026-09-04 — candidate à la suppression, mais volontairement laissée en l'état (non confirmée inutile).
├── 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/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.
```
@@ -155,7 +246,7 @@ 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)
│ ├── 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)
@@ -241,8 +332,8 @@ Contenu très largement issu du sample Epic **Motion Matching** (plugins `Mover`
```text
Content/Systems/Blueprints/
├── BPI_SandboxCharacter_Pawn.uasset → Interface du Pawn joueur (point d'entrée du framework de locomotion)
├── BPI_SandboxCharacter_ABP.uasset → Interface de l'Anim Blueprint du personnage
├── 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
@@ -267,9 +358,13 @@ Content/Systems/Blueprints/
├── 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 (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, S_ChooserOutputs, S_MovementDirectionThresholds,
│ │ 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
@@ -278,7 +373,15 @@ Content/Systems/Blueprints/
│ ├── CHPA_SmartObject, AC_SmartObjectAnimation
│ └── SmartObjectAnimationPayload, SmartObjectSelectionInputs/Outputs
│
└── SandboxCharacter_CMC_ABP.uasset → Anim Blueprint principal du personnage joueur (piloté par `/Game/SandboxCharacter_CMC`). Anciennement égaré dans un dossier `d/` mal nommé — déplacé ici (nettoyage du 2026-09-04).
├── 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/Blueprints/` (voir §8.2). `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` ; `Content/Blueprints/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.3 Autres systèmes de gameplay (ajouts spécifiques au projet)
@@ -286,7 +389,35 @@ Content/Systems/Blueprints/
```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.
│ └── 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 (voir `BP_AnimalBase::PlayStateAnimation`) ; 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).
│ ├── 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).
│ ├── 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 (AnimSequence, un jeu à fournir par espèce). Fonctions clés : `MoveTo`/`StopMovementAnimal` (wrappers autour de l'AIController caché, utilisés par les tâches StateTree), `SetCurrentState` (met à jour l'enum de debug ET déclenche `PlayStateAnimation` — lecture d'anim en **Single Node** via `SkeletalMeshComponent::PlayAnimation`, PAS d'AnimBlueprint/State Machine : suffisant pour un premier jet crédible sans blending, cf. §9), `GetThreatLocation` (position du joueur si vu, sinon source d'odeur, 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` (ragdoll `SetAllBodiesSimulatePhysics`, 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 → `bWasHitRecently=true` ; 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), transitions globales posées sur `Root` (s'appliquent depuis N'IMPORTE quel état actif) : `→Flee` (priorité High, `bWasHitRecently` ET pas mort — coup reçu non-létal) et `→Dead` (priorité Critical, `bIsDead`).
│ └── 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)` puis termine immédiatement (`FinishTask`). 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 (ou après 30s de timeout de sécurité).
│ └── STT_MoveAwayFromThreat.uasset → Utilisé par `Flee`. À l'entrée : diffuse l'alerte à la horde puis calcule un point de fuite (direction opposée à `GetThreatLocation`, projeté sur le NavMesh, distance ≈ SafeDistance×1.3). Se ré-émet automatiquement un nouveau point de fuite si l'animal arrive à destination mais reste encore trop proche.
│
│ 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_*, HerdID "DeerHerd_A".
│ └── BP_Deer_Doe.uasset → SK_DeerDoe + jeu d'anims ANIM_DeerDoe_*, 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
@@ -296,12 +427,12 @@ Content/Systems/
│ ├── 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)
│
├── Scent/BP_ScentPoint.uasset → Point émetteur d'odeur (probablement pour une IA de traque par l'odorat)
├── 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
├── Tornado/BP_Tornado.uasset, NS_Tornado.uasset → Tornade dynamique (acteur + système Niagara), spécifique au projet. ⚠️ (constaté le 2026-09-14) `NS_Tornado.uasset` est absent du disque (suppression non commitée antérieure au 2026-09-13, fichier toujours présent dans git) : `BP_Tornado` le référence encore → erreur de chargement
└── 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).
```
@@ -347,14 +478,14 @@ Content/UI/
│ ├── 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[]
│ ├── WB_EquipSlot.uasset → Widget d'un slot d'équipement (arme/speed) — contient Container
│ ├── WB_EquipSlot.uasset → Widget d'un slot d'équipement (arme/speed) — contient Container. Var `OwnContainersHost` (2026-09-04) : si définie (WB_InventoryPart2), `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 (contient InventoryPart1/InventoryPart2)
│ │ ├── WB_InventoryPart1.uasset → Contient les 4 slots d'équipement (EquipSlotWEAPON, EquipSlotWEAPON2, EquipSlotSpeed1, EquipSlotSpeed2) + autres slots d'équipement (casque, gilet, gants, sac à dos…)
│ │ └── WB_InventoryPart2.uasset → Grille(s) d'inventaire principale(s)
│ │ └── WB_InventoryPart2.uasset → 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
│ │
@@ -363,7 +494,8 @@ Content/UI/
│ ├── 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).
│ ├── 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
@@ -385,19 +517,24 @@ Content/UI/
```text
Content/Items/ → Objets ramassables/équipables du jeu
├── BaseBlueprints/
│ ├── _BP_ItemBase.uasset → Blueprint BASE de tout item (racine de hiérarchie)
│ ├── BP_Item_HoldableBase.uasset → Base des items tenables en main
│ ├── _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_AdvancedRifle / _Backpack_Camper / _Backpack_Sport / _BodyArmor / _Flashlight /
│ _Gloves / _Helmet / _KevlarVest / _LightVest / _Siren.uasset → Blueprints d'items "portés" (racine d'Items/)
│ _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.
├── 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/, Weapon/ (Base_Bow, Base_knife), Tool/ (saucepan), Water/ (water_bottle),
├── 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/
│ → 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/
@@ -445,11 +582,40 @@ Content/Characters/ → Meshes/matériaux/textures des personnages et a
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)
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/LevelPrototyping/ → **(2026-09-08)** Kit de blockout du sample (LevelBlock, LevelButton,
Teleporter_Sender/Destination…) pour construire des niveaux de test. Sans lien avec
`Content/Maps/` (les vraies maps du projet) — laissé séparé intentionnellement.
Content/Thumbnails/ → Miniatures générées pour la Content Browser
Content/Collections/ → Collections d'assets (vide actuellement)
Content/Developers/catry/ → Dossier de développeur personnel (playground, Collections/) — non partagé/gameplay
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).
@@ -457,6 +623,42 @@ Content/__ExternalObjects__/ → ⚙️ Généré automatiquement par World Part
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/Blueprints/SmartObjects/AC_SmartObjectAnimation` : 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`). Reste une référence souple inoffensive dans `Content/Widgets/GameAnimationWidget`.
- `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 de `Content/Blueprints/` conservé volontairement (voir « Convergence partielle » ci-dessous) :
- `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`.
- `SandboxCharacter_Mover` / `_ABP` / `_Ragdoll` → personnage alternatif plugin Mover (+ `GM_Sandbox`/`PC_Sandbox`, `dev_map` de démo).
- le reste du framework dupliqué (AC_TraversalLogic, BPI_*, Data/, Cameras/, AnimNotifies/ — les animations migrées y sont liées). 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 est destiné à être seulement déplacé, sans fusion, vers `Content/Systems/Mover/` ; les doublons restants sont une dette connue.
É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), `Reload_Rifle_Hip`/`DeathAnim_AGIS` sans squelette, « 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
@@ -471,6 +673,50 @@ Ce projet est modifié via le plugin **VibeUE** (service MCP `unreal-mcp`, voir
- **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.
- 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.
---
## 10. Maintenir ce document à jour
@@ -492,4 +738,12 @@ Ce document **doit toujours refléter l'état réel du projet**. Un skill dédi
- *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`.*
*Point de nettoyage identifié mais volontairement non traité : `Content/DT_DemoTags.uasset` (+ `.T3D`) — aucune référence trouvée, semble être un reste de test, laissée en l'état à la demande de l'utilisateur (voir §2.1).*
- *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/`.*
*`Content/Data/DT_DemoTags.uasset` (anciennement à la racine) : longtemps considéré comme un reste de test sans référence — FAUX (vérifié le 2026-09-13) : c'est la table de tags AGIS déclarée dans `Config/DefaultGameplayTags.ini`, à conserver (voir §2.1).*
+65 -2
View File
@@ -1,7 +1,7 @@
[/Script/EngineSettings.GameMapsSettings]
GameDefaultMap=/Game/Maps/DevMap/MapDev1.MapDev1
EditorStartupMap=/Game/Maps/DevMap/MapDev1.MapDev1
GameInstanceClass=/Game/BP_GameInstance.BP_GameInstance_C
GameInstanceClass=/Game/Core/BP_GameInstance.BP_GameInstance_C
[/Script/Engine.RendererSettings]
r.AllowStaticLighting=False
@@ -120,7 +120,70 @@ ManualIPAddress=
+CVarsArray=(Type=CVarInt,Name="DDCvar.AnalogInputStyle",ToolTip="",DefaultValueFloat=0.000000,DefaultValueInt=0,DefaultValueBool=False)
[/Script/Engine.CollisionProfile]
+Profiles=(Name="WaterBodyCollision",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="Default Water Collision Profile (Created by Water Plugin)")
-Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision",bCanModify=False)
-Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ",bCanModify=False)
-Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ",bCanModify=False)
-Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic",Response=ECR_Block),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.",bCanModify=False)
-Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors",bCanModify=False)
-Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors",bCanModify=False)
-Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.",bCanModify=False)
-Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.",bCanModify=False)
-Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="UI",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Block),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="WaterBodyCollision",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="",CustomResponses=((Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="Default Water Collision Profile (Created by Water Plugin)")
+Profiles=(Name="WaterBodyCollision",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="",CustomResponses=((Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="Default Water Collision Profile (Created by Water Plugin)")
+Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision")
+Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic"),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors")
+Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors")
+Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.")
+Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.")
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="ObstaclePreset",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="Obstacle",CustomResponses=((Channel="WorldStatic",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Moving Obstacles for Physics Obstacle Course")
+Profiles=(Name="TraversalObjectPreset",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Traversable")),HelpMessage="Traversable Level Blocks")
+Profiles=(Name="CharacterCapsule",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="Needs description")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Traversable")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Mouse")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel3,DefaultResponse=ECR_Ignore,bTraceType=False,bStaticObject=False,Name="Obstacle")
+EditProfiles=(Name="Ragdoll",CustomResponses=((Channel="Camera",Response=ECR_Ignore),(Channel="Obstacle")))
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
-ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
-ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
+ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
+ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
+ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
+ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
+ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
+ProfileRedirects=(OldName="Obstacle",NewName="ObstaclePreset")
-CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
-CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
-CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
-CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
+CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
+CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
[/Script/UnrealEd.CookerSettings]
bCookOnTheFlyForLaunchOn=True
+19 -1
View File
@@ -8,11 +8,29 @@ AllowGameTagUnloading=False
FastReplication=False
bDynamicReplication=False
InvalidTagCharacters="\"\',"
+GameplayTagTableList=/Game/DT_DemoTags.DT_DemoTags
+GameplayTagTableList=/Game/Data/DT_DemoTags.DT_DemoTags
NumBitsForContainerSize=6
NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="Foley.Event.Handplant",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Jump",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Kick",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Land",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Punch",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Ragdoll",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Run",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.RunBackwds",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.RunStrafe",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Scuff",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.ScuffPivot",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.ScuffWall",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Slide.Loop",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Tumble",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.Walk",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Foley.Event.WalkBackwds",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="Human.Face",DevComment="")
+GameplayTagList=(Tag="Human.Pant",DevComment="")
+GameplayTagList=(Tag="Human.Shoes",DevComment="")
+GameplayTagList=(Tag="Human.Speed",DevComment="")
+GameplayTagList=(Tag="SmartObject.ObjectType.Bench",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
+GameplayTagList=(Tag="SmartObject.ObjectType.Player",DevComment="Game Animation Sample tags (Foley / SmartObjects)")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 2474 files, more files were not shown because too many files have changed in this diff. Show more