LifePlay-Revival/Docs/Migration/etat/REL/SET1/SET1-V1b-IMPL.md
2026-10-21 09:36:04 +02:00

32 KiB
Raw Blame History

Fiche SET1-V1b — Niveau N2 — Modèle prévu Sonnet (fiche) | utilisé claude-sonnet-5-5 — Agent lp-impl — Skills sk-protocol, ue-cpp-build (préchargés en plus : lp-build, lp-ue-compat)

SET1-V1b-IMPL : les lignes Couleur, Video et Mods se posent sur l'instance de MainMenu qui est à l'écran (2026-10-20)

Hors gabarit : la fiche demande, après les rubriques IMPL 1 à 6, la compilation, le diff, les MD5, les journaux et la preuve attendue en jeu (sections 7 à 12). Suite directe de SET1-V1-IMPL.md (§ 0 et § 8). Contenu adulte (doc 27) : noms techniques de widgets seulement.

Résultat : réussi à la compilation (éditeur et jeu : code 0, 0 erreur, 0 avertissement) ; non éprouvé en jeu (la preuve en jeu revient à la VAL, § 10). Les trois sous-systèmes choisissent maintenant la même liste que les onglets ; aucun état par instance à remettre à zéro n'a été trouvé chez eux (§ 2, constat C1).

1. Fichiers modifiés

