Charge le plugin via AdditionalPluginDirectories, conserve ShowCouple et les commandlets anim côté jeu, et documente les lots S0–S8 (CHG-212 à CHG-220). Co-authored-by: Cursor <cursoragent@cursor.com>
19 KiB
S2-CART — Cartographie d'extraction du module LPAnimMeasure
- Date : 2026-10-06
- Fiche : S2-T1 | Agent : A-CART | Rôle : Cartographie (lecture seule, aucun code modifié)
- Modèle prévu :
claude-sonnet-5-5-high(M2) - Références :
S1/S1-SPEC.md,S1/S1-CART.md
1. Décision principale : LPAnimRedirect
LPAnimRedirect.cpp appelle FLPSandboxConfig::Get().QuaterniusUALRoot (seule dépendance, ligne 23 de ClipPath). LPPoseOrchestrator.cpp appelle LPAnimRedirect::ClipPath 8 fois (l. 223, 233, 237, 255, 262, 303, 345, 404). LPDirectControlSubsystem.cpp (runtime jeu, module LifePlay) appelle IsGameTarget() (l. 880) et ClipPath() (l. 960).
Garder Redirect dans LifePlay n'est pas possible : LPPoseOrchestrator va dans LPAnimMeasure, qui ne peut pas dépendre de LifePlay (cycle LifePlay → LPAnimMeasure → LifePlay).
Choix retenu : (b) Redirect déménage dans LPAnimMeasure, racine UAL injectée
LPAnimRedirectne dépend plus deLPSandboxConfig(le#include "LPSandboxConfig.h"disparaît du.cpp).- Ajout d'un point d'injection dans
LPAnimRedirect.h:LPANIMMEASURE_API void SetUALRoot(const FString& Root);LPANIMMEASURE_API const FString& GetUALRoot();- Valeur par défaut interne :
TEXT("/Game/Quaternius/UAL")(identique au défaut deFLPSandboxConfig::QuaterniusUALRoot, donc comportement inchangé sans ini).
LPANIMMEASURE_APIajouté àIsGameTarget()etClipPath().- Câblage côté
LifePlay(propriétaire deLPSandboxConfig, qui reste dansLifePlaypour S3) :LifePlay.cpppasse deFDefaultGameModuleImplà une classeFLifePlayModule : FDefaultGameModuleImpldontStartupModule()appelleLPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot). Le singleton litConfig/LPSandbox.ini; l'ini est donc pris en compte pour tous les consommateurs (sandbox,LPDirectControlSubsystem, commandlets), sans exiger que la sandbox soit lancée d'abord. Alternative plus légère, moins sûre : appelerSetUALRootau début deALPPairSandboxCharacter::BeginPlay. À éviter :LPDirectControlSubsystemet les commandlets s'exécuteraient avec la valeur par défaut seulement. - Couplage à documenter : le contrat
S1-SPEC.md(cléSandbox.Roots/QuaterniusUALRoot) reste valide, mais sa consommation passe parSetUALRootau lieu d'un appel direct.S1-CART.mddoit mettre à jour la ligneLPAnimRedirect.cpp:23(consommateur indirect). - Pourquoi (b) plutôt que laisser Redirect hors module :
LPPoseOrchestrator(dansLPAnimMeasure) en dépend directement, donc l'un des deux doit bouger ou être injecté. Déplacer Redirect + une seule fonction d'injection est le plus petit changement (2 fichiers, 1 setter). - Alternative écartée (c) : injecter un resolver
TFunction<FString(const FString&)>dans l'Orchestrator. Plus invasif (signaturesRun/Restore/SampleAt), etIsGameTarget()devrait rester séparé.
2. Liste exhaustive des fichiers à déplacer
Source : Source/LifePlay/ → destination : Source/LPAnimMeasure/ (structure plate comme LifePlay, pas de Public//Private/).
| # | Fichier | Destination |
|---|---|---|
| 1 | LPPoseMeasure.h |
Source/LPAnimMeasure/LPPoseMeasure.h |
| 2 | LPPoseMeasure.cpp |
Source/LPAnimMeasure/LPPoseMeasure.cpp |
| 3 | LPSkeletonProfile.h |
Source/LPAnimMeasure/LPSkeletonProfile.h |
| 4 | LPSkeletonProfile.cpp |
Source/LPAnimMeasure/LPSkeletonProfile.cpp |
| 5 | LPPoseOrchestrator.h |
Source/LPAnimMeasure/LPPoseOrchestrator.h |
| 6 | LPPoseOrchestrator.cpp |
Source/LPAnimMeasure/LPPoseOrchestrator.cpp |
| 7 | LPAnimRedirect.h |
Source/LPAnimMeasure/LPAnimRedirect.h |
| 8 | LPAnimRedirect.cpp |
Source/LPAnimMeasure/LPAnimRedirect.cpp |
Nouveaux fichiers du module :
| Fichier | Contenu |
|---|---|
Source/LPAnimMeasure/LPAnimMeasure.Build.cs |
règles du module (section 5) |
Source/LPAnimMeasure/LPAnimMeasure.h |
LPANIMMEASURE_API DECLARE_LOG_CATEGORY_EXTERN(LogLPAnimMeasure, Log, All); |
Source/LPAnimMeasure/LPAnimMeasure.cpp |
IMPLEMENT_MODULE(FDefaultModuleImpl, LPAnimMeasure) + DEFINE_LOG_CATEGORY(LogLPAnimMeasure) |
Ne bougent PAS : LPSandboxConfig.h/.cpp (reste dans LifePlay, S3), LPPairSandbox.*, LPDirectControlSubsystem.*, LifePlay.h/.cpp.
3. Dépendances sortantes de chaque fichier déplacé
| Fichier | #include projet (hors Engine) |
Autres dépendances à traiter |
|---|---|---|
LPPoseMeasure.h |
CoreMinimal.h |
6 symboles LIFEPLAY_API → LPANIMMEASURE_API ; commentaire l.~74 (« LifePlayEditorTools ») |
LPPoseMeasure.cpp |
LPPoseMeasure.h, LPSkeletonProfile.h, LifePlay.h (l. 6) |
12 UE_LOG(LogLifePlay…) (l. 298, 862, 878…) ; Engine : Animation/AnimSequence.h, Animation/Skeleton.h, Misc/FileHelper.h |
LPSkeletonProfile.h |
CoreMinimal.h |
FLPSkeletonProfile et 2 fonctions LIFEPLAY_API → LPANIMMEASURE_API |
LPSkeletonProfile.cpp |
LPSkeletonProfile.h, LifePlay.h (l. 5) |
4 UE_LOG(LogLifePlay…) ; Engine : Dom/JsonObject.h, Serialization/Json*, HAL/FileManager.h, Misc/Paths.h ; lit Tools/anim/profiles/*.json via FPaths::ProjectDir() (aucun changement) |
LPPoseOrchestrator.h |
LPPoseMeasure.h |
aucune API exportée aujourd'hui (voir §4) |
LPPoseOrchestrator.cpp |
LPPoseOrchestrator.h, LPAnimRedirect.h, LifePlay.h (l. 5) |
4 UE_LOG(LogLifePlay…) ; Engine : Animation/AnimSequence.h, HAL/FileManager.h, Misc/FileHelper.h, Misc/Paths.h |
LPAnimRedirect.h |
CoreMinimal.h |
ajouter LPANIMMEASURE_API + SetUALRoot/GetUALRoot |
LPAnimRedirect.cpp |
LPAnimRedirect.h, LPSandboxConfig.h (l. 2, à supprimer) |
GConfig (Misc/ConfigCacheIni.h), FPaths |
Couplages à casser (sinon cycle de modules)
LifePlay.h/LogLifePlay: 3.cpp(20 appelsUE_LOGau total : Measure 12, Orchestrator 4, SkeletonProfile 4) incluentLifePlay.h.LPAnimMeasurene peut pas dépendre deLifePlay. Solution : catégorie propreLogLPAnimMeasure(LPAnimMeasure.h/.cpp), remplacement mécaniqueLogLifePlay→LogLPAnimMeasureet#include "LifePlay.h"→#include "LPAnimMeasure.h".- Effet de bord :
Tools/LogStats.ps1ligne 51 compte les lignesLogLifePlay(statistique de session). Les lignesPOSET/PROFILmigrent versLogLPAnimMeasure; ajouter une entréeLogLPAnimMeasuredans ce script (ou accepter la baisse du compteur). Aucune occurrence deLogLifePlaydansSource/LifePlayEditorTools.
- Effet de bord :
LPSandboxConfig.hdansLPAnimRedirect.cpp: voir §1.- Aucune autre référence à des types
ALP*/ULP*/FLPSandbox*/FLPPair*/GEngine/UWorlddansLPPoseMeasure.cpp,LPSkeletonProfile.cpp,LPPoseOrchestrator.cpp(vérifié par grep, 0 occurrence) : l'extraction est propre hors les deux points ci-dessus.
4. Consommateurs : #include et usages (hors fichiers déplacés)
4.1. Source/LifePlay
| Consommateur | #include |
Symboles utilisés | Action |
|---|---|---|---|
LPPairSandbox.cpp l. 5-7 |
LPAnimRedirect.h, LPPoseMeasure.h, LPPoseOrchestrator.h |
LPAnimRedirect::ClipPath (l. 1923, 1929, 2011, 3089, 3111) ; LPPoseMeasure::Sample/Compare/KeyBones/LogReport/TFitReport/TransferPose/WriteRetargetPose/TPoses/TFitResult (l. 1419-1520, 1923-1932) ; LPPoseOrchestrator::Run/Restore/SampleAt (l. 1450-1451) |
includes inchangés (include path public du module), mais exports à ajouter (§4.3) |
LPPairSandbox.cpp l. 8 |
LPSandboxConfig.h |
— | inchangé (reste dans LifePlay) |
LPDirectControlSubsystem.cpp l. 10 |
LPAnimRedirect.h |
IsGameTarget() l. 880, ClipPath() l. 960 |
include inchangé ; dépendance LifePlay → LPAnimMeasure en Build.cs |
LifePlay.cpp |
(nouveau) LPAnimRedirect.h, LPSandboxConfig.h |
SetUALRoot dans StartupModule |
à créer |
4.2. Source/LifePlayEditorTools
| Consommateur | #include |
Symboles utilisés (tous déjà exportés) |
|---|---|---|
LPAnimTwistCommandlet.cpp l. 10-11 |
LPPoseMeasure.h, LPSkeletonProfile.h |
LPSkeletonProfile::Find (l. 59), LPPoseMeasure::Sample, TPoses (l. 265-295) |
LPAnimEvalCommandlet.cpp l. 9-10 |
LPPoseMeasure.h, LPSkeletonProfile.h |
LPSkeletonProfile::Find (l. 86, 171), Sample, TransferPose, Compare, TPoses, WriteRetargetPose, TFitResult |
LPAnimCatalogCommandlet.cpp l. 8 |
LPPoseMeasure.h |
RoleBone (l. 31), Sample (l. 144) |
LPAnimChecks.h l. 15 |
LPPoseMeasure.h |
FLPPose (type en signature publique) ; LPAnimChecks.cpp : RoleBone (l. 26), Sample (l. 270) |
LPAnimTwistCommandlet.h l. 7 |
— (commentaire) | mention LPPoseMeasure::TransferPose |
LifePlayEditorTools n'inclut ni LPPoseOrchestrator.h, ni LPAnimRedirect.h, ni LPSandboxConfig.h.
LPAnimEvalCommandlet a son propre ClipPath(ClipDir, ...) (fonction locale) et n'utilise pas LPAnimRedirect.
4.3. Exports requis (la frontière de module les rend obligatoires)
Aujourd'hui exportés par LIFEPLAY_API (→ LPANIMMEASURE_API) : LPPoseMeasure::{Sample, TPoses, TFitResult, TransferPose, WriteRetargetPose, Compare, RoleBone}, FLPSkeletonProfile (struct), LPSkeletonProfile::{Find, Identify}.
À ajouter (utilisés aujourd'hui par LPPairSandbox.cpp qui reste dans LifePlay, donc cross-module après extraction) :
| Symbole | Utilisé par |
|---|---|
LPPoseMeasure::KeyBones |
LPPairSandbox.cpp l. 1419 |
LPPoseMeasure::LogReport |
LPPairSandbox.cpp l. 1477, 1483, 1493 |
LPPoseMeasure::TFitReport |
LPPairSandbox.cpp l. 1520 |
LPPoseOrchestrator::Run |
LPPairSandbox.cpp l. 1451 |
LPPoseOrchestrator::Restore |
LPPairSandbox.cpp l. 1451 |
LPPoseOrchestrator::SampleAt |
LPPairSandbox.cpp l. 1450 |
LPAnimRedirect::IsGameTarget, ClipPath, SetUALRoot, GetUALRoot |
LPPairSandbox.cpp, LPDirectControlSubsystem.cpp, LifePlay.cpp |
Restent internes (non exportés, usage intra-module uniquement) : LPPoseMeasure::{AlignToReference, ScorePose, SyncSample, FormatPassage, FormatKept, FormatSnapshot} et LPSkeletonProfile::All.
Les structs de données (FLPPose, FLPPoseMeasureReport, FLPPoseScore, FLPJointScore, FLPTFitSegment, FLPTFitAdjust, FLPTFitResult, FLPOrchestratorRound, FLPTPoseAdjust) sont des structs sans UCLASS/USTRUCT ; elles n'ont besoin d'aucun export (types header-only, membres TArray/FString inline). FLPSkeletonProfile conserve son API car elle a des méthodes .cpp (Bone, Chain).
5. Frontière de module proposée
5.1. Source/LPAnimMeasure/LPAnimMeasure.Build.cs
using UnrealBuildTool;
public class LPAnimMeasure : ModuleRules
{
public LPAnimMeasure(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
// Structure plate (comme LifePlay) : exposer le dossier du module aux dependants.
PublicIncludePaths.Add(ModuleDirectory);
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });
// LPSkeletonProfile : lecture des profils Tools/anim/profiles/*.json
PrivateDependencyModuleNames.Add("Json");
}
}
Justification des dépendances (vérifiées par les #include Engine des 8 fichiers) :
Core,CoreUObject,Engine:UAnimSequence,USkeleton,FTransform,GConfig,FPaths,IFileManager,FFileHelper.Enginepublic carFLPPosen'expose que des types Core (FName,FTransform,FQuat,FString), mais les en-têtes sont consommés par des modules qui ont déjàEngine; le garder public est inoffensif.Json(+JsonUtilitiesnon requis) :Dom/JsonObject.h,Serialization/JsonReader.h,JsonSerializer.hdansLPSkeletonProfile.cpp.- Aucune dépendance vers
LifePlayniLifePlayEditorTools. Jsonreste aussi dansLifePlay.Build.cs: il est ajouté en AP1 pourLPSkeletonProfile; une fois le fichier déplacé, vérifier qu'aucun autre fichier deLifePlayn'utiliseJsonavant de le retirer (non traité ici, laisser en l'état est sans risque).
5.2. Export API
LPANIMMEASURE_API (généré par UBT pour le module LPAnimMeasure) remplace LIFEPLAY_API dans les 4 headers déplacés (pas de LIFEPLAY_API résiduel dans LPPoseMeasure.h, LPSkeletonProfile.h, LPAnimRedirect.h, LPPoseOrchestrator.h).
5.3. Source/LPAnimMeasure/LPAnimMeasure.cpp
#include "LPAnimMeasure.h"
#include "Modules/ModuleManager.h"
IMPLEMENT_MODULE(FDefaultModuleImpl, LPAnimMeasure);
DEFINE_LOG_CATEGORY(LogLPAnimMeasure);
(IMPLEMENT_PRIMARY_GAME_MODULE reste uniquement dans LifePlay.cpp.)
5.4. LifePlay.Build.cs
Ajouter :
PublicDependencyModuleNames.Add("LPAnimMeasure");
Public (et non Private) car LifePlayEditorTools dépend de LifePlay publiquement et les headers LPPoseMeasure.h etc. sont inclus par ses commandlets ; une dépendance explicite dans LifePlayEditorTools.Build.cs est quand même ajoutée (5.5) pour ne pas dépendre de la transitivité. PublicIncludePaths.Add(ModuleDirectory) de LifePlay n'est plus nécessaire pour ces 4 headers mais reste requis pour LPAssetRegistryHelpers.h et autres.
5.5. LifePlayEditorTools.Build.cs
Ajouter dans PublicDependencyModuleNames (à côté de "LifePlay") : "LPAnimMeasure" — public car LPAnimChecks.h expose FLPPose dans sa signature.
5.6. LifePlay.uproject — entrée Modules
Insérer avant LifePlay (même phase de chargement Default, ordre explicite) :
{
"Name": "LPAnimMeasure",
"Type": "Runtime",
"LoadingPhase": "Default"
}
Type: Runtime car LifePlay (module runtime du jeu packagé) en dépend (LPDirectControlSubsystem utilise LPAnimRedirect). Les dépendances ne sont pas déclarées dans le .uproject (c'est Build.cs qui gère ; AdditionalDependencies n'est pas requis).
5.7. Targets
Source/LifePlay.Target.cs:ExtraModuleNames→{ "LifePlay", "LPAnimMeasure" }.Source/LifePlayEditor.Target.cs:ExtraModuleNames→{ "LifePlay", "LPAnimMeasure", "LifePlayEditorTools" }.
6. Graphe de dépendances
Avant
LifePlayEditorTools ──► LifePlay
├─ LPPoseMeasure ──► LPSkeletonProfile
├─ LPPoseOrchestrator ──► LPPoseMeasure, LPAnimRedirect
├─ LPAnimRedirect ──► LPSandboxConfig
├─ LPPairSandbox ──► Redirect, Measure, Orchestrator, SandboxConfig
└─ LPDirectControlSubsystem ──► LPAnimRedirect
Après
┌────────────────────────────────────────────┐
LifePlayEditorTools ──┤ ▼
│ │ LPAnimMeasure (Runtime, nouveau)
▼ │ ├─ LPPoseMeasure ──► LPSkeletonProfile
LifePlay ────────┘ ├─ LPPoseOrchestrator ──► LPPoseMeasure
│ │ └─► LPAnimRedirect
├─ LPSandboxConfig (reste, S3) ├─ LPAnimRedirect (UALRoot injectee)
├─ LPPairSandbox ───► LPAnimMeasure (Redirect, Measure, Orchestrator) + LPSandboxConfig
├─ LPDirectControlSubsystem ───► LPAnimMeasure (Redirect)
└─ LifePlay.cpp StartupModule ─► LPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot)
Sens des flèches module :
| De | Vers | Type |
|---|---|---|
LifePlay |
LPAnimMeasure |
Public |
LifePlayEditorTools |
LifePlay |
Public (existant) |
LifePlayEditorTools |
LPAnimMeasure |
Public (nouveau) |
LPAnimMeasure |
LifePlay |
aucune (acyclique) |
LPAnimMeasure |
LifePlayEditorTools |
aucune |
Couplage résiduel documenté : LPAnimRedirect ne lit plus LPSandboxConfig ; le flux va dans le sens LifePlay (config) → LPAnimMeasure (setter). Ordre de chargement : LPAnimMeasure avant LifePlay (garanti par la dépendance Build.cs et par l'ordre dans .uproject).
7. Risques et points de vigilance
| # | Risque | Mitigation |
|---|---|---|
| R1 | LogLifePlay → LogLPAnimMeasure : la catégorie change dans les logs POSET/PROFIL et le compteur Tools/LogStats.ps1:51 |
ajouter LogLPAnimMeasure au script |
| R2 | SetUALRoot non appelé avant premier ClipPath (commandlet sans module LifePlay initialisé) |
LifePlay est toujours chargé (module primaire) avant les commandlets de LifePlayEditorTools ; défaut interne identique au défaut de la config |
| R3 | Symbole non exporté oublié → erreur de lien LNK2019 dans LPPairSandbox.cpp |
liste §4.3 (8 symboles existants à exporter + 2 nouveaux) |
| R4 | LifePlayEditorTools en bUseUnity = false : aucune modification |
— |
| R5 | LPAnimMeasure en compilation unity : aucun namespace anonyme avec noms identiques entre les 3 .cpp ne doit entrer en collision (ces fichiers étaient déjà dans l'unity de LifePlay) |
si collision, ajouter bUseUnity = false au Build.cs |
| R6 | Les .uasset ne référencent pas ces classes C++ (aucune UCLASS/USTRUCT dans les 8 fichiers) : pas de redirecteur de classe CoreRedirects à écrire |
— |
| R7 | Tools/RetargetQuaternius.py cite LPPoseMeasure::WriteRetargetPose/LPSkeletonProfile::Identify uniquement en commentaires |
aucune action |
8. Ordre d'exécution suggéré (pour S2-T2)
- Créer
Source/LPAnimMeasure/+LPAnimMeasure.Build.cs,LPAnimMeasure.h/.cpp. git mvdes 8 fichiers (conserve l'historique).- Remplacer
LIFEPLAY_API→LPANIMMEASURE_API,LifePlay.h→LPAnimMeasure.h,LogLifePlay→LogLPAnimMeasuredans les fichiers déplacés ; ajouter les exports manquants (<28>4.3) ; retirer l'include deLPSandboxConfig.hdansLPAnimRedirect.cppet ajouterSetUALRoot/GetUALRoot. LifePlay.cpp:FLifePlayModule::StartupModule→SetUALRoot(...).- Mettre à jour
LifePlay.Build.cs,LifePlayEditorTools.Build.cs,LifePlay.uproject, les deux*.Target.cs. - Regénérer le projet (
GenerateProjectFiles) et compiler Editor + Game ; lancer la validation (commandletsLPAnimEval,LPAnimCatalog,LPAnimTwist) pour contrôler l'absence de régression.