19 KiB
21. Migration sandbox → addon éditeur (ébauche, 2026-10-06)
Objectif : extraire le code de sandbox Pair / Interaction / Mesure (aujourd'hui dans Source/LifePlay/ et
Source/LifePlayEditorTools/, en grande partie non suivi par git) vers un plugin éditeur dédié, sans casser le
jeu empaqueté ni la chaîne d'animations (20_Chaine_Animations.md). Le module LifePlay ne garde que le contrat
minimal vers le jeu (dont LPShowCoupleSubsystem).
Amont : lot S0 validé (S0-VAL.md : PASS). Inventaire gelé : Docs/Migration/etat/sandbox/S0/S0-CART.md.
Périmètre S0 (fichiers gelés)
Liste figée au 2026-10-06 ; toute évolution ultérieure passe par une fiche de lot et une entrée CHG.
Runtime (Source/LifePlay/)
| Chemin | LOC approx. | Notes |
|---|---|---|
LPPairSandbox.h |
322 | Stage / Character / GameMode Pair |
LPPairSandbox.cpp |
4261 | Monolith Pair, interaction, mesure |
LPInteractionSandbox.* |
— | Retiré S4-T3 (addon) ; Interaction via menu LPPairSandbox |
LPPoseMeasure.h |
100 | API mesure |
LPPoseMeasure.cpp |
1558 | Sample / Transfer / T-fit |
LPSkeletonProfile.h |
38 | Profils JSON |
LPSkeletonProfile.cpp |
157 | |
LPPoseOrchestrator.h |
30 | |
LPPoseOrchestrator.cpp |
487 | |
LPAnimRedirect.h |
15 | Cible sandbox | game |
LPAnimRedirect.cpp |
24 | |
LPShowCoupleSubsystem.h |
77 | Reste dans LifePlay (sync lot S5) |
LPShowCoupleSubsystem.cpp |
1048 |
Éditeur (Source/LifePlayEditorTools/)
| Chemin | LOC approx. | Notes |
|---|---|---|
LPPairCollisionTestCommandlet.* |
~546 | PairCol headless |
LPAnimEvalCommandlet.* |
~489 | Mesure headless |
LPAnimCatalogCommandlet.* |
~388 | |
LPAnimChecks.* |
~435 | |
LPAnimTwistCommandlet.* |
~384 |
Lanceurs (Tools/debug/)
| Chemin | Notes |
|---|---|
LifePlay_pair_sandbox.bat |
Pair |
LifePlay_interaction_sandbox.bat |
Interaction |
LifePlay_measure_sandbox.bat |
Mesure |
Synthèse S0-CART : ~7,5 k LOC runtime sandbox + mesure ; trois lanceurs désormais versionnables (motif
.gitignore : /Debug/).
Contrat (S1 : configuration des chemins)
Le lot S1 fixe le premier contrat jeu ↔ addon : tous les chemins d'assets et de fichiers du sandbox Pair passent par
Config/LPSandbox.ini, lu par un point d'accès unique. Détail : etat/sandbox/S1/S1-SPEC.md ; implémentation
S1-IMPL.md ; audit S1-CART.md ; validation S1-VAL.md (PASS statique ; compilation et runtime à confirmer).
- Fichier :
Config/LPSandbox.ini(versionné, pas dansSaved/), lecture directe non hiérarchique (FConfigFile::Read). - API :
struct LIFEPLAY_API FLPSandboxConfig(Source/LifePlay/LPSandboxConfig.h/.cpp),static const FLPSandboxConfig& Get(), chargé une fois.LPPairSandbox.cppetLPAnimRedirect::ClipPathn'utilisent plus de littéral/Game/.... - Repli : fichier, clé ou valeur vide absents => default = littéral historique (comportement identique sans ini). Un asset introuvable garde le journal
LogLifePlayd'origine, sans repli silencieux. - 19 clés, 6 sections :
Sandbox.Mode(Mode=Pair|Interaction|Mesure,Saved/sandbox_mode.txtreste prioritaire) ;Sandbox.Assets(PersonBP,BridgetMesh,MichaelMesh,QuaterniusMannequinMesh,DazIdleFemale,DazIdleMale,FurnitureWallMaterial) ;Sandbox.Roots(FurnitureRoot,DazAnimRoot,QuaterniusRoot,QuaterniusUALRoot) ;Sandbox.Content, chemins relatifs àContent/(ModuleRoot,WorldFile,ChatAction,QuaterniusUALDisk) ;Sandbox.Sky(SkyCubemap,SkyIntensity) ;Sandbox.Output, relatif àSaved/(MeasureOutputRoot). - Conventions : asset = chemin UE complet
/Game/...Nom.Nom(LoadObject) ; racine = package sans nom d'asset ; disque = relatif àProjectContentDir()(ouProjectSavedDir()pourOutput). - Hors contrat (volontaire) :
LPKeyboard.ini,Saved/sandbox_mode.txt/sandbox_tour.txt, littéraux/Engine/..., noms de clips et poses (Idle_Loop,Walk_Loop,A_TPose,B_/M_), listeNames[]. - Reste ouvert (lots suivants) : points d'accroche ShowCouple (S5) ; staging de
LPSandbox.inisi le sandbox doit tourner empaqueté. (DépendancesBuild.cset répartition des exports : traitées en S2, section suivante.)
Module LPAnimMeasure (S2 : extraction de la chaîne de mesure)
Le lot S2 sort la chaîne de mesure de LifePlay vers un module Runtime dédié, Source/LPAnimMeasure/ (structure plate, comme LifePlay). Détail : etat/sandbox/S2/S2-CART.md (cartographie), S2-IMPL-H.md (implémentation), S2-VAL.md (validation : PASS statique et runtime Mesure).
- Contenu :
LPPoseMeasure,LPSkeletonProfile,LPPoseOrchestrator,LPAnimRedirect(8 fichiers déplacés) +LPAnimMeasure.Build.cs,LPAnimMeasure.h/.cpp(catégorie de journalLogLPAnimMeasure, ex-LogLifePlaypour les lignesPOSET/PROFIL/ORCH/MESURE). - Exports :
LPANIMMEASURE_APIremplaceLIFEPLAY_API; 6 symboles ajoutés pourLPPairSandbox.cpp(KeyBones,LogReport,TFitReport,Run,Restore,SampleAt) ; les structs de données restent header-only. - Rupture du couplage :
LPAnimRedirectne lit plusLPSandboxConfig.FLifePlayModule::StartupModule()(LifePlay.cpp) appelleLPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot); défaut interne/Game/Quaternius/UAL(identique à celui de la config). - Déclaration : entrée
Runtime/DefaultdansLifePlay.uproject, placée avantLifePlay;ExtraModuleNamesdes deux*.Target.cs.
Graphe de dépendances des modules
flowchart LR
LPET["LifePlayEditorTools<br/>(Editor)"] -->|Public| LP["LifePlay<br/>(Runtime, module primaire)"]
LPET -->|Public<br/>FLPPose dans LPAnimChecks.h| AM["LPAnimMeasure<br/>(Runtime, nouveau S2)"]
LP -->|Public<br/>LPPairSandbox, LPDirectControl| AM
LP -.->|"StartupModule : SetUALRoot(QuaterniusUALRoot)"| AM
AM -->|Public| ENG["Core, CoreUObject, Engine"]
AM -->|Private| JSON["Json"]
Règles : LPAnimMeasure ne dépend ni de LifePlay ni de LifePlayEditorTools (graphe acyclique) ; LPSandboxConfig reste dans LifePlay et pousse la configuration vers LPAnimMeasure par un setter, jamais l'inverse. Ordre de chargement LPAnimMeasure avant LifePlay : dépendance Build.cs et ordre du .uproject.
| De | Vers | Type | Motif |
|---|---|---|---|
LifePlay |
LPAnimMeasure |
Public | LPPairSandbox.h/.cpp, LPDirectControlSubsystem.cpp, LifePlay.cpp |
LifePlayEditorTools |
LifePlay |
Public | existant |
LifePlayEditorTools |
LPAnimMeasure |
Public | LPAnimChecks.h expose FLPPose ; commandlets LPAnimEval, LPAnimCatalog, LPAnimTwist |
LPAnimMeasure |
Core, CoreUObject, Engine / Json |
Public / Privé | animations, squelettes ; lecture de Tools/anim/profiles/*.json |
LPAnimMeasure |
LifePlay, LifePlayEditorTools |
aucune | évite un cycle de modules |
Stratégie git et liaison jeu ↔ addon (S3)
Le lot S3 déplace le code sandbox dans un dépôt séparé, LifePlay-Sandbox (https://github.com/edujiro5972/LifePlay-Sandbox.git, branche main). Détail : etat/sandbox/S3/S3-INT.md ; validation : etat/sandbox/S3/S3-VAL.md (PASS).
Décision : deux dépôts siblings + AdditionalPluginDirectories. Pas de submodule imbriqué.
D:\Game\
LifePlay-master 5.5\ <- jeu (repo LifePlay)
LifePlay-Sandbox\ <- addon (repo LifePlay-Sandbox)
- Liaison :
LifePlay.uprojectdéclare"AdditionalPluginDirectories": ["../LifePlay-Sandbox/Plugins"](chemin relatif au.uproject) et activeLPSandboxdansPlugins. UBT et l'éditeur y trouventLPSandbox.uplugin(modulesLPSandboxetLPAnimMeasure) ; les DLL du plugin sont compilées avec le jeu (Build.bat LifePlayEditor Win64 Development). - Pourquoi pas un submodule : l'addon est un
uprojectmince qui contient le plugin sousPlugins/LPSandbox/. Un submodule monté surPlugins/LPSandboxdu jeu donneraitPlugins/LPSandbox/Plugins/LPSandbox/(plugin imbriqué, non scanné au bon niveau) ; un submoduleExternal/LifePlay-Sandboxdupliquerait l'addon à côté du sibling et rendrait ambigu l'exemplaire chargé. Un clone sibling évite les deux problèmes. - Pin : le jeu consomme un commit précis de l'addon, consigné à la main dans
S3-INT.md(aujourd'hui82dae58380b76c45f60541fd7cb5a0a409700e10,lot/SB1-registre, SB1 registre de mods et barre latérale ; précédents :3b21fd180c04f0fa49a1b5c9ef1b517ade1cb362SB0 conception de la sandbox modulaire,f09c42e5a2bc613cf269cce76c878461ca41c8b7S7-T2 uplugin,c1fdd29e2c1036c7d6365ba6389eff5d2f8c8c96S5-T2LPCoupleSim,f8102647ccdebad37e4977ccbf2c51e583823a80, S4-T3). Le pin est mis à jour (hash dansS3-INT.mdet README de l'addon) à chaque évolution de l'addon que le jeu doit prendre. Reproduire :
cd D:\Game
git clone https://github.com/edujiro5972/LifePlay-Sandbox.git
git -C LifePlay-Sandbox checkout 82dae58380b76c45f60541fd7cb5a0a409700e10
# le jeu doit être cloné à côté : D:\Game\LifePlay-master 5.5
- Content : le jeu n'a rien à monter. L'addon utilisé seul (
LPSandbox.uproject) a besoin du Content du jeu : junction NTFSLifePlay-Sandbox\Content→LifePlay-master 5.5\Content(/Gamene peut pointer que vers<projet>/Content; la cléAdditionalAssetDirectoriesn'existe pas en UE 5.5). Voir le README de l'addon. - Contenu du jeu après S3-T3 :
Source/LPAnimMeasure/et les fichiersLPPairSandbox*,LPInteractionSandbox*,LPSandboxConfig*ne sont plus dans le jeu. Le bat Pair lance toujoursLifePlay.uprojectavecgame=/Script/LPSandbox.LPPairSandboxGameMode.Source/LifePlay/LifePlay.Build.csdépend toujours deLPAnimMeasure(module désormais fourni par le plugin). - Validation S3-VAL : bat Pair depuis le jeu, plugin monté et GameMode résolu sans erreur de module ; addon mince lancé avec le même GameMode (réserve : son
.uprojectn'active pasStreetMap, d'où des erreurs de chargement de Blueprints du jeu sans effet sur le sandbox).
CoupleBox : LPCoupleSim partagé (S5)
Le lot S5 ferme la dérive de fork entre la sandbox (LPSandbox/LPCoupleSim.cpp, méthodes de ALPPairSandboxStage) et le jeu (LPShowCoupleSubsystem) : les deux gardaient une copie de la géométrie du couple (mesure de pose, boîte, balayage, soudure) qui divergeait (plancher −90 / −88, itérations 2 / 3, os exclus). Détail : etat/sandbox/S5/S5-CART.md (écarts), S5-IMPL-H.md (implémentation), S5-VAL.md (validation : PASS runtime Pair, PASS-STATIC ShowCouple). Addon pinné sur c1fdd29.
- Où : header
Plugins/LPSandbox/Source/LPAnimMeasure/LPCoupleSim.h(215 l.) etLPCoupleSimCore.cpp(474 l.), moduleLPAnimMeasure,namespace LPCoupleSim, exportsLPANIMMEASURE_API. Une seule copie : le jeu la voit parLifePlay.Build.cs(dépendance publique existante), sans recopie ni changement de.Build.cs. Le nomLPCoupleSimCore.cppévite la collision avecLPSandbox/LPCoupleSim.cpp. - Trois niveaux d'API :
- pur (sans
UObjectniUWorld, testable sans monde) :MeshToActor,ComposeComponentSpace,AccumulatePoints,IsExcludedLiveBone,FitFromAnimBounds,FitFromLiveBounds,SlideWish; - lecture :
CapsuleHalfOf,AccumulateAnimBounds(8 pas, os animés,GetBoneTransform(raw=false)),AccumulateLiveBody; - effets de bord :
EnsureBox,ApplyBoxFit,PlaceBodyMesh,SaveAndFreeze/RestoreMove(FSavedMove),AttachPartner,Unweld,ResolveCoupleMove.
- pur (sans
- Paramètres :
FBoxFitParams(demi-capsule 88, pad anime 12/12/6 plafond 800, pad vivant 4/4/4 min 8 plafond 400, ancre pelvis 140,FloorLocalZ,MinExtentZ20) ;FSweepOptions::Show()(3 itérations,SweepMulti, dépénétration, PNJ + coqueWall*ignorés) etFSweepOptions::Sandbox()(2 itérations,SweepSingle, arrêt net, marches, Z à plat).ResolveCoupleMovene déplace rien : elle rend la position retenue (FSweepResult), chaque appelant l'applique. - Appelants : sandbox
FitCoupleBox/Weld/MoveCouple; jeuFitBox/FitToBodies/Weld/Engage/Release/KeepTogether. Les copiesAddPose(jeu),Accumulate(sandbox), les deux créations deUBoxComponentet les deux boucles de balayage n'existent plus (−336 lignes dupliquées, +689 dans le module partagé). - Écarts conservés volontairement (options, pas de copies) : plancher sandbox −90 contre jeu −88 (
FloorLocalZ), balayage simple 2 itérations contre multi 3 itérations, nom de composantCoupleBoxcontreLPShowCoupleBox. L'alignement du plancher est une ligne dansFitCoupleBox, à décider après capture en jeu. - Reste dans
LifePlay: sélection du couple (SexPersons,AP1/AP2,ShowReach), réflexionGI/Room,IsBedMesh(injecté viaIsWalkableSupport),IsUseFurniture,OpenUseFurniture,PairSibling/IsIdleClip,FlipResponse/RestoreResponses(non partagés, hors S5-T2), CVarlp.ShowCouple. - Contrat de modification : tout changement de géométrie du couple se fait dans
LPCoupleSim(addon), puis bump du pin ; le jeu ne doit pas réintroduire de copie locale.
Acceptation
État au 2026-10-06 (lot S8). Case cochée = prouvée par la fiche citée ; case vide = non faite.
- S0 : hygiène dépôt, inventaire gelé (
S0-VAL.mdPASS). - S1 : tous les chemins du sandbox via
Config/LPSandbox.ini(S1-VAL.mdPASS statique). - S2 : module
LPAnimMeasureextrait, sans dépendance versLifePlay(S2-VAL.mdPASS). - S3 : addon dans le dépôt
LifePlay-Sandbox, liaison sibling +AdditionalPluginDirectories, pin manuel (S3-VAL.mdPASS). - S4 : sandbox Pair découpé, GameMode Interaction legacy retiré (
S4-VAL.mdPASS). - S5 : géométrie du couple partagée via
LPCoupleSim, une seule copie (S5-VAL.mdPASS runtime Pair, PASS-STATIC ShowCouple). - S6 : stack Mesure sur la liaison addon,
LPAnimEvalcourt (S6-VAL.mdPASS). - S7 / isolation : plugin sans
include/LIFEPLAY_API/ moduleLifePlay;Person= CDO seul, aucunGI/Room; chemins par config (S7-SPEC.md,S7-CART.md: 0 écart). - S7 / configurations :
LPSandboxhors Shipping (TargetConfigurationDenyList),LPAnimMeasureconservé, pluginOptionaldansLifePlay.uproject(S7-IMPL-L.md). - Smoke Pair (bat court, plugin monté, boîte du couple identique à S5-VAL, 0 crash) (
S7-VAL.md). - Commandlets anim restants (
LPAnimCatalog,LPAnimChecks,LPAnimTwist) déplacés dans un module éditeur de l'addon : non fait (restent dansLifePlayEditorTools). - S8 : bilan du mode multi-agents (
22_Eval_Agents_Sandbox.md: GO conditionnel) ; code sandbox absent du module jeu depuis S3 ; smoke Pair par le.batréel, boîte du couple identique à S5 / S7, 0 crash (S8-VAL.mdPASS). BuildMod.ps1 -Target sandbox -Openrejoué sur la liaison addon : non fait.- Compilation / packaging Shipping complets avec le plugin (seul le plan UBT est vérifié).
- Parcours Show complet en jeu et décision d'alignement du plancher (-90 / -88).
- Commit addon
f09c42epoussé versorigin/main(constaté en S8 :origin/main=dae6206, qui le contient). - Migration commitée côté jeu (
LifePlay.uproject,Config/LPSandbox.ini,Build.cs,LPShowCoupleSubsystem.*, docs21/22,etat/sandbox/) : non fait (22§ 6). - SB0 : conception de la sandbox modulaire (addon, pin
3b21fd1, taglot-SB0-valide). - SB1 : registre de mods, barre latérale, 7 descripteurs
.lpmod, modes Pair / Interaction / Mesure enveloppés enlps_couple/lps_interaction/lps_asset_integration(etat/sandbox/SB1/SB1-VAL.mdPASS, contrôle visuel utilisateur 2026-10-07 ; taglot-SB1-valide). - Reports SB1 (registre unique, lot propriétaire SB2) : chaque ouverture de mod réécrit
OpendansSaved/sandbox_mods.ini(une tournée automatique laisse doncOpen=lps_asset_integration) ; images de la tournée Mesure : empreintes différentes d'une exécution à l'autre (JSON et CSV identiques), la non-régression stricte de SB2-T5 doit comparer les JSON/CSV, et les images visuellement ou par écart de pixels.
Lots (S0 … S8)
| Lot | Objet (une ligne) |
|---|---|
| S0 | Hygiène dépôt : /Debug/ dans .gitignore, lanceurs Tools/debug suivis, inventaire et preuves etat/sandbox/S0/*. |
| S1 | Contrat jeu ↔ addon : API minimale, dépendances modules, règles de linking (placeholder ci-dessus). |
| S2 | Extraction du module LPAnimMeasure (mesure, profils, orchestrateur, redirection) hors de LifePlay ; dépendances Build.cs et exports. Fait : S2-VAL.md PASS (voir section « Module LPAnimMeasure »). Le plugin éditeur (uplugin) reste à faire. |
| S3 | Création du dépôt addon LifePlay-Sandbox (scaffold, transfert du code, retrait côté jeu) et liaison par clone sibling + AdditionalPluginDirectories, pin manuel. Fait : S3-VAL.md PASS (voir section « Stratégie git »). Rejeu stack Mesure : lot S6 (S6-VAL.md). |
| S4 | Sandbox Pair : découpage LPPairSandbox, retrait GM Interaction legacy (S4-T3 fait), commandlet LPPairCollisionTest, bat Pair. Validation : S4-VAL.md (PASS). |
| S5 | ShowCouple : LPShowCoupleSubsystem reste dans LifePlay ; géométrie du couple partagée via LPCoupleSim (module LPAnimMeasure de l'addon, pin c1fdd29). Fait : S5-VAL.md PASS (runtime Pair, PASS-STATIC ShowCouple ; voir section « CoupleBox »). Show complet en jeu et alignement du plancher restent à valider. |
| S6 | Stack Mesure sur la liaison addon : LifePlayEditorTools → LPAnimMeasure (plugin), lanceurs Tools/debug, sorties Saved/Measurement, commandlet -run=LPAnimEval. Fait : S6-VAL.md PASS (doc 20 / 09, essai court LPAnimEval). |
| S7 | Isolation du plugin (sans lien vers LifePlay, Person en CDO seul, config seulement), LPSandbox hors Shipping, Optional dans LifePlay.uproject. Fait : S7-VAL.md PASS (smoke Pair ; Shipping vérifié par plan UBT). Le déplacement des commandlets Catalog / Checks / Twist reste à planifier (voir § Acceptation). |
| S8 | Bilan et clôture : évaluation du mode multi-agents + multi-modèles (22_Eval_Agents_Sandbox.md, GO conditionnel, 3 recommandations), smoke Pair final. Fait : S8-VAL.md PASS. BuildMod -Target et commit côté jeu restent ouverts (§ Acceptation). |
Chaque lot suit 10_Protocole_Operations.md : instantané, entrée CHG, retour arrière documenté.