Fichier Lignes (après modification) Contenu
Source/LifePlay/LPSettingsSubsystem.h 17 class UGameInstance; (déclaration avancée)
idem 50-55 static UScrollBox* FindOnScreenSettingsList(const UGameInstance* GI, const UScrollBox* Current = nullptr); publique, avec son commentaire
Source/LifePlay/LPSettingsSubsystem.cpp 592-596 ULPSettingsSubsystem::FindOnScreenSettingsList : une ligne, renvoie LPSettingsUi::FindOnScreenSettingsList(GI, Current) (la fonction du namespace LPSettingsUi, :122-146, n'est pas touchée ; le Tick des onglets l'appelle comme avant)
Source/LifePlay/LPColorGradeSubsystem.cpp 18 #include "LPSettingsSubsystem.h"
idem 260-264 EnsureControls (commence l. 258) : la boucle « première SettingsScrollBox + break » (ancien 259-274) est remplacée par ULPSettingsSubsystem::FindOnScreenSettingsList(GetGameInstance())
idem 313-314 nouvelle ligne de journal Couleur : reglages de couleur ajoutes sur <MainMenu_C_n> (fin d'EnsureControls)
Source/LifePlay/LPVideoQualitySubsystem.cpp 20 #include "LPSettingsSubsystem.h"
idem 463-467 EnsureControls (commence l. 461) : même remplacement (ancien 462-477)
idem 594-595 journal Video : controles ajoutes avant les reglages de couleur (sur <MainMenu_C_n>)
Source/LifePlay/LPModInfoSubsystem.cpp 21 #include "LPSettingsSubsystem.h"
idem 243-246 EnsureSettingsRows (commence l. 241) : même remplacement (ancien 242-257)
idem 302-305 journal Modules : cases de controle des mods ajoutees a Settings > Misc (moteur …, version min …, version max …) sur <MainMenu_C_n>

Les numéros de ligne « après » ont été relevés par grep -n sur les fichiers actuels (après les builds).

Total (diff -u --strip-trailing-cr contre l'instantané, lignes + / - hors en-têtes ; § 11) : 5 fichiers, +38 / −51. Par fichier : LPSettingsSubsystem.h +8 / −0, LPSettingsSubsystem.cpp +6 / −0, LPColorGradeSubsystem.cpp +8 / −16, LPVideoQualitySubsystem.cpp +8 / −17, LPModInfoSubsystem.cpp +8 / −18. Fins de ligne conservées (§ 9) : CRLF pour quatre fichiers, LF pour LPModInfoSubsystem.cpp (le fichier est LF dans l'index, git ls-files --eol).

LPKeyboardSubsystem.cpp : non touché (consigne), MD5 611c21489d80374a4817f70e408cf4db avant et après.

API moteur utilisée, lue dans D:\Game\Launcher\Engine\UE_5.8\Engine\Source (5.8.3). Le lot n'ajoute aucune API moteur nouvelle par rapport à SET1-V1 (§ 1 de SET1-V1-IMPL.md) ; les seules lignes neuves s'appuient sur :

API Source
UGameInstanceSubsystem::GetGameInstance() const renvoie UGameInstance* (paramètre const UGameInstance* de la nouvelle fonction : conversion vers const) Runtime/Engine/Public/Subsystems/GameInstanceSubsystem.h:25
class UGameInstance; déjà déclarée par GameInstanceSubsystem.h (la redéclaration dans notre .h est sans effet) GameInstanceSubsystem.h:9
UObject::GetTypedOuter<T>() const (pour le nom du MainMenu dans les journaux) Runtime/CoreUObject/Public/UObject/UObjectBaseUtility.h:551-553

2. Écarts à la SPEC / à la fiche

# Écart Motif
E1 Le journal de Video et celui de Mods changent de texte (suffixe (sur <nom>) / sur <nom>), et le Color reçoit une ligne neuve. La fiche demande que « les lignes de journal de chaque sous-système visent l'instance à l'écran ». Sans nom d'instance, aucune ligne ne prouve sur quelle liste les lignes ont été posées. Le début du texte est conservé, donc une recherche par préfixe trouve toujours les lignes : VQ2-VAL.md:62 et VQ2-SPEC.md:302 citent Video : controles ajoutes avant les reglages de couleur ; U7-T7-IMPL.md:221 cite la ligne Mods entière, qui se terminait par ) : une comparaison exacte avec cette trace ancienne échouerait.
E2 Tick des onglets inchangé : il appelle toujours la fonction du namespace LPSettingsUi, pas la fonction statique. « Sans changer son comportement » : la statique est un renvoi d'une ligne vers la même fonction, aucun risque de divergence.
E3 Les trois appelants passent Current = nul (valeur par défaut) ; Tick des onglets passe SettingsList. Ils ne suivent aucune liste. Conséquence : à égalité de score (deux instances à l'écran, aucune liste ouverte) ils prennent la première trouvée, les onglets la liste déjà suivie. Cas non rencontré (une seule instance à l'écran à la fois d'après SET1-V1-IMPL.md § 0), sans effet visible : dès qu'une liste est ouverte (score 2), les quatre sous-systèmes la choisissent.
E4 LPSettingsSubsystem.h est modifié (V1 : « .h non modifié »). Exigé par la fiche (fonction statique publique déclarée dans le .h).
E5 Aucune remise à zéro d'état par instance n'a été ajoutée dans Color, Video et Mods (la fiche : « corrige au minimum »). Constat C1 ci-dessous : leur « état » est lu sur les enfants de la liste choisie, donc par instance de fait.
E6 CopieEtat.ps1 -Lot SET1 rend ALERTE GIT (code 1), 7 fichiers. Deux sont antérieurs à ce travail (LPCameraModeSubsystem.cpp, LPDirectControlSubsystem.cpp, statut git de départ de la session) ; LPSettingsSubsystem.cpp porte aussi les changements de SET1-V1, non commités ; les quatre autres sont les fichiers de ce lot, non déclarés par -Assets (aucun asset).

Constat C1 — état par instance (lecture, non observé en jeu). Pour chacun des trois sous-systèmes, ce qui décide « les lignes sont-elles déjà là ? » est lu sur la liste choisie, jamais mémorisé dans un indicateur :

  • Color : présence d'un enfant LPColorBrightness (LPColorGradeSubsystem.cpp:273, boucle sur Scroll->GetChildrenCount()). Les cinq afficheurs de valeur BrightnessValue…TintValue sont des TWeakObjectPtr<UTextBlock> (LPColorGradeSubsystem.h:53-57) réaffectés par AddRow (LPColorGradeSubsystem.cpp:235-254, test sur le nom de la ligne) puis remplis (:293-312). Aucun indicateur booléen.
  • Video : présence d'un enfant LPVideoOverall (LPVideoQualitySubsystem.cpp:477). Rows[] (.h:104) et RecommendedButton (.h:105) sont réaffectés par AddRow (:426-427) et MakeRecommendedRow (:457) ; RefreshWidgets() (:591) et ApplyToScalability() (:593) rejouent les valeurs sur les curseurs neufs. Levels et bConfigured sont globaux par conception (choix du joueur), pas par instance.
  • Mods : présence d'un enfant LPModCheckEngine (LPModInfoSubsystem.cpp:254, RowNames[0]) ; aucune variable membre liée à la liste des réglages (ManagerList et bManagerListLogged, .h:75-76, concernent le gestionnaire de mods, autre widget, déjà filtré par IsInViewport à TickModManager). Avec la bonne liste, une nouvelle instance n'a pas ces enfants : les lignes sont recréées à la première image où l'instance est à l'écran ; l'ancienne instance n'est plus regardée. Les noms LPColor* / LPVideo* / LPModCheck* sont classés par LPSettingsUi::CategoryOf (LPSettingsSubsystem.cpp:267-275 : Video, Video, Misc) et ApplyRows est rejoué à chaque image où la liste est ouverte, donc une ligne ajoutée plus tard entre dans son onglet à l'image suivante.

Constat C2 — délai. Les lignes sont posées par des tickers à 0,5 s (LPColorGradeSubsystem.cpp:77, LPVideoQualitySubsystem.cpp:160, LPModInfoSubsystem.cpp:150), alors que LPSettingsSubsystem tourne à chaque image (:583, période 0). Entre l'apparition d'une instance à l'écran et ses lignes, il peut s'écouler jusqu'à ≈ 0,5 s ; un clic sur Settings dans cet intervalle montrerait les onglets Video et Misc incomplets quelques images (puis complétés). Estimé, non mesuré ; périodes non modifiées (hors fiche).

Constat C3 — le défaut de V1 §8 est bien celui-ci. Les trois boucles supprimées étaient les mêmes (TObjectIterator<UScrollBox>, nom SettingsScrollBox, même GameInstance, break à la première) : git diff/diff -u du § 11, lignes -.

3. Instantané

D:\Game\LifePlay_Backup_5.5\SET1-V1b\ (fait par l'orchestrateur), manifest.csv relu : 5 fichiers, MD5 de départ tous égaux au manifeste avant écriture (relevé de session, § 9).

Fichier (dans Source\LifePlay\) Octets MD5 du manifeste
LPSettingsSubsystem.cpp 33904 3591F579D88C4CA3A44468C750C9A24E
LPSettingsSubsystem.h 1792 0F98C05568AE789C5C0B78F6EC580503
LPColorGradeSubsystem.cpp 12464 F818C7F56DA018ED97683F01717A9AFB
LPVideoQualitySubsystem.cpp 19408 DFF29F3F1B976979E556501CEBBF2613
LPModInfoSubsystem.cpp 16572 1D0FFF7D4327C493903F180868D00BDE

Retour arrière (proposé, non lancé) : Tools\Restore.ps1 -Lot SET1-V1b. Attention : LPSettingsSubsystem.cpp y revient à l'état de fin de SET1-V1 (qui contient le travail de V1, non commité), pas à HEAD.

4. Ce qui n'a pas été fait

  • Aucun essai en jeu (la fiche n'en confie pas) ; aucun éditeur ni jeu lancé.
  • LPKeyboardSubsystem.cpp non touché (consigne). LPReadableTextSubsystem.cpp, LPCameraModeSubsystem.cpp, LPDirectControlSubsystem.cpp non ouverts.
  • Pas de changement des périodes des tickers (C2), du Tick des onglets, de PlaceSettingsButton, d'un Blueprint ni du GI.
  • Pas de test automatique (aucun existant pour ces sous-systèmes). Pas de build empaqueté.
  • Aucune autre boucle SettingsScrollBox à reprendre : Grep "SettingsScrollBox" sur Source ne trouve plus que LPSettingsSubsystem.cpp:129 (la fonction partagée), LPKeyboardSubsystem.cpp:854 (hors consigne, indicateur de journal sans break), LPReadableTextSubsystem.cpp:125 (remontée de parents) et des commentaires.

5. Points à confirmer en VAL (un par ligne)

  1. W1 : en partie (Échap, Settings), première ouverture : l'onglet Video montre Overall Quality, Shadows, Textures, Effects, Anti-Aliasing, Recommended (LPVideo*) puis Brightness, Saturation, Contrast, White Balance, Tint (LPColor*) ; l'onglet Misc montre les trois cases de contrôle des mods (LPModCheck*) ; le tout dès l'ouverture, sans attendre la collecte d'une ancienne instance (≈ 30 s).
  2. W2 : deuxième et troisième ouverture en partie (nouvelle instance à chaque fois) : mêmes contenus Video et Misc dès l'ouverture ; pour chaque instance trois lignes de journal portant le même MainMenu_C_<n> que Reglages : onglets poses sur MainMenu_C_<n> (partie) : Couleur : reglages de couleur ajoutes sur …, Video : controles ajoutes avant les reglages de couleur (sur …), Modules : cases de controle des mods ajoutees a Settings > Misc (…) sur ….
  3. W3 : écran titre, premier lancement, ouvrir Settings : mêmes contenus et mêmes trois lignes, <n> identique à celui de onglets poses sur … (ecran titre). Symptôme du risque V6 de SET1-V1 (IsInViewport() faux pour l'instance du titre) : aucune des trois lignes et aucun onglets poses au titre ; ce lot l'aggraverait pour Video/Mods/Couleur, qui l'avaient avant (première liste trouvée, sans filtre d'écran).
  4. W4 : retour au titre puis réouverture : mêmes contenus et trois lignes avec un <n> différent de celui du premier titre.
  5. W5 : valeurs sur l'instance neuve : le curseur Overall et les quatre curseurs de Video affichent le niveau en cours (RefreshWidgets, pas la valeur par défaut) ; les cinq afficheurs de Couleur affichent les valeurs en cours (réaffectation des TWeakObjectPtr) ; un curseur déplacé sur l'instance neuve met bien à jour son afficheur (pas l'ancien).
  6. W6 : pas de doublon : une seule ligne de journal par sous-système et par instance ; les noms LPColorBrightness, LPVideoOverall, LPModCheckEngine présents une fois dans la liste de l'instance à l'écran.
  7. W7 : délai (C2) : mesurer, dans LifePlay.log, l'écart entre Reglages : onglets poses sur … et les trois lignes de la même instance ; attendu ≤ ≈ 0,5 s ; une ouverture de Settings dans cet intervalle ne doit rien casser.
  8. W8 : ouverture répétée sur la même instance (ouvrir, Back, rouvrir) : aucune nouvelle ligne Couleur/Video/Modules (présence déjà vue), onglet Video inchangé.
  9. W9 : reprise de V8 de SET1-V1-IMPL.md § 5 (onglets Video et Misc de l'instance de partie complets) : à juger sur W1 à W3 ; V1 à V10 de SET1-V1 restent à rejouer comme prévu.

6. Fichiers à commiter

Dépôt du jeu, branche ue5.8 : M Source/LifePlay/LPSettingsSubsystem.h M Source/LifePlay/LPSettingsSubsystem.cpp (contient aussi le travail de SET1-V1, non commité à la date de cette fiche) M Source/LifePlay/LPColorGradeSubsystem.cpp M Source/LifePlay/LPVideoQualitySubsystem.cpp M Source/LifePlay/LPModInfoSubsystem.cpp A Docs/Migration/etat/REL/SET1/SET1-V1b-IMPL.md A Docs/Migration/etat/REL/SET1/SET1_Build_20261020-213520.txt (résumé Build.ps1 éditeur) A Docs/Migration/etat/REL/SET1/SET1_Build_20261020-213620.txt (résumé Build.ps1 jeu) A Docs/Migration/etat/REL/SET1/SET1-V1b_CopieEtat_avant_build.json, SET1-V1b_CopieEtat_apres_build.json (traces CopieEtat.ps1)

Hors lot, déjà modifiés avant ce travail, à ne pas embarquer : Source/LifePlay/LPCameraModeSubsystem.cpp, Source/LifePlay/LPDirectControlSubsystem.cpp.

7. Compilation

Éditeur fermé et rien ne tournait avant (UeState : processus=0 editeur=0 compilation=0 shaders=0 jeu=0, code 0). Les deux builds ont été lancés à la suite, l'éditeur d'abord, le jeu seulement après un code 0.

LifePlayEditor Win64 Development LifePlay Win64 Development -NoUBA
Commande pwsh -NoProfile -Command "& 'D:/Game/LifePlay-master 5.8/Tools/Build.ps1' -Lot SET1 -EtatDir 'D:/Game/LifePlay-master 5.8/Docs/Migration/etat/REL/SET1'" idem + -Target LifePlay -Config Development -ExtraArgs '-NoUBA'
Code de sortie 0 0
Durée 59 s 59 s
Erreurs / avertissements du compilateur 0 / 0 0 / 0
Autres lignes (UBT, UHT, liens) 20 (les 20 lignes Plugin 'HyperAIStudio' does not list plugin … connues, lp-build § 7 : attendu 20 pour l'éditeur) 0 (attendu 0 pour la cible jeu)
Unités compilées 5 : LPColorGradeSubsystem.cpp, LPModInfoSubsystem.cpp, LPSettingsSubsystem.cpp, LPVideoQualitySubsystem.cpp, Module.LifePlay.cpp les mêmes 5, marquées [NoUba]
Liaison [6/8] Link [x64] UnrealEditor-LifePlay.dll (DLL liées : 1) [6/7] Link [x64] LifePlay.exe [NoUba], Output binary: D:\Game\LifePlay-master 5.8\Binaries\Win64\LifePlay.exe, Result: Succeeded (journal :26, :31, :33) ; le résumé compte « DLL liées : 0 » car le jeu lie un .exe
Toolchain Using Visual Studio 14.50.35739 toolchain (C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.50.35717) = MSVC épinglé de la 5.8 idem
Résumé Docs\Migration\etat\REL\SET1\SET1_Build_20261020-213520.txt Docs\Migration\etat\REL\SET1\SET1_Build_20261020-213620.txt
Journal Saved\Logs\portage\SET1_Build_20261020-213520.log Saved\Logs\portage\SET1_Build_20261020-213620.log

Sorties brutes de Build.ps1 (dernières lignes de chaque build) :

code=0 duree=59s erreurs=0 avertissements=0 autres=20 unites=5
code=0 duree=59s erreurs=0 avertissements=0 autres=0 unites=5

Dates des binaires (ls -l --time-style=full-iso) : UnrealEditor-LifePlay.dll 2026-10-20 21:36:18, LifePlay.exe 2026-10-20 21:37:17 (postérieurs aux écritures du § 11). Limites : la ligne Makefile des deux résumés est vide (comme en V1) ; le module modifié figure bien dans les unités compilées. Aucune ligne de journal propre au nouveau code n'existe avant un lancement du jeu (§ 10).

8. Les quatre autres sous-systèmes (point 3 de la fiche)

LPKeyboardSubsystem.cpp : non modifié, MD5 611c21489d80374a4817f70e408cf4db identique avant et après (md5sum, § 9). Aucun défaut de choix d'instance d'après SET1-V1-IMPL.md § 8 (boucle sans break, ne sert qu'à un indicateur pour un journal). Trois sous-systèmes corrigés : Color, Video, Mods (§ 1). LPReadableTextSubsystem : sans objet (aucun choix d'instance).

9. MD5 et fins de ligne

Commande : md5sum Source/LifePlay/LPSettingsSubsystem.cpp Source/LifePlay/LPSettingsSubsystem.h Source/LifePlay/LPColorGradeSubsystem.cpp Source/LifePlay/LPVideoQualitySubsystem.cpp Source/LifePlay/LPModInfoSubsystem.cpp Source/LifePlay/LPKeyboardSubsystem.cpp (après modification et après les builds, identique aux deux relevés) :

6277a8fc139c05dc10e302f88de0f8d9 *Source/LifePlay/LPSettingsSubsystem.cpp
138350efe8473c430db984db63c8feac *Source/LifePlay/LPSettingsSubsystem.h
5be400543166b6de7a4a88f6097a9d93 *Source/LifePlay/LPColorGradeSubsystem.cpp
c3055197030bdbbce813df4cc6d7cd63 *Source/LifePlay/LPVideoQualitySubsystem.cpp
98206e688308e908b04ae15cf408e1bb *Source/LifePlay/LPModInfoSubsystem.cpp
611c21489d80374a4817f70e408cf4db *Source/LifePlay/LPKeyboardSubsystem.cpp
Fichier MD5 avant (relu avant d'écrire, = manifeste) MD5 après
LPSettingsSubsystem.cpp 3591f579d88c4ca3a44468c750c9a24e 6277a8fc139c05dc10e302f88de0f8d9
LPSettingsSubsystem.h 0f98c05568ae789c5c0b78f6ec580503 138350efe8473c430db984db63c8feac
LPColorGradeSubsystem.cpp f818c7f56da018ed97683f01717a9afb 5be400543166b6de7a4a88f6097a9d93
LPVideoQualitySubsystem.cpp dff29f3f1b976979e556501cebbf2613 c3055197030bdbbce813df4cc6d7cd63
LPModInfoSubsystem.cpp 1d0fff7d4327c493903f180868d00bde 98206e688308e908b04ae15cf408e1bb
LPKeyboardSubsystem.cpp (non touché) 611c21489d80374a4817f70e408cf4db idem

git ls-files --eol sur les cinq fichiers modifiés, puis comptes tr -cd '\r' | wc -c et tr -cd '\n' | wc -c :

i/crlf  w/crlf  attr/-text   Source/LifePlay/LPColorGradeSubsystem.cpp     (CR=370  LF=370)
i/lf    w/lf    attr/-text   Source/LifePlay/LPModInfoSubsystem.cpp        (CR=0    LF=432)
i/crlf  w/crlf  attr/-text   Source/LifePlay/LPSettingsSubsystem.cpp       (CR=1002 LF=1002)
i/crlf  w/crlf  attr/-text   Source/LifePlay/LPSettingsSubsystem.h         (CR=76   LF=76)
i/crlf  w/crlf  attr/-text   Source/LifePlay/LPVideoQualitySubsystem.cpp   (CR=596  LF=596)

pwsh -NoProfile -File Tools/FileCheck.ps1 -Lot SET1-V1b (le lot de l'instantané donne le manifeste des 5 fichiers) :

Fichiers CRLF  LF CR BOM : fichiers=5 CRLF=4 LF=1 alertes=0 introuvables=0
contenu : modifie=5

(détail par fichier : CRLF 370 / LF 432 / CRLF 1002 / CRLF 76 / CRLF 596, Sauv = fins de ligne de l'instantané identiques, aucune alerte.)

pwsh -NoProfile -File Tools/PubCheck.ps1 -Fichiers <chemin relatif> -Depot "D:/Game/LifePlay-master 5.8" (stdin sur /dev/null, un fichier par appel) : PubCheck : 0 constat(s), code 0, pour chacun des cinq fichiers source. Pour ce livrable : voir la fin de la section 12.

pwsh -NoProfile -File Tools/CopieEtat.ps1 -Lot SET1 -Sortie … avant et après les builds : COPIE ALERTE lot=SET1 … proc=0 assets=0 absents=0 modifies=0 git=7/0/0 hors_declares=7 parasites=0 … alertes=GIT, code 1 dans les deux cas (voir E6). Traces : SET1-V1b_CopieEtat_avant_build.json, SET1-V1b_CopieEtat_apres_build.json.

Fin de lot : pwsh -NoProfile -File Tools/UeState.ps1 < /dev/null → processus=0 editeur=0 compilation=0 shaders=0 jeu=0, code 0. Jeton UE rendu.

10. Journaux et preuve attendue en jeu

Lignes de journal (préfixe LogLifePlay: dans LifePlay.log) :

Ligne Origine Quand
`Reglages : onglets poses sur <MainMenu_C_n> (ecran titre partie)` SET1-V1 (LPSettingsSubsystem.cpp, fin d'EnsureTabs)
Couleur : reglages de couleur ajoutes sur <MainMenu_C_n> nouvelle (LPColorGradeSubsystem.cpp:313-314, texte à la ligne 314) les 5 lignes LPColor* viennent d'être ajoutées à la liste de cette instance
Video : controles ajoutes avant les reglages de couleur (sur <MainMenu_C_n>) existante, suffixe nouveau (LPVideoQualitySubsystem.cpp:594-595) les lignes LPVideo* et Recommended viennent d'être ajoutées
Modules : cases de controle des mods ajoutees a Settings > Misc (moteur a, version min b, version max c) sur <MainMenu_C_n> existante, suffixe nouveau (LPModInfoSubsystem.cpp:302-305) les 3 cases LPModCheck* viennent d'être ajoutées

Recette de lecture pour la VAL : pwsh -NoProfile -File Tools/LogStats.ps1 -Log <LifePlay.log> -Pattern 'onglets (poses|retires)|reglages de couleur ajoutes sur|controles ajoutes avant|cases de controle des mods' -Max 60 (un seul motif à alternatives : pwsh -File refuse une liste ; journal de la session, pas de compte refait de mémoire). Rapprocher ensuite les noms MainMenu_C_<n> des quatre familles de lignes.

Preuve attendue, à rejouer par la VAL sur un build Development :

Scénario Attendu à l'écran Attendu au journal
Partie : Échap, Settings, première ouverture onglets Video et Misc complets dès l'ouverture (W1) onglets poses sur MainMenu_C_n (partie) puis, avec le même n, les trois lignes Couleur, Video, Modules (ordre libre)
Partie : deuxième, troisième ouverture idem, sans attendre ≈ 30 s (W2) onglets retires de <ancienne> si une barre existait ; un n nouveau à chaque ouverture, repris par les quatre lignes
Écran titre, puis retour au titre idem (W3, W4) (ecran titre) ; un n différent au second titre, repris par les trois lignes
Même instance rouverte aucun changement (W8) aucune nouvelle ligne Couleur, Video, Modules

Limite : la présence d'une ligne sur <n> ne prouve que la liste choisie ; ce que le joueur voit (contenu des onglets) se juge à l'écran. Ni IsInViewport() sur l'instance du titre, ni l'ordre réel d'itération de TObjectIterator, ni le délai du ticker à 0,5 s ne sont observés ; établis par lecture seulement.

11. Diff (diff -u --strip-trailing-cr entre l'instantané D:/Game/LifePlay_Backup_5.5/SET1-V1b/Source/LifePlay/ et Source/LifePlay/)

=== LPSettingsSubsystem.h
@@ -14,6 +14,7 @@
 
 class UButton;
 class UCanvasPanel;
+class UGameInstance;
 class UHorizontalBox;
 class UNativeWidgetHost;
 class UScrollBox;
@@ -46,6 +47,13 @@
 	UFUNCTION()
 	void OpenSettings();
 
+	// Lot SET1-V1b. Liste des reglages (MainMenu.SettingsScrollBox) de l'instance de MainMenu qui est a l'ecran, nulle s'il
+	// n'y en a aucune. Partagee avec les sous-systemes qui ajoutent des lignes a cette liste (couleur, video, controle des
+	// mods) : une ancienne instance, retiree du viewport et pas encore collectee, garde sa liste en memoire et ne doit pas
+	// recevoir leurs lignes a la place de l'instance affichee. Current : liste deja suivie par l'appelant, elle departage
+	// deux listes a l'ecran ; peut etre nulle.
+	static UScrollBox* FindOnScreenSettingsList(const UGameInstance* GI, const UScrollBox* Current = nullptr);
+
 private:
 	bool Tick(float DeltaTime);
 	void PlaceSettingsButton();
=== LPSettingsSubsystem.cpp
@@ -589,6 +589,12 @@
 	Super::Deinitialize();
 }
 
+UScrollBox* ULPSettingsSubsystem::FindOnScreenSettingsList(const UGameInstance* GI, const UScrollBox* Current)
+{
+	// SET1-V1b : meme choix que le Tick des onglets (LPSettingsUi::FindOnScreenSettingsList), expose aux autres sous-systemes.
+	return LPSettingsUi::FindOnScreenSettingsList(GI, Current);
+}
+
 bool ULPSettingsSubsystem::Tick(float DeltaTime)
 {
 	(void)DeltaTime;
=== LPColorGradeSubsystem.cpp
@@ -15,6 +15,7 @@
 #include "Engine/PostProcessVolume.h"
 #include "Engine/World.h"
 #include "LifePlay.h"
+#include "LPSettingsSubsystem.h"
 #include "Misc/ConfigCacheIni.h"
 #include "Misc/Paths.h"
 #include "Styling/CoreStyle.h"
@@ -256,22 +257,11 @@
 
 void ULPColorGradeSubsystem::EnsureControls()
 {
-	UScrollBox* Scroll = nullptr;
-	for (TObjectIterator<UScrollBox> It; It; ++It)
-	{
-		UScrollBox* Candidate = *It;
-		if (!Candidate || Candidate->GetFName() != TEXT("SettingsScrollBox") || Candidate->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
-		{
-			continue;
-		}
-		const UUserWidget* Owner = Candidate->GetTypedOuter<UUserWidget>();
-		if (!Owner || Owner->HasAnyFlags(RF_ClassDefaultObject) || Owner->GetGameInstance() != GetGameInstance())
-		{
-			continue;
-		}
-		Scroll = Candidate;
-		break;
-	}
+	// SET1-V1b : la liste de l'instance de MainMenu qui est a l'ecran, pas la premiere trouvee (une ancienne instance,
+	// retiree du viewport et pas encore collectee, vient souvent avant). Aucune a l'ecran : rien a faire. Pas d'etat par
+	// instance a remettre a zero : la presence de LPColorBrightness se lit sur les enfants de la liste choisie, et AddRow
+	// rebranche les afficheurs de valeur (BrightnessValue...) sur les lignes de cette liste.
+	UScrollBox* Scroll = ULPSettingsSubsystem::FindOnScreenSettingsList(GetGameInstance());
 	if (!Scroll)
 	{
 		return;
@@ -320,6 +310,8 @@
 	{
 		Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Tint, 2)));
 	}
+	const UUserWidget* Menu = Scroll->GetTypedOuter<UUserWidget>();
+	UE_LOG(LogLifePlay, Display, TEXT("Couleur : reglages de couleur ajoutes sur %s"), Menu ? *Menu->GetName() : TEXT("?"));
 }
 
 void ULPColorGradeSubsystem::OnBrightnessChanged(float Value)
=== LPVideoQualitySubsystem.cpp
@@ -17,6 +17,7 @@
 #include "Engine/World.h"
 #include "HAL/IConsoleManager.h"
 #include "LifePlay.h"
+#include "LPSettingsSubsystem.h"
 #include "Misc/ConfigCacheIni.h"
 #include "Misc/Paths.h"
 #include "DynamicRHI.h"
@@ -459,22 +460,11 @@
 
 void ULPVideoQualitySubsystem::EnsureControls()
 {
-	UScrollBox* Scroll = nullptr;
-	for (TObjectIterator<UScrollBox> It; It; ++It)
-	{
-		UScrollBox* Candidate = *It;
-		if (!Candidate || Candidate->GetFName() != TEXT("SettingsScrollBox") || Candidate->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
-		{
-			continue;
-		}
-		const UUserWidget* Owner = Candidate->GetTypedOuter<UUserWidget>();
-		if (!Owner || Owner->HasAnyFlags(RF_ClassDefaultObject) || Owner->GetGameInstance() != GetGameInstance())
-		{
-			continue;
-		}
-		Scroll = Candidate;
-		break;
-	}
+	// SET1-V1b : la liste de l'instance de MainMenu qui est a l'ecran, pas la premiere trouvee (une ancienne instance,
+	// retiree du viewport et pas encore collectee, vient souvent avant). Aucune a l'ecran : rien a faire. Pas d'etat par
+	// instance a remettre a zero : la presence de LPVideoOverall se lit sur les enfants de la liste choisie, et AddRow /
+	// MakeRecommendedRow rebranchent Rows et RecommendedButton sur les lignes de cette liste.
+	UScrollBox* Scroll = ULPSettingsSubsystem::FindOnScreenSettingsList(GetGameInstance());
 	if (!Scroll)
 	{
 		return;
@@ -601,5 +591,6 @@
 	RefreshWidgets();
 	// Nouvelle instance du menu : le Blueprint a pu reappliquer ses propres valeurs.
 	ApplyToScalability();
-	UE_LOG(LogLifePlay, Display, TEXT("Video : controles ajoutes avant les reglages de couleur"));
+	const UUserWidget* Menu = Scroll->GetTypedOuter<UUserWidget>();
+	UE_LOG(LogLifePlay, Display, TEXT("Video : controles ajoutes avant les reglages de couleur (sur %s)"), Menu ? *Menu->GetName() : TEXT("?"));
 }
=== LPModInfoSubsystem.cpp
@@ -18,6 +18,7 @@
 #include "LifePlay.h"
 #include "LPDataCompat.h"
 #include "LPModGuard.h"
+#include "LPSettingsSubsystem.h"
 #include "Misc/EngineVersion.h"
 #include "Misc/FileHelper.h"
 #include "Misc/Paths.h"
@@ -239,22 +240,10 @@
 
 void ULPModInfoSubsystem::EnsureSettingsRows()
 {
-	UScrollBox* Scroll = nullptr;
-	for (TObjectIterator<UScrollBox> It; It; ++It)
-	{
-		UScrollBox* Candidate = *It;
-		if (!Candidate || Candidate->GetFName() != TEXT("SettingsScrollBox") || Candidate->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
-		{
-			continue;
-		}
-		const UUserWidget* Owner = Candidate->GetTypedOuter<UUserWidget>();
-		if (!Owner || Owner->HasAnyFlags(RF_ClassDefaultObject) || Owner->GetGameInstance() != GetGameInstance())
-		{
-			continue;
-		}
-		Scroll = Candidate;
-		break;
-	}
+	// SET1-V1b : la liste de l'instance de MainMenu qui est a l'ecran, pas la premiere trouvee (une ancienne instance,
+	// retiree du viewport et pas encore collectee, vient souvent avant). Aucune a l'ecran : rien a faire. Pas d'etat par
+	// instance a remettre a zero : la presence de LPModCheckEngine se lit sur les enfants de la liste choisie.
+	UScrollBox* Scroll = ULPSettingsSubsystem::FindOnScreenSettingsList(GetGameInstance());
 	if (!Scroll)
 	{
 		return;
@@ -310,9 +299,10 @@
 			Slot->SetPadding(FMargin(0.f, 0.f, 0.f, 10.f));
 		}
 	}
-	UE_LOG(LogLifePlay, Display, TEXT("Modules : cases de controle des mods ajoutees a Settings > Misc (moteur %d, version min %d, version max %d)"),
+	const UUserWidget* Menu = Scroll->GetTypedOuter<UUserWidget>();
+	UE_LOG(LogLifePlay, Display, TEXT("Modules : cases de controle des mods ajoutees a Settings > Misc (moteur %d, version min %d, version max %d) sur %s"),
 		FLPModGuard::GetSavedCheck(ELPModCheck::Engine) ? 1 : 0, FLPModGuard::GetSavedCheck(ELPModCheck::MinVersion) ? 1 : 0,
-		FLPModGuard::GetSavedCheck(ELPModCheck::MaxVersion) ? 1 : 0);
+		FLPModGuard::GetSavedCheck(ELPModCheck::MaxVersion) ? 1 : 0, Menu ? *Menu->GetName() : TEXT("?"));
 }

12. Établi / estimé / incertain

  • Établi : les trois boucles remplacées étaient identiques (SettingsScrollBox, même GameInstance, break à la première, § 11 lignes -) ; aucun autre site ne les reprend (Grep "SettingsScrollBox" sur Source, § 4) ; l'état de Color, Video et Mods se lit sur les enfants de la liste choisie (C1, avec lignes) ; la fonction statique renvoie la même valeur que celle des onglets (renvoi d'une ligne, LPSettingsSubsystem.cpp:592-596) ; MD5 de départ égaux au manifeste, MD5 d'arrivée et fins de ligne relevés (§ 9) ; LPKeyboardSubsystem.cpp inchangé ; compilation éditeur et jeu : code 0, 0 erreur, 0 avertissement, 5 unités compilées dans chaque (§ 7).
  • Estimé : une ancienne instance précède la nouvelle dans TObjectIterator (déjà estimé en V1) ; les lignes arrivent au plus ≈ 0,5 s après l'apparition de l'instance (tickers à 0,5 s, C2) ; ApplyRows classe sans autre changement les lignes ajoutées plus tard (rejoué à chaque image, Tick des onglets).
  • Incertain (essai qui trancherait : W1 à W9, § 5) : contenu réel des onglets Video et Misc aux trois scénarios ; IsInViewport() vrai pour l'instance du titre (V6 de V1) ; absence de régression de Video/Mods/Couleur au titre si ce filtre était faux ; mesure du délai de 0,5 s.
  • Livrable : 0 CR (fins de ligne LF, tr -cd '\r' | wc -c = 0) ; PubCheck sur ce fichier : PubCheck : 0 constat(s), code 0 ; UeState final : processus=0 editeur=0 compilation=0 shaders=0 jeu=0, code 0 ; jeton UE rendu.

Tours : 36 / 40 (déclaré par l'agent ; Tools/FicheStats.py fait foi)

Constats

  • Tools\FileCheck.ps1 -Lot SET1-V1b (lot de l'instantané, sans -Path) compare bien les cinq fichiers au manifeste (Sauv = fins de ligne d'origine, Contenu = modifié). C'est le contournement du piège relevé en V1 (Contenu = pas sauvegarde avec un chemin relatif à barres obliques).
  • Les builds ont été enchaînés dans une commande d'arrière-plan (CopieEtat avant, Build éditeur, Build jeu seulement si l'éditeur rend 0, CopieEtat après, UeState), l'attente se faisant par UeState.ps1 -Kind Compilation -WaitExit (lp-build § 2) ; le jeu est lancé par pwsh -Command "& '…/Build.ps1' … -ExtraArgs '-NoUBA'" : la forme -File … -ExtraArgs '-NoUBA' risquerait de lire -NoUBA comme un nom de paramètre.
  • La ligne exacte U7-T7-IMPL.md:221 (trace ancienne de la ligne Mods) ne correspond plus à la ligne produite par le code actuel (suffixe sur <nom>) : voir E1.