LifePlay-Revival/Docs/Migration/etat/ST/STC/STC-T3-IMPL.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

406 lines
23 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.

Fiche STC-T3 — Niveau N3 — Modèle prévu lp-impl | utilisé claude-opus-5-5 — Agent lp-impl — Skills lp-ue-compat, ue-cpp-build, lp-build, sk-protocol
# STC-T3-IMPL : C++ ULPUserSettings (GameUserSettings.ini) et style des sliders de Settings (2026-10-10)
Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8`, HEAD `20620f6`. SPEC : `STC-SPEC.md` § 0-2, 7 (lue en entier).
Non compilé (fiche : BUILD par lp-builder, éditeur ouvert). Aucun asset, config, Build.cs ni git touché.
## 1. Fichiers modifiés (chemins, lignes)
| Fichier | État | Lignes (`wc -l`) | Fins de ligne (`git ls-files --eol` / `-o --eol`) | MD5 |
|---|---|---|---|---|
| `D:\Game\LifePlay-master 5.8\Source\LifePlay\LPUserSettings.h` | neuf | 59 | `w/lf` (comme le modèle `LPModSettingsLibrary.h/.cpp`, `i/lf w/lf`) | `7d67c3f755930bcf1c0fd4c65aced897` |
| `D:\Game\LifePlay-master 5.8\Source\LifePlay\LPUserSettings.cpp` | neuf | 115 | `w/lf` | `ba74f9e3e6dbaa4a02579be89ea2e037` |
| `D:\Game\LifePlay-master 5.8\Source\LifePlay\LPSettingsSubsystem.cpp` | modifié, +52 / -0 (`git diff --stat`) | 835 → 887 | `i/crlf w/crlf` (inchangé, CRLF gardé par Edit) | `2fe96f77…` → `ede28e6d9aeff9a27f1adb988c03ae36` |
- `LPSettingsSubsystem.h` non modifié (MD5 `0f98c055…` = instantané). `LifePlay.Build.cs` non modifié : `Slate`, `SlateCore`,
`UMG` déjà en privé (`LifePlay.Build.cs:38`), `CoreUObject`/`Engine` en public (`:17`) ; aucune dépendance manquante (estimé :
toutes les API utilisées sont dans ces modules).
- Dossier `Source/LifePlay` : 18 fichiers CRLF, 35 LF (`git ls-files --eol -- Source/LifePlay`) ; les neufs suivent leur modèle (LF).
- Aucun caractère hors ASCII dans les deux fichiers neufs (Grep `[^\x00-\x7F]` : 0 résultat).
- Emplacements dans `LPSettingsSubsystem.cpp` (après modification) : include `Components/Slider.h` l. 19 ; `CollectSliders`
l. 281-303 ; couleurs l. 346-351 ; collecte l. 355 et 360 ; boucle de style l. 403-420 (`SetWidgetStyle` l. 415,
`SetSliderBarColor` l. 417, `SetSliderHandleColor` l. 418, Grep relu).
## 2. Écarts à la SPEC (obligatoire)
- E1 (style, § 2.3) : les couleurs sont portées par la **teinte des pinceaux** du style (`NormalBarImage` 0.06/0.06/0.06/0.95,
`HoveredBarImage` 0.12/0.12/0.12/0.98, `NormalThumbImage` 0.2/0.45/0.9/1, `HoveredThumbImage` 0.3/0.55/1/1) et
`SetSliderBarColor` / `SetSliderHandleColor` reçoivent **blanc** (multiplicateur neutre). Motif : `SSlider::OnPaint` dessine
teinte du pinceau × couleur (`SSlider.cpp:125, 137`) ; mettre les couleurs dans les pinceaux garde un état survolé distinct
(`GetBarImage`/`GetThumbImage`, `SSlider.cpp:483-513`). Les teintes de survol (0.12 et 0.3/0.55/1) ne sont pas dans la SPEC
(reprises de `SpinBgHover` et `CheckedHover`). Base = style propre du slider (`GetWidgetStyle`), pas `FCoreStyle` comme les
SpinBox : pinceaux, `BarThickness` (2 px par défaut) et taille de poignée (8×14) gardés. Seuls appels d'écriture : les trois
permis par la SPEC ; aucun `SetValue`, ni `SetIsEnabled`/`SetRenderOpacity`.
- E2 (portée du style, § 2.3) : appliqué, comme écrit, à **tous** les `USlider` de `SettingsScrollBox` : donc aussi aux 5 lignes
`LPColor*` (`LPColorGradeSubsystem.cpp:298-302`), aux sliders `LPVideo*` (`LPVideoQualitySubsystem.cpp:392`) et à tout slider
Blueprint de la liste. Effet visible au-delà du slider caméra : à confirmer par l'orchestrateur (une restriction au nom
`SliderCameraSpeed` serait un changement d'une ligne).
- E3 (propriété GI absente) : interprétation de « avertissement, rien d'autre ». `ApplyCameraSpeedAtStartup` : avertissement
puis retour, **ini non écrit** dans les deux branches (la reprise du premier lancement sera retentée). `SetCameraSpeed` :
avertissement pour GI, **ini quand même mis à jour** (l'ini fait foi, D4). GameInstance nul = même traitement.
- E4 : `SetCameraSpeed` écrit une ligne `Display` à chaque écriture de l'ini (`Camera : vitesse N enregistree dans
GameUserSettings.ini`) ; non demandé, utile à V5 ; au plus une ligne par cran réellement changé.
- E5 : formule de la SPEC gardée telle quelle, sans garde NaN : `FMath::Clamp` = `Max(Min(X, Max), Min)`
(`UnrealMathUtility.h:592-595`), donc NaN → 7 (estimé par lecture du code, non essayé).
- E6 : broche `V` gardée (nom de la SPEC) pour `ClampCameraSpeed` et `SetCameraSpeed`.
- Aucun autre écart : signatures, catégorie `LifePlay|Settings`, `UCLASS(config = GameUserSettings)`, valeurs par défaut (3, faux),
`SaveConfig()` seulement si valeur changée ou `bCameraSpeedSet` faux, lecture/écriture GI par réflexion `FDoubleProperty`
puis `FFloatProperty`.
## 3. Instantané (lot, manifeste)
- Lot `STC`, manifeste `D:\Game\LifePlay_Backup_5.5\STC\manifest.csv` (fait par l'orchestrateur, 2026-10-10T09:11:26) :
`LPUserSettings.h` et `.cpp` `Existed=False` ; `LPSettingsSubsystem.cpp` MD5 `2FE96F776A0F3DFDA803F6E0EB1BC73B` et `.h`
`0F98C05568AE789C5C0B78F6EC580503`, identiques aux fichiers avant modification (`md5sum`, relu avant la première écriture).
- Retour arrière (proposé, non fait) : `Tools\Restore.ps1 -Lot STC` (déplace les deux neufs, restaure le `.cpp`).
## 4. Ce qui n'a pas été fait
- Compilation (BUILD par lp-builder, éditeur fermé) ; aucun build 5.5 de contrôle (le lot vit dans la copie 5.8).
- Blueprints `MainMenu` (§ 3) et `GI` (§ 4), CHG, ini, `GameSettings.sav` : hors fiche.
- Aucun commit, aucun `git add`, aucune écriture dans `Docs/` de la copie 5.8, aucun script.
## 5. Points à confirmer en VAL
- BUILD 5.8 : code 0 ; `LPUserSettings.gen.cpp` produit par UHT ; `LPUserSettings.cpp` et `LPSettingsSubsystem.cpp` compilés ; 0 avertissement nouveau (règles V7 : ombrage, code inatteignable).
- Unity build : espace de noms `LPUserSettingsGi` (nommé, unique : Grep `LPUserSettings` sur Source, Plugins et addon 5.8 avant écriture = 0) sans C2374.
- Palette Blueprint : 4 nœuds sous `LifePlay|Settings` avec les broches de la table « Signatures » (Constats).
- V8 : journal `LogLifePlay` `Display` « Camera : vitesse N reprise de GI (GameSettings.sav : X), ecrite dans GameUserSettings.ini (premier lancement) » et section `[/Script/LifePlay.LPUserSettings]` avec `CameraSpeed=…` et `bCameraSpeedSet=True`.
- V8 (risque) : valeur de `CameraSpeed` dans `GameSettings.sav` avant migration ; si elle vaut 0.2 (cause (c)), la reprise donne 1, pas 3 (`Round(0.2)=0` puis borne 1) ; attendu SPEC V8 = 3.
- V6 : au relancement, ligne « Camera : vitesse 5 lue dans GameUserSettings.ini (ini 5.00), recopiee dans GI (avant X) » et `GI.CameraSpeed = 5`.
- V5 : une ligne « enregistree dans GameUserSettings.ini » par cran changé, aucune quand la valeur ne change pas ; fichier écrit sur disque (`SaveConfig` → `Flush`, `Obj.cpp:3942-3944`).
- V9 : seule la section `LPUserSettings` ajoutée dans `GameUserSettings.ini`.
- Style (E1, E2) : slider caméra lisible sur fond clair (barre 2 px, poignée 8×14 inchangées) ; aspect des sliders `LPColor*` / `LPVideo*` / Blueprint acceptable ; aucune valeur de slider modifiée à l'ouverture du menu.
- Cases et SpinBox : rendu inchangé (aucune ligne de leur traitement modifiée, diff relu).
## 6. Fichiers à commiter
Dépôt jeu `D:\Game\LifePlay-master 5.8`, branche `ue5.8` :
A Source/LifePlay/LPUserSettings.h
A Source/LifePlay/LPUserSettings.cpp
M Source/LifePlay/LPSettingsSubsystem.cpp
Tours : 56 / 60
## Constats
### Signatures telles qu'un Blueprint les verra (estimé : affichage par `FName::NameToDisplayString`, à confirmer en VAL)
Cible : `LPUser Settings Library` (classe `ULPUserSettingsLibrary`, statiques, aucune broche Target). Catégorie `LifePlay|Settings`.
| Nœud (titre) | C++ | Type | Broches d'entrée (nom interne → affiché) | Broches de sortie |
|---|---|---|---|---|
| Clamp Camera Speed | `static float ClampCameraSpeed(float V)` | `BlueprintPure` | `V` → « V » (Float simple précision) | `ReturnValue` → « Return Value » (Float) |
| Apply Camera Speed At Startup | `static void ApplyCameraSpeedAtStartup(UObject* GameInstance)` | `BlueprintCallable` | `execute` ; `GameInstance` → « Game Instance » (Object Reference) | `then` |
| Set Camera Speed | `static void SetCameraSpeed(UObject* GameInstance, float V)` | `BlueprintCallable` | `execute` ; `GameInstance` → « Game Instance » ; `V` → « V » (Float) | `then` |
| Get Camera Speed | `static float GetCameraSpeed()` | `BlueprintPure` | — | `ReturnValue` → « Return Value » (Float) |
Pas de `DefaultToSelf` : la broche `GameInstance` doit être reliée (`self` dans GI, `Get Game Instance` dans MainMenu).
Classe de configuration : `ULPUserSettings` (`UCLASS(config = GameUserSettings)`, `UPROPERTY(config) float CameraSpeed = 3.f`,
`UPROPERTY(config) bool bCameraSpeedSet = false`), non visible des Blueprints (pas de spécificateur Blueprint, conforme SPEC 2.1).
### Choix faits
- Accès à l'ini : `GetMutableDefault<ULPUserSettings>()` (objet par défaut chargé de l'ini à sa création), écriture
`SaveConfig()` sans argument : fichier = nom de config de la classe (`Obj.cpp:3697`, `GetConfigFilename` `Obj.cpp:2332-2338`,
`UClass::GetConfigName` `Class.cpp:7144-7149` : `GameUserSettings` est un nom de config connu), puis `Flush` sur disque
(`Obj.cpp:3942-3944`).
- Réflexion GI : `FindPropertyByName("CameraSpeed")`, `CastField<FDoubleProperty>` puis `CastField<FFloatProperty>`
(`UnrealType.h:2507, 2547` ; `CastField` const `Field.h:1133`) ; `Get/SetPropertyValue_InContainer` const (`UnrealType.h:1663, 1673`).
Tout autre type ou absence : `Warning` « pas de propriete reelle CameraSpeed dans <classe>, GI non touche ».
- `ApplyCameraSpeedAtStartup` : une ligne `Display` par appel réussi (source ini avec valeur ini et valeur GI d'avant, ou reprise
depuis GI avec valeur du sav) ; `SaveConfig` seulement dans la branche premier lancement.
- `SetCameraSpeed` : GI toujours écrit (valeur bornée) ; ini et `SaveConfig` seulement si `!bCameraSpeedSet || CameraSpeed != V`
(comparaison exacte : entiers 1-7 exacts en float).
- `GetCameraSpeed` : `bCameraSpeedSet ? ClampCameraSpeed(CameraSpeed) : 3`.
- Helpers dans l'espace de noms nommé `LPUserSettingsGi` (piège unity C2374, `lp-build` § 8) ; `FName` en `static` local (comme `LPModSettingsLibrary.cpp:13`).
- Compatibilité 5.5 (estimé, non compilé) : API du slider présentes en 5.5 (`UE_5.5/.../Components/Slider.h:147, 150, 184, 191`) ;
aucune garde de version nécessaire ; aucun correctif UE4 (`LPStringCompat`, `LPMeshCompat`, `LPNavigationHelpers`…) touché.
### API moteur 5.8 lues (établi)
- `UE_5.8/Engine/Source/Runtime/UMG/Public/Components/Slider.h:151` `GetWidgetStyle`, `:154` `SetWidgetStyle`, `:188`
`SetSliderBarColor(FLinearColor)`, `:195` `SetSliderHandleColor(FLinearColor)` ; accès direct aux membres déprécié 5.1 (`:51, 61, 66`).
- `UMG/Private/Components/Slider.cpp:210-217, 284-305` : ces setters ne touchent pas `Value` ; `:30` style d'exécution par défaut =
`FDefaultStyleCache::GetRuntime().GetSliderStyle()` (`SlateCore/Private/Styling/DefaultStyleCache.cpp:60` → `UMGCoreStyle.cpp:723-731` :
barre `FSlateColorBrush` blanche, poignée `Common/Button` 8×14, épaisseur 2).
- `SlateCore/Public/Styling/SlateTypes.h:1339-1386` : `FSliderStyle` (`NormalBarImage`, `HoveredBarImage`, `DisabledBarImage`,
`NormalThumbImage`, `HoveredThumbImage`, `DisabledThumbImage`, `BarThickness`).
- `Slate/Private/Widgets/Input/SSlider.cpp:119-138` (peinture : teinte × couleur × teinte du widget), `:483-513` (pinceau survolé).
- `CoreUObject/Public/UObject/Object.h:1283` `SaveConfig(uint64 RequiredPropertyFlags = CPF_Config, const TCHAR* Filename = nullptr, …)`.
- `Core/Public/GenericPlatform/GenericPlatformMath.h:332` `RoundToFloat(float)` ; `Core/Public/Math/UnrealMathUtility.h:592` `Clamp`.
Aucune API supposée par la SPEC absente en 5.8 (arrêt rubrique 7 non déclenché).
### Diff complet
`Source/LifePlay/LPSettingsSubsystem.cpp` (`git diff`, CR retirés à l'affichage) :
```diff
@@ -16,6 +16,7 @@
#include "Components/OverlaySlot.h"
#include "Components/ScrollBox.h"
#include "Components/SizeBox.h"
+#include "Components/Slider.h"
#include "Components/SpinBox.h"
#include "Components/TextBlock.h"
#include "Components/PanelWidget.h"
@@ -277,6 +278,30 @@ namespace LPSettingsUi
}
}
+ void CollectSliders(UWidget* Widget, TArray<USlider*>& Out)
+ {
+ if (!Widget)
+ {
+ return;
+ }
+ if (USlider* Slider = Cast<USlider>(Widget))
+ {
+ Out.Add(Slider);
+ return;
+ }
+ if (UUserWidget* User = Cast<UUserWidget>(Widget))
+ {
+ CollectSliders(User->GetRootWidget(), Out);
+ }
+ if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
+ {
+ for (int32 Index = 0; Index < Panel->GetChildrenCount(); ++Index)
+ {
+ CollectSliders(Panel->GetChildAt(Index), Out);
+ }
+ }
+ }
+
void TintBrush(FSlateBrush& Brush, const FLinearColor& Tint)
{
Brush.TintColor = FSlateColor(Tint);
@@ -318,12 +343,21 @@ namespace LPSettingsUi
TintBrush(SpinStyle.ActiveFillBrush, FLinearColor(0.2f, 0.45f, 0.9f, 0.85f));
SpinStyle.ForegroundColor = FSlateColor(FLinearColor(1.f, 1.f, 1.f, 1.f));
+ // Lot STC : sliders (vitesse de camera, lignes LPColor* et LPVideo*). Barre sombre comme le fond des spinboxes,
+ // poignee bleue comme leur remplissage. Style et couleurs seulement : aucune valeur ecrite (pas de SetValue).
+ const FLinearColor SliderBar(0.06f, 0.06f, 0.06f, 0.95f);
+ const FLinearColor SliderBarHover(0.12f, 0.12f, 0.12f, 0.98f);
+ const FLinearColor SliderHandle(0.2f, 0.45f, 0.9f, 1.f);
+ const FLinearColor SliderHandleHover(0.3f, 0.55f, 1.f, 1.f);
+
TArray<UCheckBox*> Boxes;
TArray<USpinBox*> Spins;
+ TArray<USlider*> Sliders;
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
{
CollectCheckBoxes(Scroll->GetChildAt(Index), Boxes);
CollectSpinBoxes(Scroll->GetChildAt(Index), Spins);
+ CollectSliders(Scroll->GetChildAt(Index), Sliders);
}
for (UCheckBox* Box : Boxes)
@@ -366,6 +400,24 @@ namespace LPSettingsUi
Spin->SetFont(Font);
}
+ for (USlider* Slider : Sliders)
+ {
+ if (!Slider)
+ {
+ continue;
+ }
+ // Style propre du slider (pinceaux et epaisseur gardes), seules les teintes changent.
+ FSliderStyle SliderStyle = Slider->GetWidgetStyle();
+ TintBrush(SliderStyle.NormalBarImage, SliderBar);
+ TintBrush(SliderStyle.HoveredBarImage, SliderBarHover);
+ TintBrush(SliderStyle.NormalThumbImage, SliderHandle);
+ TintBrush(SliderStyle.HoveredThumbImage, SliderHandleHover);
+ Slider->SetWidgetStyle(SliderStyle);
+ // SSlider::OnPaint multiplie la teinte du pinceau par ces couleurs : blanc = teintes ci-dessus telles quelles.
+ Slider->SetSliderBarColor(FLinearColor::White);
+ Slider->SetSliderHandleColor(FLinearColor::White);
+ }
+
if (UWidget* ShowFPS = [&]() -> UWidget*
{
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
```
`Source/LifePlay/LPUserSettings.h` (fichier neuf, 59 lignes, contenu intégral) :
```cpp
// Lot STC - vitesse de camera adossee a GameUserSettings.ini (STC-SPEC, partie 2).
//
// La valeur de reference de la vitesse de camera est la section [/Script/LifePlay.LPUserSettings] de
// GameUserSettings.ini (PIE : Saved/Config/WindowsEditor/, jeu : Saved/Config/Windows/). GI.CameraSpeed n'en est
// qu'une recopie : ApplyCameraSpeedAtStartup la remplit au demarrage (apres GI.LoadSettings), SetCameraSpeed la met a
// jour quand le joueur bouge le slider du menu Settings. L'ini n'est ecrit que si la valeur change, ou une fois au
// premier lancement (bCameraSpeedSet faux) : la valeur de GI, issue de GameSettings.sav, est alors reprise et bornee.
// GameSettings.sav garde son champ CameraSpeed, recopie de GI par GI.SaveSettings.
// Valeurs permises : entiers de 1 a 7 (slider a pas de 1), 3 par defaut.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "UObject/Object.h"
#include "LPUserSettings.generated.h"
/** Reglages du joueur propres a LifePlay, enregistres dans GameUserSettings.ini (objet par defaut seulement). */
UCLASS(config = GameUserSettings)
class LIFEPLAY_API ULPUserSettings : public UObject
{
GENERATED_BODY()
public:
/** Vitesse de camera choisie dans le menu Settings (1 a 7). */
UPROPERTY(config)
float CameraSpeed = 3.f;
/** Faux tant que l'entree n'a jamais ete ecrite (premier lancement : reprise de GI.CameraSpeed). */
UPROPERTY(config)
bool bCameraSpeedSet = false;
};
UCLASS()
class LIFEPLAY_API ULPUserSettingsLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/** Arrondit a l'entier le plus proche et borne entre 1 et 7. */
UFUNCTION(BlueprintPure, Category = "LifePlay|Settings")
static float ClampCameraSpeed(float V);
/**
* A appeler au demarrage, apres GI.LoadSettings : recopie dans GI.CameraSpeed la valeur de GameUserSettings.ini.
* Premier lancement (entree jamais ecrite) : reprend GI.CameraSpeed (lu dans GameSettings.sav), la borne, l'ecrit
* dans GI et dans l'ini.
*/
UFUNCTION(BlueprintCallable, Category = "LifePlay|Settings")
static void ApplyCameraSpeedAtStartup(UObject* GameInstance);
/** Slider du menu Settings : borne V, l'ecrit dans GI.CameraSpeed et, si elle change, dans GameUserSettings.ini. */
UFUNCTION(BlueprintCallable, Category = "LifePlay|Settings")
static void SetCameraSpeed(UObject* GameInstance, float V);
/** Vitesse de camera enregistree dans GameUserSettings.ini, bornee (3 si jamais ecrite). */
UFUNCTION(BlueprintPure, Category = "LifePlay|Settings")
static float GetCameraSpeed();
};
```
`Source/LifePlay/LPUserSettings.cpp` (fichier neuf, 115 lignes, contenu intégral) :
```cpp
// Lot STC - voir LPUserSettings.h
#include "LPUserSettings.h"
#include "LifePlay.h"
#include "UObject/UnrealType.h"
namespace LPUserSettingsGi
{
constexpr float DefaultCameraSpeed = 3.f;
// GI.CameraSpeed est une variable Blueprint : reel double en 5.x (FDoubleProperty), float accepte aussi.
// Propriete absente ou d'un autre type : avertissement, GI n'est pas touche.
FProperty* FindCameraSpeed(UObject* GameInstance, const TCHAR* Caller)
{
static const FName CameraSpeedName(TEXT("CameraSpeed"));
if (!GameInstance)
{
UE_LOG(LogLifePlay, Warning, TEXT("Camera : %s sans GameInstance, GI.CameraSpeed non touche"), Caller);
return nullptr;
}
FProperty* Prop = GameInstance->GetClass()->FindPropertyByName(CameraSpeedName);
if (!CastField<FDoubleProperty>(Prop) && !CastField<FFloatProperty>(Prop))
{
UE_LOG(LogLifePlay, Warning, TEXT("Camera : %s, pas de propriete reelle CameraSpeed dans %s, GI non touche"),
Caller, *GameInstance->GetClass()->GetName());
return nullptr;
}
return Prop;
}
float ReadValue(const FProperty* Prop, const UObject* GameInstance)
{
if (const FDoubleProperty* AsDouble = CastField<FDoubleProperty>(Prop))
{
return static_cast<float>(AsDouble->GetPropertyValue_InContainer(GameInstance));
}
if (const FFloatProperty* AsFloat = CastField<FFloatProperty>(Prop))
{
return AsFloat->GetPropertyValue_InContainer(GameInstance);
}
return DefaultCameraSpeed;
}
void WriteValue(const FProperty* Prop, UObject* GameInstance, float Value)
{
if (const FDoubleProperty* AsDouble = CastField<FDoubleProperty>(Prop))
{
AsDouble->SetPropertyValue_InContainer(GameInstance, static_cast<double>(Value));
}
else if (const FFloatProperty* AsFloat = CastField<FFloatProperty>(Prop))
{
AsFloat->SetPropertyValue_InContainer(GameInstance, Value);
}
}
}
float ULPUserSettingsLibrary::ClampCameraSpeed(float V)
{
return FMath::Clamp(FMath::RoundToFloat(V), 1.f, 7.f);
}
void ULPUserSettingsLibrary::ApplyCameraSpeedAtStartup(UObject* GameInstance)
{
ULPUserSettings* Settings = GetMutableDefault<ULPUserSettings>();
FProperty* Prop = LPUserSettingsGi::FindCameraSpeed(GameInstance, TEXT("ApplyCameraSpeedAtStartup"));
if (!Prop)
{
// Avertissement deja ecrit. Ini inchange : au premier lancement, la reprise depuis GI sera retentee.
return;
}
if (Settings->bCameraSpeedSet)
{
const float Value = ClampCameraSpeed(Settings->CameraSpeed);
const float Before = LPUserSettingsGi::ReadValue(Prop, GameInstance);
LPUserSettingsGi::WriteValue(Prop, GameInstance, Value);
UE_LOG(LogLifePlay, Display, TEXT("Camera : vitesse %.0f lue dans GameUserSettings.ini (ini %.2f), recopiee dans GI (avant %.2f)"),
Value, Settings->CameraSpeed, Before);
return;
}
// Premier lancement : entree jamais ecrite. GI.CameraSpeed vient de GameSettings.sav (GI.LoadSettings).
const float FromGi = LPUserSettingsGi::ReadValue(Prop, GameInstance);
const float Value = ClampCameraSpeed(FromGi);
LPUserSettingsGi::WriteValue(Prop, GameInstance, Value);
Settings->CameraSpeed = Value;
Settings->bCameraSpeedSet = true;
Settings->SaveConfig();
UE_LOG(LogLifePlay, Display, TEXT("Camera : vitesse %.0f reprise de GI (GameSettings.sav : %.2f), ecrite dans GameUserSettings.ini (premier lancement)"),
Value, FromGi);
}
void ULPUserSettingsLibrary::SetCameraSpeed(UObject* GameInstance, float V)
{
const float Value = ClampCameraSpeed(V);
if (FProperty* Prop = LPUserSettingsGi::FindCameraSpeed(GameInstance, TEXT("SetCameraSpeed")))
{
LPUserSettingsGi::WriteValue(Prop, GameInstance, Value);
}
// L'ini fait foi : ecrit seulement si la valeur change, ou si l'entree n'a jamais ete ecrite.
ULPUserSettings* Settings = GetMutableDefault<ULPUserSettings>();
if (Settings->bCameraSpeedSet && Settings->CameraSpeed == Value)
{
return;
}
Settings->CameraSpeed = Value;
Settings->bCameraSpeedSet = true;
Settings->SaveConfig();
UE_LOG(LogLifePlay, Display, TEXT("Camera : vitesse %.0f enregistree dans GameUserSettings.ini"), Value);
}
float ULPUserSettingsLibrary::GetCameraSpeed()
{
const ULPUserSettings* Settings = GetDefault<ULPUserSettings>();
return Settings->bCameraSpeedSet ? ClampCameraSpeed(Settings->CameraSpeed) : LPUserSettingsGi::DefaultCameraSpeed;
}
```
### Commandes de contrôle rejouables
- `git -C "D:/Game/LifePlay-master 5.8" status --short` → ` M Source/LifePlay/LPSettingsSubsystem.cpp`, `?? Source/LifePlay/LPUserSettings.cpp`,
`?? Source/LifePlay/LPUserSettings.h` (+ `?? Docs/Migration/32_Organisation_Agents.md`, préexistant, non touché).
- `git -C "D:/Game/LifePlay-master 5.8" ls-files --eol -- Source/LifePlay/LPSettingsSubsystem.cpp` → `i/crlf w/crlf` ;
`git … ls-files -o --eol -- Source/LifePlay/` → `w/lf` pour les deux neufs.
## Addendum orchestrateur (2026-10-10, après remise du livrable)
Écart E2 tranché : le style ne s'applique qu'au slider `SliderCameraSpeed` (les sliders `LPColor*` / `LPVideo*` gardent
leur aspect). Code actuel de la boucle : `if (!Slider || Slider->GetFName() != TEXT("SliderCameraSpeed")) { continue; }` et
commentaire « slider de vitesse de camera seulement ». MD5 actuel de `LPSettingsSubsystem.cpp` : `b72671af…` (le MD5
`ede28e6d…` cité plus haut est celui de la version remise par lp-impl). Le diff de ce livrable décrit la version
antérieure ; la version qui fait foi est celle relue en STC-VAL (contrôle a).