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

9.4 KiB

S1-T1 — Contrat Config/LPSandbox.ini

Rôle : A-ARCH. Périmètre : spécification uniquement (aucun changement runtime dans cette fiche). Source analysée : Source/LifePlay/LPPairSandbox.cpp (et .h, qui ne contient aucun littéral de chemin : seulement QuaterniusMesh / QuaterniusClips en FString, lignes 261-262) + Source/LifePlay/LPAnimRedirect.cpp:22 (helper ClipPath utilisé par le sandbox).

1. Décisions de contrat

Décision Choix
Emplacement Config/LPSandbox.ini (projet, versionné). Pas Saved/.
Lecture (S2, hors périmètre ici) FConfigFile::Read(FPaths::Combine(FPaths::ProjectConfigDir(), TEXT("LPSandbox.ini"))) — lecture directe, non hiérarchique (pas de DefaultLPSandbox.ini).
Fichier absent / clé absente Repli sur le default = littéral actuel du code (colonne « default »). Le comportement actuel doit rester identique sans ini.
Section Une section par thème : [Sandbox.Mode], [Sandbox.Assets], [Sandbox.Roots], [Sandbox.Content], [Sandbox.Sky], [Sandbox.Output].
Convention de chemin asset Chemin UE complet /Game/...Nom.Nom (format LoadObject), sauf mention « racine » (sans .Nom).
Convention de chemin disque Relatif à FPaths::ProjectContentDir() / ProjectSavedDir() selon la clé (le préfixe est noté dans l'usage).
Hors contrat (volontairement) Saved/Config/Windows/LPKeyboard.ini (config clavier utilisateur, reste en Saved), Saved/sandbox_mode.txt et Saved/sandbox_tour.txt (déclencheurs éphémères consommés au lancement), littéraux /Engine/... (Cube, BP_Sky_Sphere), noms de clips/poses (Idle_Loop, Walk_Loop, A_TPose, préfixes B_/M_), liste des 43 poses Names[] (l. ~3365-3376).

2. Tableau des clés

Les clés notées * sont critiques (demandées par la fiche). Numéros de ligne = LPPairSandbox.cpp au moment de l'analyse.

clé ini section valeur default usage dans code fichier:ligne
PersonBP * Sandbox.Assets /Game/BPs/Person.Person_C LoadObject<UClass> : lecture des défauts de capsule (rayon, demi-hauteur) dans ALPPairSandboxStage::Build LPPairSandbox.cpp:844
PersonBP (même clé, 2e usage) Sandbox.Assets idem LoadObject<UClass> : copie du profil/réponses de collision de la capsule dans ConfigureCapsule LPPairSandbox.cpp:1089
WorldFile * Sandbox.Content Modules/vin_Base/World/work___vin01.lpworld Fichier de la chambre (props + échelle) ; chemin = ProjectContentDir() + valeur ; passé à PairSandbox::LoadWorldFile LPPairSandbox.cpp:832
ModuleRoot * Sandbox.Content Modules/vin_Base Racine du scan récursif *.lpaction (catalogue d'actions Interaction) ; ProjectContentDir() + valeur LPPairSandbox.cpp:622
ChatAction Sandbox.Content Modules/vin_Base/Interactions/chat.lpaction Lecture de ACTION_NAME pour ChatLabel ; ProjectContentDir() + valeur LPPairSandbox.cpp:1045
FurnitureRoot * Sandbox.Roots /Game/Heavy/New2/Furniture Racine des meshes de meubles : "<racine>/%s.%s" avec Prop.Name issu du .lpworld LPPairSandbox.cpp:857
FurnitureWallMaterial Sandbox.Assets /Game/Heavy/New2/Furniture/Materials/FntWall.FntWall LoadObject<UMaterialInterface> : matériau des murs/coque de la chambre LPPairSandbox.cpp:877
DazAnimRoot * Sandbox.Roots /Game/Heavy/Daz/Anims Racine des clips Daz : paires "<racine>/%s%s.%s%s" (Pair + _F/_M) ; idles Daz LPPairSandbox.cpp:2610, 3106, 1078-1079
DazIdleFemale Sandbox.Assets /Game/Heavy/Daz/Anims/Idle_F_Daz.Idle_F_Daz PlayIdle(bFemale = true) LPPairSandbox.cpp:1078
DazIdleMale Sandbox.Assets /Game/Heavy/Daz/Anims/idle_Daz.idle_Daz PlayIdle(bFemale = false) LPPairSandbox.cpp:1079
BridgetMesh * Sandbox.Assets /Game/Heavy/Daz/Bridget/bridget_gp.bridget_gp Corps Bridget : ApplyBody("Bridget") et mode Mesure (Place("Bridget", …)) LPPairSandbox.cpp:3026, 1529
MichaelMesh * Sandbox.Assets /Game/Heavy/Daz/Michael/michael.michael Corps Michael : ApplyBody("Michael") LPPairSandbox.cpp:3030
QuaterniusRoot * Sandbox.Roots /Game/Quaternius ScanPathsSynchronous de l'Asset Registry avant détection du corps/clips LPPairSandbox.cpp:2962
QuaterniusUALRoot * Sandbox.Roots /Game/Quaternius/UAL GetAssetsByPath (détection auto du mesh le plus riche en bones + clips non B_/M_) ; sert aussi de base à LPAnimRedirect::ClipPath ("<racine>/%s.%s") LPPairSandbox.cpp:2964, LPAnimRedirect.cpp:22
QuaterniusUALDisk Sandbox.Content Quaternius/UAL Dossier disque scanné (*.uasset) pour lister les clips ayant une copie B_ (43 clips) ; ProjectContentDir() + valeur LPPairSandbox.cpp:1894
QuaterniusMannequinMesh Sandbox.Assets /Game/Quaternius/UAL/UAL1_Standard.UAL1_Standard Mannequin de référence en mode Mesure (Place("Mannequin", …)) LPPairSandbox.cpp:1528
Mode * Sandbox.Mode Pair Mode initial du menu. Valeurs : Pair, Interaction, Mesure (liste Modes, Modes[0] = Pair). Aujourd'hui seul Mesure est activable, via Saved/sandbox_mode.txt ; l'ini fournirait le mode persistant. Le .txt éphémère garde la priorité (compat) LPPairSandbox.cpp:3396-3399, 3907-3921
SkyCubemap * (opt.) Sandbox.Sky /Game/Heavy/New2/Buildings/Mats/urban_street_03_1k.urban_street_03_1k LoadObject<UTextureCube> pour SkyLight->SetCubemap (SkyLight SLS_SpecifiedCubemap) LPPairSandbox.cpp:1001
SkyIntensity (opt.) Sandbox.Sky 0.6 SkyLight->SetIntensity(0.6f) LPPairSandbox.cpp:1000
MeasureOutputRoot Sandbox.Output Measurement Sous-dossier de ProjectSavedDir() pour shots, tour, vignettes, planches, retarget_pose_*.txt (les sous-noms restent en dur) LPPairSandbox.cpp:1687, 1862, 1873, 1885, 1930-1931

Notes

  • PersonBP n'a qu'une clé pour deux sites d'appel (844 et 1089) : en S2 un seul accesseur partagé.
  • DazAnimRoot : les deux idles (DazIdleFemale/Male) sont des clés distinctes car leurs noms ne suivent pas le motif %s%s.%s%s (casse différente Idle_F_Daz / idle_Daz) ; les valeurs par défaut sont donc les littéraux exacts, y compris la casse.
  • Walk_Loop, Idle_Loop, A_TPose, préfixes B_/M_ : conventions de nommage Quaternius/retarget, non exposées (hors contrat) ; seul leur dossier (QuaterniusUALRoot) l'est.
  • Les préfixes disque vs chemin UE (Quaternius/UAL vs /Game/Quaternius/UAL) sont deux clés séparées pour ne pas dériver un chemin de l'autre (l'actuel code les écrit indépendamment).
  • Packaging : un Config/LPSandbox.ini custom n'est staged que s'il est listé (UFS/DirectoriesToAlwaysStageAsUFS ou +DirectoriesToAlwaysStageAsNonUFS) ; le sandbox est un outil éditeur/dev, donc à traiter en S2 uniquement si le sandbox doit tourner packagé.

3. Contenu proposé de Config/LPSandbox.ini

Les valeurs ci-dessous sont identiques aux littéraux actuels : charger ce fichier ne doit rien changer au comportement.

; Config/LPSandbox.ini
; Contrat S1-T1 — chemins et options du bac a sable LPPairSandbox.
; Toute cle absente => valeur par defaut du code (identique a celle-ci).
; Chemins "/Game/..." : format LoadObject (/Package/Nom.Nom ou /Package/BP.BP_C).
; Chemins relatifs (sans "/") : relatifs a Content/ sauf [Sandbox.Output] (relatif a Saved/).

[Sandbox.Mode]
; Mode initial du menu : Pair | Interaction | Mesure
; (Saved/sandbox_mode.txt, s'il existe, reste prioritaire et est consomme.)
Mode=Pair

[Sandbox.Assets]
PersonBP=/Game/BPs/Person.Person_C
BridgetMesh=/Game/Heavy/Daz/Bridget/bridget_gp.bridget_gp
MichaelMesh=/Game/Heavy/Daz/Michael/michael.michael
QuaterniusMannequinMesh=/Game/Quaternius/UAL/UAL1_Standard.UAL1_Standard
DazIdleFemale=/Game/Heavy/Daz/Anims/Idle_F_Daz.Idle_F_Daz
DazIdleMale=/Game/Heavy/Daz/Anims/idle_Daz.idle_Daz
FurnitureWallMaterial=/Game/Heavy/New2/Furniture/Materials/FntWall.FntWall

[Sandbox.Roots]
; Racines de packages UE (sans nom d'asset final)
FurnitureRoot=/Game/Heavy/New2/Furniture
DazAnimRoot=/Game/Heavy/Daz/Anims
QuaterniusRoot=/Game/Quaternius
QuaterniusUALRoot=/Game/Quaternius/UAL

[Sandbox.Content]
; Chemins disque, relatifs a Content/
ModuleRoot=Modules/vin_Base
WorldFile=Modules/vin_Base/World/work___vin01.lpworld
ChatAction=Modules/vin_Base/Interactions/chat.lpaction
QuaterniusUALDisk=Quaternius/UAL

[Sandbox.Sky]
; Optionnel : cubemap du SkyLight du sandbox
SkyCubemap=/Game/Heavy/New2/Buildings/Mats/urban_street_03_1k.urban_street_03_1k
SkyIntensity=0.6

[Sandbox.Output]
; Relatif a Saved/
MeasureOutputRoot=Measurement

4. Critères d'acceptation pour S2 (implémentation, hors de cette fiche)

  1. Sans Config/LPSandbox.ini, comportement strictement identique à aujourd'hui (defaults = littéraux de la colonne « default »).
  2. Avec le fichier d'exemple ci-dessus, comportement strictement identique.
  3. Un seul point de lecture (struct de config chargée une fois, p. ex. FLPSandboxConfig::Get()), plus de TEXT("/Game/...") en dur dans LPPairSandbox.cpp/LPAnimRedirect.cpp pour les clés ci-dessus.
  4. Clé présente mais asset introuvable : même journal d'erreur qu'aujourd'hui (LogLifePlay), sans repli silencieux sur une autre valeur.