LifePlay-Revival/Docs/Migration/etat/ST/STC/STC-SPEC.md
edujiro5972 8084622450 LifePlay UE 5.8 : état de développement au 2026-10-19
Tickets : REP1-T4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:57:42 +02:00

11 KiB

Fiche STC-T2 — Niveau N3 — Modèle prévu orchestrateur (Opus 5.5) | utilisé claude-opus-5-5 — Agent orchestrateur — Skills lp-lot, lp-mcp, sk-protocol

STC-SPEC : slider caméra adossé à GameUserSettings.ini, durée des scènes protégée (2026-10-10)

Copie D:\Game\LifePlay-master 5.8 (branche ue5.8, HEAD 20620f6). Entrées : STC-TACHES.md (décisions utilisateur), STC-T0-CART.md (avec son correctif), diagnostic side-session-notes\...\STC-reponse-fable.md § 1-4 et 6 (conception approuvée « 4 approuvé »), STC-T1 / T1b acceptées.

0. Décisions qui cadrent la SPEC (utilisateur)

# Décision Conséquence
D1 Slider caméra dans Settings, valeur dans sa propre entrée GameUserSettings.ini, lue au démarrage, écrite seulement quand le joueur bouge le slider § 2, § 3.1, § 4
D2 Durée des scènes : SpinBox gardée, protégée (ne change que sur action réelle du joueur) § 3.2
D3 Slider de 1 à 7, pas de 1 (7 positions), défaut 3 § 2, § 3.1
D4 L'ini fait foi ; GameSettings.sav garde son champ CameraSpeed, recopie à jour § 2.3, § 4
D5 Les 12 autres SpinBox : lot séparé (carte proposée « Lot séparé : protéger les 12 autres SpinBox ») hors périmètre

1. Causes traitées (rappel, établi)

