LifePlay-Revival/Docs/Migration/etat/sandbox/S2/S2-IMPL-H.md
edujiro5972 04b053554f Sandbox addon : brancher le jeu sur LifePlay-Sandbox (plugin LPSandbox).
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>
2026-10-06 21:10:53 +02:00

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é (LifePlayEditor et LifePlay, Win64 Development), non committé
  • Hors périmètre respecté : aucune UI Slate de la sandbox touchée, LPSandboxConfig.* et LPPairSandbox.* restent dans LifePlay.

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 de LPSandboxConfig) → LPAnimMeasure (setter). Aucun cycle de modules.
  • Config/LPSandbox.ini (clé Sandbox.Roots/QuaterniusUALRoot, contrat S1-SPEC.md) est pris en compte pour tous les consommateurs — sandbox, ULPDirectControlSubsystem, commandlets — sans exiger que la sandbox soit lancée d'abord.
  • SetUALRoot ignore une chaîne vide : un ini incomplet ne peut pas effacer la racine.
  • Défaut interne de LPAnimRedirect identique au défaut de FLPSandboxConfig::QuaterniusUALRoot (/Game/Quaternius/UAL) : si SetUALRoot n'est jamais appelé (test unitaire, outil chargeant LPAnimMeasure seul), le comportement reste celui d'avant l'extraction.
  • S1-CART.md doit être mis à jour : LPAnimRedirect.cpp n'est plus un consommateur direct de la clé ; LifePlay.cpp le 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 (ligne LPAnimRedirect.cpp:23 → consommation via LifePlay.cpp / SetUALRoot).
  • Aucun commit effectué (consigne de la fiche).