LifePlay-Revival/Docs/Migration/21_Sandbox_Addon.md
edujiro5972 83b366aeef DC4 : cloture du decouplage jeu / sandbox (CHG-245)
DC4-VAL PASS (clone propre sans addon, build empaquete sans addon, test en jeu utilisateur),
evaluation DC4-EVAL ; piege UBT Makefile.bin et compilation sans addon documentes dans 09/18 ;
plan 24 termine ; reports DC2/DC3 coches dans 21.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 08:12:14 +02:00

214 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 dans `Saved/` ; depuis DC3 il vit dans l'addon, avec sa section `[Workshop]` `GameRoot`), 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.cpp` et `LPAnimRedirect::ClipPath` n'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 `LogLifePlay` d'origine, sans repli silencieux.
- **19 clés, 6 sections** : `Sandbox.Mode` (`Mode` = `Pair` | `Interaction` | `Mesure`, `Saved/sandbox_mode.txt` reste 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()` (ou `ProjectSavedDir()` pour `Output`).
- **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_`), liste `Names[]`.
- **Reste ouvert (lots suivants)** : points d'accroche ShowCouple (S5) ; staging de `LPSandbox.ini` si le sandbox doit tourner empaqueté. (Dépendances `Build.cs` et 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 journal `LogLPAnimMeasure`, ex-`LogLifePlay` pour les lignes `POSET` / `PROFIL` / `ORCH` / `MESURE`).
- **Exports** : `LPANIMMEASURE_API` remplace `LIFEPLAY_API` ; 6 symboles ajoutés pour `LPPairSandbox.cpp` (`KeyBones`, `LogReport`, `TFitReport`, `Run`, `Restore`, `SampleAt`) ; les structs de données restent header-only.
- **Rupture du couplage** : `LPAnimRedirect` ne lit plus `LPSandboxConfig`. l'addon (`LPSandbox.cpp:17`) appelle `LPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot)` (`FLifePlayModule::StartupModule()` ne l'appelle plus) ; depuis DC1, `LPAnimRedirect` et `LPCoupleSim` sont dans le plugin du jeu `Plugins/LPAnimCore` ; défaut interne `/Game/Quaternius/UAL` (identique à celui de la config).
- **Déclaration** : entrée `Runtime` / `Default` dans `LifePlay.uproject`, placée avant `LifePlay` ; `ExtraModuleNames` des deux `*.Target.cs`.
### Graphe de dépendances des modules
```mermaid
flowchart LR
LPET["LifePlayEditorTools<br/>(Editor)"] -->|Public| LP["LifePlay<br/>(Runtime, module primaire)"]
MT["LPModTools<br/>(Editor, addon, DC2)"] -->|Public| AM["LPAnimMeasure<br/>(Runtime, nouveau S2)"]
LP -->|Public<br/>LPPairSandbox, LPDirectControl| AM
LP -->|Public DC1| AC["LPAnimCore<br/>(plugin du jeu : LPAnimRedirect, LPCoupleSim)"]
AM -->|Private DC1| AC
SB["LPSandbox<br/>(addon)"] -->|DC1| AM
SB -->|DC1| AC
SB -.->|"LPSandbox.cpp:17 : SetUALRoot(QuaterniusUALRoot)"| AC
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` |
| `LifePlay` | `LPAnimCore` | Public | DC1 : `LPAnimRedirect`, `LPCoupleSim` (plugin du jeu `Plugins/LPAnimCore`) |
| `LPAnimMeasure` | `LPAnimCore` | Private | DC1 : la mesure utilise `LPAnimRedirect` |
| `LPSandbox` | `LPAnimMeasure`, `LPAnimCore` | Public | DC1 : mesure et redirection / géométrie du couple |
| `LifePlayEditorTools` | `LifePlay` | Public | existant |
| `LPModTools` (Editor, addon) | `LPAnimMeasure` | Public | DC2 : `LPAnimChecks.h` expose `FLPPose` ; commandlets `LPAnimEval`, `LPAnimCatalog`, `LPAnimTwist`, `LPAnimIdentify`, `LPHairFromStaticMesh` (ex-`LifePlayEditorTools`, qui ne dépend plus de `LPAnimMeasure`) |
| `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.uproject` déclare `"AdditionalPluginDirectories": ["../LifePlay-Sandbox/Plugins"]` (chemin relatif au `.uproject`) et active `LPSandbox` dans `Plugins`. UBT et l'éditeur y trouvent `LPSandbox.uplugin` (modules `LPSandbox` et `LPAnimMeasure`) ; les DLL du plugin sont compilées avec le jeu (`Build.bat LifePlayEditor Win64 Development`).
- **Pourquoi pas un submodule** : l'addon est un `uproject` mince qui contient le plugin sous `Plugins/LPSandbox/`. Un submodule monté sur `Plugins/LPSandbox` du jeu donnerait `Plugins/LPSandbox/Plugins/LPSandbox/` (plugin imbriqué, non scanné au bon niveau) ; un submodule `External/LifePlay-Sandbox` dupliquerait 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'hui `79f0205b7281152dde7cd088086d8c813e0b20f5`, `lot/DC3-atelier`, DC3 atelier de mods (scripts, `ModSources`, `AnimSources`) dans l'addon ; précédents : `97c0d134cd1388c3735add79d77ea98817e89fbe` DC2 module éditeur `LPModTools` et chemins propres à l'addon, `3e9c32f1f27b1abdaf7731dc90496c27ee061718` DC1 `LPAnimRedirect` et `LPCoupleSim` rapatriés dans le plugin `LPAnimCore` du jeu, `16905c68070992f5139dab907b41b461fb765957` SB4 ouverture par déclencheur éphémère non mémorisée, `3d858527fccfdddd8711c7c7448fa001442e0b8a` SB2-O1 correction de `ShowRoom`, `fece7e9a0e63b3058b5d24d96d669a3c9c0e9add` SB2 bibliothèques de scène et de personnages, caméra du socle, état des modes sorti vers les mods, `82dae58380b76c45f60541fd7cb5a0a409700e10` SB1 registre de mods et barre latérale, `3b21fd180c04f0fa49a1b5c9ef1b517ade1cb362` SB0 conception de la sandbox modulaire, `f09c42e5a2bc613cf269cce76c878461ca41c8b7` S7-T2 uplugin, `c1fdd29e2c1036c7d6365ba6389eff5d2f8c8c96` S5-T2 `LPCoupleSim`, `f8102647ccdebad37e4977ccbf2c51e583823a80`, S4-T3). Le pin est mis à jour (hash dans `S3-INT.md` et README de l'addon) à chaque évolution de l'addon que le jeu doit prendre. Reproduire :
```powershell
cd D:\Game
git clone https://github.com/edujiro5972/LifePlay-Sandbox.git
git -C LifePlay-Sandbox checkout 79f0205b7281152dde7cd088086d8c813e0b20f5
# 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 NTFS `LifePlay-Sandbox\Content` → `LifePlay-master 5.5\Content` (`/Game` ne peut pointer que vers `<projet>/Content` ; la clé `AdditionalAssetDirectories` n'existe pas en UE 5.5). Voir le README de l'addon.
- **Contenu du jeu après S3-T3** : `Source/LPAnimMeasure/` et les fichiers `LPPairSandbox*`, `LPInteractionSandbox*`, `LPSandboxConfig*` ne sont plus dans le jeu. Le bat Pair lance toujours `LifePlay.uproject` avec `game=/Script/LPSandbox.LPPairSandboxGameMode`. `Source/LifePlay/LifePlay.Build.cs` dépend toujours de `LPAnimMeasure` (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 `.uproject` n'active pas `StreetMap`, 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.) et `LPCoupleSimCore.cpp` (474 l.), module `LPAnimMeasure`, `namespace LPCoupleSim`, exports `LPANIMMEASURE_API`. Une seule copie : le jeu la voit par `LifePlay.Build.cs` (dépendance publique existante), sans recopie ni changement de `.Build.cs`. Le nom `LPCoupleSimCore.cpp` évite la collision avec `LPSandbox/LPCoupleSim.cpp`.
- **Trois niveaux d'API** :
- *pur* (sans `UObject` ni `UWorld`, 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`.
- **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`, `MinExtentZ` 20) ; `FSweepOptions::Show()` (3 itérations, `SweepMulti`, dépénétration, PNJ + coque `Wall*` ignorés) et `FSweepOptions::Sandbox()` (2 itérations, `SweepSingle`, arrêt net, marches, Z à plat). `ResolveCoupleMove` **ne déplace rien** : elle rend la position retenue (`FSweepResult`), chaque appelant l'applique.
- **Appelants** : sandbox `FitCoupleBox` / `Weld` / `MoveCouple` ; jeu `FitBox` / `FitToBodies` / `Weld` / `Engage` / `Release` / `KeepTogether`. Les copies `AddPose` (jeu), `Accumulate` (sandbox), les deux créations de `UBoxComponent` et 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 composant `CoupleBox` contre `LPShowCoupleBox`. L'alignement du plancher est une ligne dans `FitCoupleBox`, à décider après capture en jeu.
- **Reste dans `LifePlay`** : sélection du couple (`SexPersons`, `AP1/AP2`, `ShowReach`), réflexion `GI` / `Room`, `IsBedMesh` (injecté via `IsWalkableSupport`), `IsUseFurniture`, `OpenUseFurniture`, `PairSibling` / `IsIdleClip`, `FlipResponse` / `RestoreResponses` (non partagés, hors S5-T2), CVar `lp.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.
- [x] **S0** : hygiène dépôt, inventaire gelé (`S0-VAL.md` PASS).
- [x] **S1** : tous les chemins du sandbox via `Config/LPSandbox.ini` (`S1-VAL.md` PASS statique).
- [x] **S2** : module `LPAnimMeasure` extrait, sans dépendance vers `LifePlay` (`S2-VAL.md` PASS).
- [x] **S3** : addon dans le dépôt `LifePlay-Sandbox`, liaison sibling + `AdditionalPluginDirectories`, pin manuel (`S3-VAL.md` PASS).
- [x] **S4** : sandbox Pair découpé, GameMode Interaction legacy retiré (`S4-VAL.md` PASS).
- [x] **S5** : géométrie du couple partagée via `LPCoupleSim`, une seule copie (`S5-VAL.md` PASS runtime Pair, PASS-STATIC ShowCouple).
- [x] **S6** : stack Mesure sur la liaison addon, `LPAnimEval` court (`S6-VAL.md` PASS).
- [x] **S7 / isolation** : plugin sans `include` / `LIFEPLAY_API` / module `LifePlay` ; `Person` = CDO seul, aucun `GI` / `Room` ; chemins par config (`S7-SPEC.md`, `S7-CART.md` : 0 écart).
- [x] **S7 / configurations** : `LPSandbox` hors Shipping (`TargetConfigurationDenyList`), `LPAnimMeasure` conservé, plugin `Optional` dans `LifePlay.uproject` (`S7-IMPL-L.md`).
- [x] **Smoke Pair** (bat court, plugin monté, boîte du couple identique à S5-VAL, 0 crash) (`S7-VAL.md`).
- [x] Commandlets anim restants (`LPAnimCatalog`, `LPAnimChecks`, `LPAnimTwist`) déplacés dans un module éditeur de l'addon : **fait au lot DC2** (module `LPModTools`, avec `LPAnimEval`, `LPAnimIdentify`, `LPAnimMethodSelect`, `LPHairFromStaticMesh`).
- [x] **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 `.bat` réel, boîte du couple identique à S5 / S7, 0 crash (`S8-VAL.md` PASS).
- [ ] `BuildMod.ps1 -Target sandbox -Open` rejoué 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).
- [x] Commit addon `f09c42e` poussé vers `origin/main` (constaté en S8 : `origin/main` = `dae6206`, qui le contient).
- [ ] Migration commitée **côté jeu** (`LifePlay.uproject`, `Config/LPSandbox.ini`, `Build.cs`, `LPShowCoupleSubsystem.*`, docs `21` / `22`, `etat/sandbox/`) : **non fait** (`22` § 6).
- [x] **SB0** : conception de la sandbox modulaire (addon, pin `3b21fd1`, tag `lot-SB0-valide`).
- [x] **SB1** : registre de mods, barre latérale, 7 descripteurs `.lpmod`, modes Pair / Interaction / Mesure enveloppés en `lps_couple` / `lps_interaction` / `lps_asset_integration` (`etat/sandbox/SB1/SB1-VAL.md` PASS, contrôle visuel utilisateur 2026-10-07 ; tag `lot-SB1-valide`).
- [x] **SB2** : bibliothèques `lps_lib_scene` / `lps_lib_actors`, caméra du socle, état des modes sorti vers les mods `lps_couple` / `lps_interaction` / `lps_asset_integration` (`etat/sandbox/SB2/SB2-VAL.md` PASS, contrôle visuel utilisateur 2026-10-07 ; tag `lot-SB2-valide`).
- [x] Reports SB1 (registre unique, lot propriétaire **SB2**) : (traité) images de la tournée Mesure non déterministes : SB2-T5 compare les JSON/CSV (identiques) et les images visuellement ; (traité, SB4-T0, prouvé SB4-VAL F2) « Open réécrit » : chaque ouverture de mod réécrit `Open` dans `Saved/sandbox_mods.ini` (une tournée automatique laisse donc `Open=lps_asset_integration`). Corrigé : `Open(Id, Context, bRemember)`, une ouverture par `Saved/sandbox_mode.txt` n'est plus mémorisée.
- [x] **SB4** : validation finale (SB4-VAL PASS : démarrage, tournées Quaternius et FreeAnimationsPack identiques à SB2-REF, LPAnimEval identique, Open intact), doc 23 § 7 ; commit `16905c6` et tag `lot-SB4-valide` ; évaluation `etat/sandbox/SB4/SB4-EVAL.md` : GO transposition.
- [x] **G-SB3** : SB3 abandonné (décision utilisateur 2026-10-07). Motif : les mods du jeu sont du contenu (.lpmod + pak), leurs dépendances sont vérifiées par le registre (prouvé en SB1/SB2) ; coût ≈ 1 à 1,5 lot, et `LPAnimMeasure` est utilisé par le jeu en Shipping ; on passe à SB4.
- [x] **SB2-O1** : correction du défaut O1 (`etat/sandbox/SB2/SB2-O1-BUILD.md` PASS, contrôle visuel utilisateur 2026-10-07 ; tag `lot-SB2-O1-valide`).
- [x] Reports SB2 : (O1) traité (SB2-O1, `3d858527fccfdddd8711c7c7448fa001442e0b8a` : `ShowRoom` symétrique de `HideRoom`, contrôle visuel utilisateur 2026-10-07 « c'est bon ») ; (E3) sans `lps_lib_scene`, la pièce est construite quand même : non traité, séparation physique abandonnée à la porte G-SB3 (décision utilisateur 2026-10-07).
- [x] **DC0** : cartographie et SPEC du découplage jeu / sandbox (`etat/sandbox/DC0/DC0-SPEC.md`, approuvée par l'utilisateur 2026-10-07) ; plan `24_Plan_Decouplage_Sandbox.md`.
- [x] **DC1** : Plugin LPAnimCore dans le jeu, LPAnimMeasure réduit à la mesure (DC1-T1..T5) (DC1-VAL PASS, contrôle visuel utilisateur 2026-10-07 ; tag addon lot-DC1-valide).
- [x] **DC2** : Commandlets de mods vers un module éditeur de la sandbox (DC2-T1..T5) (DC2-VAL PASS ; tag addon lot-DC2-valide ; le jeu compile et démarre sans l'addon).
- [x] **DC3** : Scripts, données et sources de mods vers la sandbox (DC3-T1..T5) (DC3-VAL PASS ; tag addon lot-DC3-valide ; atelier de mods dans l'addon).
- [x] **DC4** : Preuve « jeu seul », docs, évaluation (DC4-T1..T4) (DC4-VAL PASS, test en jeu utilisateur 2026-10-07 ; évaluation DC4-EVAL : le jeu public compile et tourne sans l'addon).
- [ ] Intégration des déplacements dans le jeu à améliorer (remarque utilisateur au contrôle visuel DC1, 2026-10-07) ; lot propriétaire : à définir, hors DC.
- [x] Reports DC0 (lot propriétaire **DC1**, traité : texte corrigé en § Rupture du couplage) : § Rupture du couplage : la mention d'un appel à SetUALRoot par FLifePlayModule::StartupModule() est périmée ; seul l'addon l'appelle (LPSandbox.cpp:17, LPSandboxMeasure.cpp:39) — voir DC0-CART b2.
- [x] Report DC2 (traité en DC3 : `-Livraison=` obligatoire) : `LPAnimCatalog` ignore `-DryRun` et a des valeurs par défaut (pack quaternius) : lancé sans arguments, il réécrit `Saved/AnimPipeline/quaternius/fiches_calculees.json` (DC2-VAL anomalie 1) — lot propriétaire DC3.
- [x] Report DC2 (traité en DC4, `fbbcee1`) : `LifePlay.Build.cs` garde `Json` avec un commentaire AP1 périmé (plus aucun usage dans `LifePlay`) — lot propriétaire DC4.
- [x] Report DC2 (traité : documenté dans `09`/`18`) : sans addon, l'absence est silencieuse au runtime ; l'éditeur/UBT affiche `AdditionalPluginDirectory … not found` (avertissement, non bloquant) — pour information, DC4 docs.
- [x] Report DC3 (traité : documenté dans `09`/`18`) : après un test sans addon, UBT réutilise un `Makefile.bin` sans les modules de l'addon : le déplacer avant de recompiler (DC3-BUILD) — à écrire dans `09`/`18` — lot propriétaire DC4.
- [ ] Numéros de docs en double : `23_Video_Quality.md` / `23_Cycle_De_Vie_Mod.md` et `24_Eval_Agents_VideoQuality.md` / `24_Plan_Decouplage_Sandbox.md` (pour information, sans renommage) ; lot propriétaire : à définir.
## 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é.