(a) liaison de propriété Value ← GI.X (designer) ; (b) écriture GI sur OnValueChanged, émis aussi par SynchronizeProperties / SetValue ; (c) MaxValue = 0 sur caméra et durée → toute valeur commise ramenée à 0.2 (contre-épreuve T1b). Les trois sont levées pour les deux réglages, par remplacement des widgets : aucun outil MCP ne retire une liaison de propriété (UMGToolSet : pas d'outil de liaison) ; un widget neuf, d'un autre nom, n'a pas de liaison.

2. C++ (module LifePlay, IMPL par lp-impl, BUILD par lp-builder, éditeur fermé)

Fichiers neufs Source/LifePlay/LPUserSettings.h et .cpp (structure plate du module, style de LPModSettingsLibrary).

2.1 Classe de configuration

UCLASS(config = GameUserSettings)
class LIFEPLAY_API ULPUserSettings : public UObject
{
	GENERATED_BODY()
public:
	UPROPERTY(config) float CameraSpeed = 3.f;
	UPROPERTY(config) bool bCameraSpeedSet = false;   // faux tant que l'entrée n'a jamais été écrite
};

Section [/Script/LifePlay.LPUserSettings] de GameUserSettings.ini (PIE : Saved/Config/WindowsEditor/, archive : Saved/Config/Windows/). Accès par GetMutableDefault<ULPUserSettings>(), écriture par SaveConfig() (fichier GGameUserSettingsIni). Pas de remplacement de UGameUserSettings (aucune config Engine touchée).

2.2 Bibliothèque Blueprint ULPUserSettingsLibrary : UBlueprintFunctionLibrary (catégorie LifePlay|Settings)

Fonction Rôle
static float ClampCameraSpeed(float V) (Pure) FMath::Clamp(FMath::RoundToFloat(V), 1, 7)
static void ApplyCameraSpeedAtStartup(UObject* GameInstance) si bCameraSpeedSet : GI.CameraSpeed = ClampCameraSpeed(ini) ; sinon (premier lancement) : lit GI.CameraSpeed (valeur issue de GameSettings.sav par LoadSettings), la borne, l'écrit dans GI et dans l'ini (bCameraSpeedSet = true, SaveConfig) ; journal LogLifePlay Display une ligne
static void SetCameraSpeed(UObject* GameInstance, float V) V = ClampCameraSpeed(V) ; écrit GI.CameraSpeed ; si V diffère de l'ini ou !bCameraSpeedSet : met l'ini à jour et SaveConfig()
static float GetCameraSpeed() (Pure) valeur de l'ini bornée (3 si jamais écrite)
Écriture de GI.CameraSpeed par réflexion, comme LPSettingsUi::WireMainMenuGI : FindPropertyByName("CameraSpeed"),
FDoubleProperty (réel Blueprint 5.x) ou FFloatProperty ; absence de la propriété → avertissement au journal, rien d'autre.

2.3 Style du slider (LPSettingsSubsystem.cpp, HardenSettingsControls)

Ajouter CollectSliders et appliquer aux USlider de SettingsScrollBox un style lisible sur fond clair, cohérent avec les SpinBox (barre sombre 0.06, poignée 0.2/0.45/0.9 comme ActiveFillBrush). Aucune écriture de valeur (seulement SetWidgetStyle, SetSliderBarColor, SetSliderHandleColor). Libellé de la ligne inchangé (contient « camera » : classement par onglet de TabFor).

2.4 Compilation

Tools/Build.ps1 (lp-build), éditeur fermé ; critère : code 0, module LifePlay recompilé, 0 avertissement nouveau.

3. Blueprint Content/UI/MainMenu.uasset (orchestrateur, MCP, après la BUILD, éditeur rouvert)

3.1 Vitesse caméra

  1. Relever par UMGToolSet.GetWidgets la ligne de SpinBoxCameraSpeed (parent HorizontalBox_4, créneau 1) : taille, alignement, remplissage du créneau.
  2. ReplaceWidgetWithTemplate (ou AddWidget au même indice puis RemoveWidget) : USlider nommé SliderCameraSpeed, variable, MinValue 1, MaxValue 7, StepSize 1, MouseUsesStep true, Value 3 (conception), même créneau. Ajouter à sa droite un TextBlock TextCameraSpeedValue (variable) qui affiche l'entier courant.
  3. Supprimer l'événement BndEvt__SpinBoxCameraSpeed_…_207 et ses nœuds (IsValid, Set CameraSpeed, Get GI).
  4. OnValueChanged(SliderCameraSpeed) (émis seulement par l'interaction, SSlider.cpp:415-428, SetValue n'émet rien :532) → ULPUserSettingsLibrary::SetCameraSpeed(GetGameInstance(), Value) → TextCameraSpeedValue.SetText(Round(Value)).

3.2 Durée des scènes

  1. Remplacer SpinBoxSexDurationMultiplier par une SpinBox neuve SpinBoxSexDuration au même créneau, propriétés recopiées (style, police, largeur, décimales) sauf : MinValue 0.2, MaxValue 10, MinSliderValue 0.2, MaxSliderValue 10, Value 2 (conception = défaut GI). Aucune liaison.
  2. Supprimer l'événement BndEvt__SpinBoxSexDurationMultiplier_…_61 et ses nœuds.
  3. OnValueCommitted(SpinBoxSexDuration) → IsValid(GI) → Set GI.SexDurationMult = Value. Aucun gestionnaire sur OnValueChanged (OnValueCommitted : saisie, flèches, fin de glisser ; jamais SetValue sans commit ni SynchronizeProperties, SSpinBox.cpp:1053-1058, 367).

3.3 Construct (après Set GI, avant UpdateDonors)

SliderCameraSpeed.SetValue(GI.CameraSpeed) → TextCameraSpeedValue.SetText(Round(GI.CameraSpeed)) → SpinBoxSexDuration.SetValue(GI.SexDurationMult) (SetValue UMG → OnValueChanged seulement, sans gestionnaire).

3.4 Contrôles de l'asset

CompileWidgetBlueprint sans erreur ni avertissement ; plus aucune entrée Bindings pour SpinBoxCameraSpeed / SpinBoxSexDurationMultiplier (relecture binaire du .uasset comme au diagnostic § 1.1, ou journal de compilation) ; find_nodes : 0 nœud référant aux deux anciens widgets.

4. Blueprint Content/BPs/GI.uasset

Après l'appel de démarrage LoadSettings (K2Node_CallFunction_1007, dump GI l. 17760, LoadLastSave = true), insérer ULPUserSettingsLibrary::ApplyCameraSpeedAtStartup(self) entre 1007.then et K2Node_CallFunction_186.execute. Avant : find_nodes « LoadSettings » sur tous les graphes de GI (377) ; tout autre appel de LoadSettings reçoit le même nœud à sa suite. SaveSettings inchangé : il recopie GI.CameraSpeed (égal à l'ini) dans GameSettings.sav (D4).

