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>
12 KiB
S2-IMPL-H — Extraction du module LPAnimMeasure
- Date : 2026-10-06
- Fiche : S2-T2 | Agent : A-IMPL-H | Rôle : Implémentation
- Modèle prévu :
claude-opus-5-thinking-high(M3) - Référence suivie :
S2/S2-CART.md(décision §1 (b), listes §2 à §5, ordre §8) - Statut : compilé (
LifePlayEditoretLifePlay, Win64 Development), non committé - Hors périmètre respecté : aucune UI Slate de la sandbox touchée,
LPSandboxConfig.*etLPPairSandbox.*restent dansLifePlay.
1. Fichiers créés
| Fichier | Contenu |
|---|---|
Source/LPAnimMeasure/LPAnimMeasure.Build.cs |
PublicIncludePaths.Add(ModuleDirectory) (structure plate) ; PublicDependencyModuleNames = Core, CoreUObject, Engine ; PrivateDependencyModuleNames = Json ; aucune dépendance vers LifePlay / LifePlayEditorTools |
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) |
Docs/Migration/etat/sandbox/S2/S2-IMPL-H.md |
cette fiche |
2. Fichiers déplacés (Source/LifePlay/ → Source/LPAnimMeasure/)
Les 8 fichiers de S2-CART.md §2, déplacés tels quels (pas de Public//Private/) :
LPPoseMeasure.h/.cpp, LPSkeletonProfile.h/.cpp, LPPoseOrchestrator.h/.cpp, LPAnimRedirect.h/.cpp.
git mv non utilisable : les 8 fichiers n'étaient pas encore suivis par git (fatal: not under version control) — ils apparaissent en ?? dans le statut, comme la plupart des fichiers de la sandbox. Le déplacement est un Move-Item ; il n'y a aucun historique git à préserver pour ces fichiers. Les anciens chemins n'existent plus sous Source/LifePlay/.
Modifications appliquées aux fichiers déplacés
| Fichier | Modification |
|---|---|
LPPoseMeasure.h |
6 LIFEPLAY_API → LPANIMMEASURE_API ; 3 exports ajoutés (TFitReport, LogReport, KeyBones) ; commentaire d'en-tête du namespace actualisé (LPANIMMEASURE_API, mention de la sandbox) |
LPPoseMeasure.cpp |
#include "LifePlay.h" → #include "LPAnimMeasure.h" ; 12 UE_LOG(LogLifePlay…) → LogLPAnimMeasure |
LPSkeletonProfile.h |
3 LIFEPLAY_API → LPANIMMEASURE_API (struct FLPSkeletonProfile, Find, Identify) |
LPSkeletonProfile.cpp |
#include "LifePlay.h" → #include "LPAnimMeasure.h" ; 4 LogLifePlay → LogLPAnimMeasure |
LPPoseOrchestrator.h |
3 exports ajoutés (Run, Restore, SampleAt) |
LPPoseOrchestrator.cpp |
#include "LifePlay.h" → #include "LPAnimMeasure.h" ; 4 LogLifePlay → LogLPAnimMeasure |
LPAnimRedirect.h |
LPANIMMEASURE_API sur IsGameTarget/ClipPath ; 2 fonctions ajoutées : SetUALRoot, GetUALRoot |
LPAnimRedirect.cpp |
#include "LPSandboxConfig.h" retiré ; racine interne static FString UALRoot() initialisée à TEXT("/Game/Quaternius/UAL") ; ClipPath utilise GetUALRoot() |
Vérification : plus aucune occurrence de LIFEPLAY_API, LogLifePlay, #include "LifePlay.h" ni #include "LPSandboxConfig.h" dans Source/LPAnimMeasure/ (seules subsistent 3 mentions en commentaire, qui documentent la rupture de couplage).
3. Fichiers modifiés hors module
| Fichier | Modification |
|---|---|
LifePlay.uproject |
entrée { "Name": "LPAnimMeasure", "Type": "Runtime", "LoadingPhase": "Default" } insérée avant LifePlay |
Source/LifePlay.Target.cs |
ExtraModuleNames → { "LifePlay", "LPAnimMeasure" } |
Source/LifePlayEditor.Target.cs |
ExtraModuleNames → { "LifePlay", "LPAnimMeasure", "LifePlayEditorTools" } |
Source/LifePlay/LifePlay.Build.cs |
PublicDependencyModuleNames.Add("LPAnimMeasure") |
Source/LifePlayEditorTools/LifePlayEditorTools.Build.cs |
"LPAnimMeasure" ajouté à PublicDependencyModuleNames, à côté de "LifePlay" |
Source/LifePlay/LifePlay.cpp |
FDefaultGameModuleImpl → FLifePlayModule (§4) |
Source/LifePlay/LPInteractionSandbox.cpp |
#include "Engine/TextureCube.h" ajouté — effet de bord de la recomposition des blobs unity (§7) |
Tools/LogStats.ps1 |
compteur LogLPAnimMeasure ajouté à côté de LogLifePlay (mitigation R1 de S2-CART.md §7) |
Non touchés : LPPairSandbox.h/.cpp, LPDirectControlSubsystem.h/.cpp, LPSandboxConfig.h/.cpp, les 4 fichiers de LifePlayEditorTools consommateurs. Leurs #include "LPPoseMeasure.h" etc. restent valides grâce à PublicIncludePaths.Add(ModuleDirectory) du nouveau module. Json reste déclaré dans LifePlay.Build.cs (retrait non traité, sans risque — cf. S2-CART.md §5.1).
4. Câblage de la racine UAL (LifePlay.cpp existe)
Source/LifePlay/LifePlay.cpp existait bien (IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, LifePlay, "LifePlay")). La solution préférée de S2-CART.md §1 a donc été appliquée, sans recourir à l'alternative BeginPlay :
class FLifePlayModule : public FDefaultGameModuleImpl
{
public:
virtual void StartupModule() override
{
FDefaultGameModuleImpl::StartupModule();
LPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot);
}
};
IMPLEMENT_PRIMARY_GAME_MODULE( FLifePlayModule, LifePlay, "LifePlay" );
Conséquences :
- Le flux de configuration va dans le sens
LifePlay(propriétaire deLPSandboxConfig) →LPAnimMeasure(setter). Aucun cycle de modules. Config/LPSandbox.ini(cléSandbox.Roots/QuaterniusUALRoot, contratS1-SPEC.md) est pris en compte pour tous les consommateurs — sandbox,ULPDirectControlSubsystem, commandlets — sans exiger que la sandbox soit lancée d'abord.SetUALRootignore une chaîne vide : un ini incomplet ne peut pas effacer la racine.- Défaut interne de
LPAnimRedirectidentique au défaut deFLPSandboxConfig::QuaterniusUALRoot(/Game/Quaternius/UAL) : siSetUALRootn'est jamais appelé (test unitaire, outil chargeantLPAnimMeasureseul), le comportement reste celui d'avant l'extraction. S1-CART.mddoit être mis à jour :LPAnimRedirect.cppn'est plus un consommateur direct de la clé ;LifePlay.cpple devient.
5. API publique du module LPAnimMeasure
Les structures de données sont des struct C++ simples (aucune UCLASS/USTRUCT, aucune UFUNCTION) : header-only, elles ne nécessitent pas d'export, sauf FLPSkeletonProfile qui a des méthodes définies en .cpp.
5.1. LPAnimMeasure.h
| Symbole | Export |
|---|---|
LogLPAnimMeasure (catégorie de log) |
LPANIMMEASURE_API |
5.2. LPAnimRedirect.h
| Symbole | Export | Statut |
|---|---|---|
bool LPAnimRedirect::IsGameTarget() |
LPANIMMEASURE_API |
export ajouté |
FString LPAnimRedirect::ClipPath(const FString& AssetName) |
LPANIMMEASURE_API |
export ajouté |
void LPAnimRedirect::SetUALRoot(const FString& Root) |
LPANIMMEASURE_API |
nouveau |
const FString& LPAnimRedirect::GetUALRoot() |
LPANIMMEASURE_API |
nouveau |
5.3. LPPoseMeasure.h
Types publics non exportés (header-only) : FLPPose, FLPPoseMeasureReport, FLPJointScore, FLPPoseScore, FLPTFitSegment, FLPTFitAdjust, FLPTFitResult.
| Symbole | Export | Statut |
|---|---|---|
bool Sample(const FString& AnimPath, float Time, FLPPose& Out) |
LPANIMMEASURE_API |
existant |
bool TPoses(const FLPPose& Reference, const FLPPose& Target, FLPPose& OutRefT, FLPPose& OutBodyT) |
LPANIMMEASURE_API |
existant |
const TArray<FString>& TFitReport() |
LPANIMMEASURE_API |
export ajouté (LPPairSandbox.cpp) |
bool TFitResult(const FLPPose& Reference, const FLPPose& Target, FLPTFitResult& Out) |
LPANIMMEASURE_API |
existant |
bool TransferPose(const FLPPose& Reference, const FLPPose& Template, FLPPose& Out) |
LPANIMMEASURE_API |
existant |
bool WriteRetargetPose(const FLPPose& Reference, const FLPPose& Template, const FString& Path) |
LPANIMMEASURE_API |
existant |
FLPPoseMeasureReport Compare(const TCHAR* Body, const TCHAR* Clip, const FLPPose& Reference, const FLPPose& Target) |
LPANIMMEASURE_API |
existant |
void LogReport(const FLPPoseMeasureReport& Report) |
LPANIMMEASURE_API |
export ajouté (LPPairSandbox.cpp) |
FName RoleBone(const FLPPose& Pose, const TCHAR* Role, int32 Index = 0) |
LPANIMMEASURE_API |
existant |
TArray<FName> KeyBones(const FLPPose& Pose) |
LPANIMMEASURE_API |
export ajouté (LPPairSandbox.cpp) |
Restent internes au module (non exportés) : AlignToReference, ScorePose, SyncSample, FormatPassage, FormatKept, FormatSnapshot.
5.4. LPSkeletonProfile.h
| Symbole | Export | Statut |
|---|---|---|
struct FLPTPoseAdjust |
— (header-only) | existant |
struct FLPSkeletonProfile (+ Bone, Chain, Has) |
LPANIMMEASURE_API |
existant |
const FLPSkeletonProfile* Find(const FString& Id) |
LPANIMMEASURE_API |
existant |
const FLPSkeletonProfile* Identify(const TArray<FName>& BoneNames, float* OutScore = nullptr) |
LPANIMMEASURE_API |
existant |
Reste interne : LPSkeletonProfile::All().
5.5. LPPoseOrchestrator.h
Type public non exporté (header-only) : FLPOrchestratorRound.
| Symbole | Export | Statut |
|---|---|---|
FLPOrchestratorRound Run(const TCHAR* Clip, bool bOneSubject = false) |
LPANIMMEASURE_API |
export ajouté (LPPairSandbox.cpp) |
FLPOrchestratorRound Restore(const TCHAR* Clip) |
LPANIMMEASURE_API |
export ajouté (LPPairSandbox.cpp) |
FLPOrchestratorRound SampleAt(const TCHAR* Clip, float Fraction) |
LPANIMMEASURE_API |
export ajouté (LPPairSandbox.cpp) |
5.6. Contrôle de couverture
Tous les symboles LPPoseMeasure::, LPSkeletonProfile::, LPPoseOrchestrator::, LPAnimRedirect:: référencés depuis Source/LifePlay/ et Source/LifePlayEditorTools/ sont exportés (relevé exhaustif : ClipPath, Compare, Find, IsGameTarget, KeyBones, LogReport, Restore, RoleBone, Run, Sample, SampleAt, SetUALRoot, TFitReport, TFitResult, TPoses, TransferPose, WriteRetargetPose). Mitigation R3 de S2-CART.md §7 couverte.
6. Graphe de dépendances obtenu
LifePlayEditorTools ──► LifePlay ──► LPAnimMeasure
└──────────────────────────────┘ (public, pour FLPPose dans LPAnimChecks.h)
LPAnimMeasure ──► Core, CoreUObject, Engine (public), Json (privé)
LPAnimMeasure ──► LifePlay : AUCUNE (acyclique)
Ordre de chargement LPAnimMeasure avant LifePlay garanti deux fois : dépendance Build.cs et position dans LifePlay.uproject.
7. Validation
| Target | Résultat | Journal |
|---|---|---|
LifePlayEditor Win64 Development |
succès — UnrealEditor-LPAnimMeasure.lib/.dll produits, LifePlay et LifePlayEditorTools relinkés sans LNK2019 |
Saved/Logs/portage/S2-T2-build.log |
LifePlay Win64 Development (Game) |
succès après le correctif ci-dessous | Saved/Logs/portage/S2-T2-build-game.log |
Effet de bord rencontré (famille du risque R5)
Première passe du target Game : error C2027: utilisation du type non défini 'UTextureCube' dans LPInteractionSandbox.cpp:123 (LoadObject<UTextureCube>). Ce fichier n'a jamais inclus Engine/TextureCube.h ; il dépendait de l'include transitif apporté par un voisin du même blob unity de LifePlay — très probablement LPPairSandbox.cpp, qui inclut Engine/TextureCube.h explicitement. La sortie des 8 fichiers du module a changé la composition des blobs et découvert ce défaut IWYU préexistant (le target Editor, dont le découpage unity diffère, ne le voyait pas).
Correctif : ajout de #include "Engine/TextureCube.h" dans LPInteractionSandbox.cpp. Aucune collision de namespace anonyme n'est survenue dans LPAnimMeasure ; bUseUnity = false n'a pas été nécessaire.
8. Reste à faire
- Validation fonctionnelle (commandlets
LPAnimEval,LPAnimCatalog,LPAnimTwist, sandbox) : fiche S2-T3 /S2-VAL.md. - Mise à jour de
S1-CART.md(ligneLPAnimRedirect.cpp:23→ consommation viaLifePlay.cpp/SetUALRoot). - Aucun commit effectué (consigne de la fiche).