LifePlay-Revival/Docs/Migration/etat/sandbox/S2/S2-CART.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

19 KiB
Raw Blame History

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

  • LPAnimRedirect ne dépend plus de LPSandboxConfig (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 de FLPSandboxConfig::QuaterniusUALRoot, donc comportement inchangé sans ini).
  • LPANIMMEASURE_API ajouté à IsGameTarget() et ClipPath().
  • Câblage côté LifePlay (propriétaire de LPSandboxConfig, qui reste dans LifePlay pour S3) : LifePlay.cpp passe de FDefaultGameModuleImpl à une classe FLifePlayModule : FDefaultGameModuleImpl dont StartupModule() appelle LPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot). Le singleton lit Config/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 : appeler SetUALRoot au début de ALPPairSandboxCharacter::BeginPlay. À éviter : LPDirectControlSubsystem et 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 par SetUALRoot au lieu d'un appel direct. S1-CART.md doit mettre à jour la ligne LPAnimRedirect.cpp:23 (consommateur indirect).
  • Pourquoi (b) plutôt que laisser Redirect hors module : LPPoseOrchestrator (dans LPAnimMeasure) 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 (signatures Run/Restore/SampleAt), et IsGameTarget() 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)

  1. LifePlay.h / LogLifePlay : 3 .cpp (20 appels UE_LOG au total : Measure 12, Orchestrator 4, SkeletonProfile 4) incluent LifePlay.h. LPAnimMeasure ne peut pas dépendre de LifePlay. Solution : catégorie propre LogLPAnimMeasure (LPAnimMeasure.h/.cpp), remplacement mécanique LogLifePlay → LogLPAnimMeasure et #include "LifePlay.h" → #include "LPAnimMeasure.h".
    • Effet de bord : Tools/LogStats.ps1 ligne 51 compte les lignes LogLifePlay (statistique de session). Les lignes POSET/PROFIL migrent vers LogLPAnimMeasure ; ajouter une entrée LogLPAnimMeasure dans ce script (ou accepter la baisse du compteur). Aucune occurrence de LogLifePlay dans Source/LifePlayEditorTools.
  2. LPSandboxConfig.h dans LPAnimRedirect.cpp : voir §1.
  3. Aucune autre référence à des types ALP*/ULP*/FLPSandbox*/FLPPair*/GEngine/UWorld dans LPPoseMeasure.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. Engine public car FLPPose n'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 (+ JsonUtilities non requis) : Dom/JsonObject.h, Serialization/JsonReader.h, JsonSerializer.h dans LPSkeletonProfile.cpp.
  • Aucune dépendance vers LifePlay ni LifePlayEditorTools.
  • Json reste aussi dans LifePlay.Build.cs : il est ajouté en AP1 pour LPSkeletonProfile ; une fois le fichier déplacé, vérifier qu'aucun autre fichier de LifePlay n'utilise Json avant 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)

  1. Créer Source/LPAnimMeasure/ + LPAnimMeasure.Build.cs, LPAnimMeasure.h/.cpp.
  2. git mv des 8 fichiers (conserve l'historique).
  3. Remplacer LIFEPLAY_API → LPANIMMEASURE_API, LifePlay.h → LPAnimMeasure.h, LogLifePlay → LogLPAnimMeasure dans les fichiers déplacés ; ajouter les exports manquants (<28>4.3) ; retirer l'include de LPSandboxConfig.h dans LPAnimRedirect.cpp et ajouter SetUALRoot/GetUALRoot.
  4. LifePlay.cpp : FLifePlayModule::StartupModule → SetUALRoot(...).
  5. Mettre à jour LifePlay.Build.cs, LifePlayEditorTools.Build.cs, LifePlay.uproject, les deux *.Target.cs.
  6. Regénérer le projet (GenerateProjectFiles) et compiler Editor + Game ; lancer la validation (commandlets LPAnimEval, LPAnimCatalog, LPAnimTwist) pour contrôler l'absence de régression.