5. Ordre, sécurité, traces

  1. Snapshot complémentaire -Lot STC : Source\LifePlay\LPUserSettings.h, .cpp (absents, Existed=False), Source\LifePlay\LPSettingsSubsystem.cpp (MainMenu, GI, sav, ini déjà au manifeste).
  2. IMPL C++ (lp-impl) → BUILD (lp-builder, éditeur fermé : l'orchestrateur ferme son éditeur avant) → réouverture.
  3. MCP MainMenu (§ 3) puis GI (§ 4), relecture get_node_infos, compilation de chaque Blueprint.
  4. CompileAllBlueprints (référence STM-T4c : 418 / 418, 0 erreur, 0 avertissement).
  5. VAL (lp-validator, agent distinct) § 6 ; puis archive Development et preuve en jeu utilisateur.
  6. CHG (un par modification, à partir de CHG-296) : C++ (2.1-2.2), style (2.3), MainMenu (3), GI (4). Commit selon lp-lot (tickets au gardien du dépôt si la règle en vigueur l'exige), sans push. Fin de gel annoncée.

6. Critères de VAL et de preuve

# Contrôle Attendu
V1 BUILD code 0, 0 avertissement nouveau
V2 CompileAllBlueprints 418 / 418, 0 erreur, 0 avertissement
V3 LPTestStringCompat 3120 / 0 / 60
V4 PIE M0-M6 (diagnostic § 3.2) 0 écart sur les 14 variables de GI
V5 PIE : slider sur 5 GI.CameraSpeed = 5, ini CameraSpeed=5.000000, bCameraSpeedSet=True ; menu fermé puis rouvert : slider 5, texte « 5 », GI 5
V6 PIE relancé GI.CameraSpeed = 5 (lu dans l'ini)
V7 PIE : 3 tapé + Entrée dans durée ; puis glisser GI.SexDurationMult = 3, puis valeur du glisser ; menu fermé / rouvert : inchangé
V8 Ini sans section LPUserSettings (copie de travail) au démarrage migration : GI et ini = Clamp(Round(sav)) (3), une ligne au journal
V9 Fichiers GameUserSettings.ini : seule la section ajoutée diffère ; GameSettings.sav réécrit seulement par une sauvegarde de partie
J1 Preuve en jeu (archive Development, utilisateur) slider fonctionnel et persistant entre deux lancements ; valeur intacte après ouverture / fermeture du menu ; durée des scènes inchangée sauf action du joueur

6b. Relevés complémentaires (MCP, lecture seule, 2026-10-10, établi)

  • Lignes du menu (UMGToolSet.GetWidgets, 285 widgets) : CanvasPanel_4 > HorizontalBox_4 > [TextBlock_11, SpinBoxCameraSpeed] (créneau HorizontalBoxSlot_1) ; CanvasPanel_1 > HorizontalBox_0 > [Text, SpinBoxSexDurationMultiplier] (créneau HorizontalBoxSlot_1).
  • GI : 377 graphes ; find_nodes « LoadSettings » : 2 nœuds, tous deux dans EventGraph (K2Node_CustomEvent_3270, définition ; K2Node_CallFunction_1007, seul appel : CallFunction_80.then → 1007 → CallFunction_186, LoadLastSave = true).
  • Chaîne LoadSettings (dump GI) : SetActive → ExecuteConsoleCommand → EnableDynamicResolution → DoesSaveGameExist → LoadGameFromSlot → Cast → affectations (ModEnableds, DifficultyPlayerInput, SceneFrequency, MarkerSize…) : aucun nœud latent sur le chemin relu (synchrone, estimé pour les branches non relues).

7. Risques

  • Bindings orphelins après remplacement : le compilateur UMG ignore une liaison sans widget ; si un avertissement apparaît (V2), retirer l'entrée (réécriture par le designer) avant VAL — à mesurer en 3.4.
  • LoadSettings asynchrone ou appelé plus tard que prévu : vérifié en § 4 (LoadGameFromSlot est synchrone).
  • Ini en archive installée (-UserDir, piège U8 « Shipping installé ») : V9 relu dans l'archive à la preuve en jeu.