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
- Relever par
UMGToolSet.GetWidgetsla ligne deSpinBoxCameraSpeed(parentHorizontalBox_4, créneau 1) : taille, alignement, remplissage du créneau. ReplaceWidgetWithTemplate(ouAddWidgetau même indice puisRemoveWidget) :USlidernomméSliderCameraSpeed, variable,MinValue 1,MaxValue 7,StepSize 1,MouseUsesStep true,Value 3(conception), même créneau. Ajouter à sa droite unTextBlockTextCameraSpeedValue(variable) qui affiche l'entier courant.- Supprimer l'événement
BndEvt__SpinBoxCameraSpeed_…_207et ses nœuds (IsValid,Set CameraSpeed,Get GI). OnValueChanged(SliderCameraSpeed)(émis seulement par l'interaction,SSlider.cpp:415-428,SetValuen'émet rien:532) →ULPUserSettingsLibrary::SetCameraSpeed(GetGameInstance(), Value)→TextCameraSpeedValue.SetText(Round(Value)).
3.2 Durée des scènes
- Remplacer
SpinBoxSexDurationMultiplierpar une SpinBox neuveSpinBoxSexDurationau 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. - Supprimer l'événement
BndEvt__SpinBoxSexDurationMultiplier_…_61et ses nœuds. OnValueCommitted(SpinBoxSexDuration)→IsValid(GI)→Set GI.SexDurationMult = Value. Aucun gestionnaire surOnValueChanged(OnValueCommitted: saisie, flèches, fin de glisser ; jamaisSetValuesans commit niSynchronizeProperties,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
- 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). - IMPL C++ (lp-impl) → BUILD (lp-builder, éditeur fermé : l'orchestrateur ferme son éditeur avant) → réouverture.
- MCP MainMenu (§ 3) puis GI (§ 4), relecture
get_node_infos, compilation de chaque Blueprint. CompileAllBlueprints(référence STM-T4c : 418 / 418, 0 erreur, 0 avertissement).- VAL (lp-validator, agent distinct) § 6 ; puis archive Development et preuve en jeu utilisateur.
- 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éneauHorizontalBoxSlot_1) ;CanvasPanel_1 > HorizontalBox_0 > [Text, SpinBoxSexDurationMultiplier](créneauHorizontalBoxSlot_1). - GI : 377 graphes ;
find_nodes« LoadSettings » : 2 nœuds, tous deux dansEventGraph(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.
LoadSettingsasynchrone ou appelé plus tard que prévu : vérifié en § 4 (LoadGameFromSlotest synchrone).- Ini en archive installée (
-UserDir, piège U8 « Shipping installé ») : V9 relu dans l'archive à la preuve en jeu.