# S1-T2 — Implémentation du lecteur `Config/LPSandbox.ini` Rôle : A-IMPL-L. Référence : `S1-SPEC.md`. Pas de split du monolith ; `ShowCouple` non modifié. Non compilé / non committé (voir « Reste à faire »). ## Fichiers | Fichier | Statut | |---|---| | `Source/LifePlay/LPSandboxConfig.h` | créé | | `Source/LifePlay/LPSandboxConfig.cpp` | créé | | `Config/LPSandbox.ini` | créé (contenu exemple du SPEC, valeurs = littéraux historiques) | | `Source/LifePlay/LPPairSandbox.cpp` | modifié (`#include "LPSandboxConfig.h"` + remplacements ci-dessous) | | `Source/LifePlay/LPAnimRedirect.cpp` | modifié (`ClipPath`) | ## Symboles créés - `struct LIFEPLAY_API FLPSandboxConfig` : champs `Mode, PersonBP, BridgetMesh, MichaelMesh, QuaterniusMannequinMesh, DazIdleFemale, DazIdleMale, FurnitureWallMaterial, FurnitureRoot, DazAnimRoot, QuaterniusRoot, QuaterniusUALRoot, ModuleRoot, WorldFile, ChatAction, QuaterniusUALDisk, SkyCubemap, SkyIntensity (float), MeasureOutputRoot`. Initialiseurs de membres = littéraux historiques. - `static const FLPSandboxConfig& FLPSandboxConfig::Get()` : singleton (static locale thread-safe), chargé une fois. - `void FLPSandboxConfig::Load()` (privé) : `FPaths::FileExists` puis `FConfigFile::Read(ProjectConfigDir()/LPSandbox.ini)` ; lecture directe non hiérarchique. Fichier absent, clé absente ou valeur vide => default conservé. `SkyIntensity` : ignoré si non numérique. - Helper anonyme `SandboxCfgReadString` (`LPSandboxConfig.cpp`). ## Symboles touchés dans `LPPairSandbox.cpp` | Fonction | Littéral remplacé | Clé | |---|---|---| | namespace `PairSandbox` (catalogue d'actions, scan `*.lpaction`, ~l.622) | `"Modules/vin_Base"` | `ModuleRoot` | | `ALPPairSandboxStage::Build` | `.../World/work___vin01.lpworld` | `WorldFile` | | `ALPPairSandboxStage::Build` | `/Game/BPs/Person.Person_C` | `PersonBP` | | `ALPPairSandboxStage::Build` | `/Game/Heavy/New2/Furniture/%s.%s` | `FurnitureRoot` (`"%s/%s.%s"`) | | `ALPPairSandboxStage::Build` | `.../Materials/FntWall.FntWall` | `FurnitureWallMaterial` | | `ALPPairSandboxStage::Build` (SkyLight) | `SetIntensity(0.6f)` | `SkyIntensity` | | `ALPPairSandboxStage::Build` (SkyLight) | `urban_street_03_1k` | `SkyCubemap` | | `ALPPairSandboxStage::LoadChat` | `.../Interactions/chat.lpaction` | `ChatAction` | | `ALPPairSandboxStage::PlayIdle` | `Idle_F_Daz` / `idle_Daz` (`const TCHAR*` -> `const FString&`) | `DazIdleFemale` / `DazIdleMale` | | `ALPPairSandboxStage::ConfigureCapsule` | `/Game/BPs/Person.Person_C` | `PersonBP` | | `ALPPairSandboxStage::BeginMeasure` (appels `Place` Mannequin/Bridget) | `UAL1_Standard`, `bridget_gp` | `QuaterniusMannequinMesh`, `BridgetMesh` | | `PairSandboxAuto::ShotDir`, `PairSandboxTour::TourDir/VignetteDir/PlancheDir` | `TEXT("Measurement")` | `MeasureOutputRoot` | | `ALPPairSandboxStage::ShowFormulaDefault` (`WriteRetargetPose`) | `TEXT("Measurement")` | `MeasureOutputRoot` | | `ALPPairSandboxStage::GetMeasureClips` (scan disque clips `B_`) | `Quaternius`,`UAL` | `QuaterniusUALDisk` | | `ALPPairSandboxStage::FitCoupleBox` (lambda `Accumulate`) et `ALPPairSandboxCharacter::RefreshPose` | `/Game/Heavy/Daz/Anims/%s%s.%s%s` | `DazAnimRoot` (`"%s/%s%s.%s%s"`) | | `ALPPairSandboxCharacter::LoadQuaternius` | `/Game/Quaternius`, `/Game/Quaternius/UAL` | `QuaterniusRoot`, `QuaterniusUALRoot` | | `ALPPairSandboxCharacter::ApplyBody` | `bridget_gp`, `michael` | `BridgetMesh`, `MichaelMesh` | | `ALPPairSandboxCharacter::ShowAnimMenu` (fin, après lecture de `sandbox_mode.txt`) | nouveau : branche `else` si `Saved/sandbox_mode.txt` absent | `Mode` | `Mode` : le `.txt` éphémère garde la priorité (comportement inchangé s'il existe). S'il est absent et que `Mode != Pair`, `SelectMode` est appelé sur le choix correspondant (`Pair` = comportement actuel, aucun appel). ## Symbole touché dans `LPAnimRedirect.cpp` - `LPAnimRedirect::ClipPath` : `"/Game/Quaternius/UAL/%s.%s"` -> `"%s/%s.%s"` avec `QuaterniusUALRoot`. ## Defaults Tous les defaults (champs de `FLPSandboxConfig` et `Config/LPSandbox.ini`) sont identiques caractère par caractère aux littéraux remplacés ; sans ini ou avec l'ini exemple, chemins et valeurs résultants sont identiques (les `FString::Printf` reconstituent exactement les mêmes chaînes). Les logs d'erreur (`LogLifePlay`) sont inchangés. ## Hors périmètre / non touchés `ShowCouple`, `Saved/sandbox_mode.txt`/`sandbox_tour.txt`, `LPKeyboard.ini`, littéraux `/Engine/...`, noms de clips/préfixes, liste `Names[]`. ## Reste à faire - Compilation UBT non exécutée dans cette fiche (nouveaux fichiers pris par le glob du module `LifePlay`). - Packaging (staging de `Config/LPSandbox.ini`) : voir note du SPEC, non traité.