16 KiB
Fiche U7-T9 — Niveau N3 — Modèle prévu lp-impl (Opus xhigh) | utilisé Opus 5.5 (claude-opus-5-5) — Agent lp-impl — Skills ue-cpp-build, sk-protocol (lp-build, lp-ue-compat préchargés)
Marquage, dans le gestionnaire de mods, des lignes de mods refusés par la garde U7 (copie D:\Game\LifePlay-master 5.8,
branche ue5.8). Décision utilisateur : C++ seulement, aucun Blueprint modifié.
Statut : proposé, non compilé (BUILD = fiche séparée). Ni jeu, ni éditeur, ni commandlet, ni compilation lancés. Aucun commit.
1. Résultat
PASS-STATIC proposé (à recompter par la VAL). Critère d'arrêt (§ 9) non atteint : la ligne est identifiable sans Blueprint, et la reconstruction du widget ne rend pas le marquage instable (§ 3).
- Ligne d'un mod refusé : nom suffixé « (not loaded) », ligne teintée rouge atténué, infobulle « Not loaded: <raisons
anglaises de la fenêtre> », case
ModEnabledBoxdésactivée.GI.ModEnabledsn'est pas touché (choix du joueur conservé). - Idempotent : marque reconnue à la teinte de la ligne, suffixe protégé par
EndsWith; tri et images suivantes sans effet. - Une ligne Display par ouverture :
Modules : gestionnaire, N mod(s) refuse(s) marque(s). - Aucun mod refusé : aucun ticker ajouté (coût nul).
2. Widget et propriétés (lecture seule des relevés, aucun outil lancé)
| Élément | Preuve | Niveau |
|---|---|---|
Gestionnaire /Game/UI/ModManager (classe ModManager_C), liste ModScrollBox (ScrollBox, variable) |
etat/L6e-CX-B09_widgets_apres.txt:14811, :14838 ; nom de classe ModManager_C : Source/LifePlay/LPDirectControlSubsystem.cpp:53 |
établi |
Ligne /Game/UI/ModuleTick : ModEnabledBox (CheckBox), HoverButton (Button) contenant NameText et AuthorText (TextBlock, variables), UpButton, DownButton |
etat/L6e-CX-B09_widgets_apres.txt:14934, :14945, :14955, :14972, :14985, :14998, :15014 |
établi |
Création à chaque ouverture : GI.CreateModManagerWidget → CreateWidget → AddToViewport ; fermeture RemoveFromParent |
etat/DOC-MOD_LPDumpFunction_20261007-083554.txt:1484, :1489, :1508 ; bouton titre → même événement : Source/LifePlayEditorTools/LPTitleModManagerCommandlet.cpp:295-296 |
établi |
Par .lpmod : CreateWidget ModuleTick, FullString = fichier, UniqueID = ligne 1 après : (Trim, TrimTrailing) = MODULE_UNIQUEID, CheckIfModAlreadyFound, NameText.SetText (ligne 2), AuthorText.SetText (ligne 3), ajout à TempModuleTicks |
083554.txt:1561, :1573, :1579, :1639, :1644, :3413 |
établi |
Lignes ajoutées en bloc après la boucle (AddTempModuleTicks, dans l'ordre de ModEnableds) |
083554.txt:3437, :3482 |
établi |
Tri (▲/▼, SortLoadOrder) : Array_Swap(ModEnableds), ModScrollBox.ClearChildren, AddTempModuleTicks = mêmes objets remis |
083554.txt:3497, :3501 |
établi |
CheckIfModAlreadyFound fixe la variable ModEnabled de la ligne depuis ModEnableds (aucun SetIsChecked) |
etat/L6f_dump_GI.txt:153, :179 |
établi |
ModuleTick, un seul graphe (EventGraph, 48 nœuds) : case → ModEnabled → GI.ToggleMod(UniqueID) ; un 2ᵉ événement inverse ModEnabled et appelle ToggleMod |
etat/DOC-MOD_LPDumpFunction_20261007-083154.txt:9-12 ; 083338.txt:141, :165, :182, :191, :211 |
établi |
Ce 2ᵉ événement = HoverButton.OnClicked ; la case affiche ModEnabled par une liaison de propriété (pas de graphe de liaison) |
déduit : seul bouton restant hors ▲/▼ et survol ; aucun SetIsChecked dans le graphe |
estimé |
Pocolov : dossier lpr_hair_pocolov, MODULE_UNIQUEID: lpr_hair_pocolov, MODULE_NAME: Pocolov Hairstyles, MODULE_AUTHOR: LifePlay Revival (hairstyles by Pocolov) |
D:\Game\LifePlay_Build_5.8_U7_P10\Windows\LifePlay\Content\Modules\lpr_hair_pocolov\lpr_hair_pocolov.lpmod:1-3 |
établi |
| Pocolov refusé et coché par défaut | ...\P10\Windows\LifePlay\Saved\Logs\LifePlay.log:827 (refus), :887 (« actif par defaut (MODULE_DEFAULT_ENABLED), ajoute a la liste des mods ») |
établi |
3. Mécanisme retenu, stabilité
- Ticker
FTSTickerà chaque image (0.f, commeLPSettingsSubsystem.cpp:437), ajouté seulement si au moins un mod est refusé. Recherche parTObjectIterator<UScrollBox>(requête par classe,UObjectIterator.h:251-265) deModScrollBoxdont le propriétaire est unModManager*au viewport (UWidget::IsInViewport) de cette instance de jeu : une instance fermée (en attente de GC) est écartée. - Pour chaque enfant
ModuleTick*: variable BlueprintUniqueIDlue par réflexion (FStrProperty), recherchée dans une tableRefusedTipsconstruite à l'initialisation depuisFLPModGuard::GetVerdicts()(clés : nom du plugin etMODULE_UNIQUEIDdu.lpmod;FString: égalité et hachage sans casse,UnrealString.h.inl:910-912,:2129-2132, comme leEqualEqual_StriStridu Blueprint). - Stabilité : les marques sont des propriétés UMG des objets (
Text,ColorAndOpacity,bIsEnabled,ToolTipText), réappliquées à toute reconstruction Slate (UserWidget.cpp:406-422,Widget.cpp:321-333,:526-536,TextBlock.cpp:469-478). Tri = mêmes objets → marques conservées ; réouverture = nouveaux objets → marqués à la première image. Le Blueprint n'écritNameTextqu'à la création (avant l'ajout à la liste) : pas d'écrasement constaté. - Le marquage a lieu entre deux images (ticker), jamais au milieu de l'exécution Blueprint qui remplit la liste.
4. API moteur lues (UE 5.8.3, D:\Game\Launcher\Engine\UE_5.8\Engine\Source)
| API | Source |
|---|---|
UWidget::IsInViewport (vrai si ajouté par AddToViewport) |
Runtime/UMG/Public/Components/Widget.h:547-549, Private/Components/Widget.cpp:344-354 ; AddToViewport → sous-système UserWidget.cpp:1366-1378, drapeau Blueprint/GameViewportSubsystem.cpp:158, :214 |
UWidget::SetIsEnabled, SetToolTipText, GetGameInstance |
Widget.h:545, :556, :871 ; Widget.cpp:321-333, :526-536 |
UUserWidget::SetColorAndOpacity (« affects all child widgets »), GetColorAndOpacity, GetWidgetFromName |
Blueprint/UserWidget.h:1050-1061, :1426 ; UserWidget.cpp:427-441, :1259-1262 ; réappliqué :406-422 |
UTextBlock::GetText, SetText |
Components/TextBlock.h:95, :103 ; TextBlock.cpp:457-478 |
UPanelWidget::GetChildrenCount, GetChildAt |
Components/PanelWidget.h:28, :36 |
| Infobulle : chemin sous le curseur y compris widgets désactivés, de la feuille vers la racine, 1ʳᵉ infobulle non vide | Runtime/Slate/Private/Framework/Application/SlateUser.cpp:1350-1386 |
FStrProperty : en-tête UObject/StrProperty.h (inclus par UnrealType.h seulement si UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_7, UnrealType.h:7806-7816 ; la copie 5.8 est en Unreal5_8, Source/LifePlay.Target.cs:12) ; GetPropertyValue_InContainer |
CoreUObject/Public/UObject/StrProperty.h:1-19, StrProperty.h.inl:27-29, UnrealType.h:1663 ; existe aussi en 5.5 (UE_5.5/.../UObject/StrProperty.h) |
FName comparé à const TCHAR* |
Core/Public/UObject/NameTypes.h:1362, :1413-1417 (précédent du fichier : RowNames[0]) |
constexpr FLinearColor, operator== |
Core/Public/Math/Color.h:130, :332 ; précédent moteur Developer/LogVisualizer/Private/SVisualLoggerFilterWidget.h:133 |
FTSTicker::RemoveTicker sans effet sur une poignée vide |
Core/Private/Containers/Ticker.cpp:39-58 (Handle.Pin() nul) |
5. Modifications par fichier (numéros après modification)
| Fichier (EOL) | Lignes | Modification |
|---|---|---|
Source/LifePlay/LPModInfoSubsystem.h (LF) |
17-21 | En-tête : 4ᵉ rôle du sous-système (gestionnaire de mods, aucun Blueprint modifié) |
| idem | 31 | class UScrollBox; |
| idem | 60-61 | bool TickModManager(float DeltaTime); |
| idem | 71-77 | RefusedTips, ManagerTickHandle, ManagerList (faible), bManagerListLogged, bWarnedNoUniqueId |
Source/LifePlay/LPModInfoSubsystem.cpp (LF) |
25 | #include "UObject/StrProperty.h" |
| idem | 84-118 | LPModInfoUi : noms ModScrollBox / ModManager / ModuleTick, suffixe, teinte RefusedTint (0.75, 0.28, 0.28, 0.9), MarkRefusedRow (teinte, infobulle, suffixe si absent, case désactivée ; faux si déjà marquée) |
| idem | 151-172 | Initialize : table RefusedTips (raisons FLPModVerdict::Reasons jointes par « ; »), ticker par image seulement si la table n'est pas vide |
| idem | 178 | Deinitialize : retrait du ticker |
| idem | 318-383 | TickModManager : liste à l'écran, lignes, UniqueID, marquage, Warning unique si UniqueID absent, ligne Display |
Rien d'autre : LPSettingsSubsystem.cpp, LPModGuard.*, Blueprints, Build.cs inchangés (UMG et CoreUObject déjà en
dépendance). Correctifs UE4 (LPStringCompat, LPMeshCompat, LPNavigationHelpers…) non touchés.
6. Diff, fins de ligne, contrôles statiques
T9 seul (état T7 copié avant modification dans
%USERPROFILE%\AppData\Local\Temp\claude\D--Game-LifePlay-master-5-5\ab8918a1-261f-45b4-904a-678ecfce98f7\scratchpad\t9\avant\,
diffs ..\T9_LPModInfoSubsystem.cpp.diff 165 lignes, ..\T9_LPModInfoSubsystem.h.diff 47 lignes) :
git diff --no-index --stat <avant>/LPModInfoSubsystem.cpp Source/LifePlay/LPModInfoSubsystem.cpp 1 file changed, 128 insertions(+)
git diff --no-index --stat <avant>/LPModInfoSubsystem.h Source/LifePlay/LPModInfoSubsystem.h 1 file changed, 16 insertions(+), 1 deletion(-)
git -C "D:\Game\LifePlay-master 5.8" diff --stat (cumul U7 contre HEAD) :
Config/DefaultGame.ini | 2 +-
Source/LifePlay/LPHairstyleSubsystem.cpp | 13 ++
Source/LifePlay/LPHairstyleSubsystem.h | 2 +
Source/LifePlay/LPModDailies.cpp | 7 +
Source/LifePlay/LPModDailies.h | 2 +
Source/LifePlay/LPModInfoSubsystem.cpp | 332 ++++++++++++++++++++++++++-----
Source/LifePlay/LPModInfoSubsystem.h | 36 +++-
Source/LifePlay/LPSettingsSubsystem.cpp | 5 +
Source/LifePlay/LifePlay.cpp | 15 +-
9 files changed, 361 insertions(+), 53 deletions(-)
(avant T9 : LPModInfoSubsystem.cpp | 208, .h | 21, total 220+/55− ; seules ces deux lignes changent.)
git status --short : 9 M + 2 ?? (LPModGuard.*, T7), inchangé en nombre ; copie 5.5 : vide ; addon 5.8 : M Tools/BuildMod.ps1 (T7).
Fins de ligne relues octet par octet (Python, count(b'\n'), count(b'\r\n'), octets > 127) :
| Fichier | Avant T9 | Après T9 | Non-ASCII | BOM | Fin de fichier |
|---|---|---|---|---|---|
LPModInfoSubsystem.cpp |
LF 314 / CRLF 0 | LF 442 / CRLF 0 | 0 = 0 | non | LF |
LPModInfoSubsystem.h |
LF 63 / CRLF 0 | LF 78 / CRLF 0 | 2 = 2 (§ l. 1) |
non | LF |
Noms nouveaux uniques dans Source/ (grep -rln "MarkRefusedRow\|TickModManager\|RefusedTint\|NotLoadedSuffix\|ManagerListName" →
les 2 fichiers seulement) ; tout dans l'espace de noms nommé LPModInfoUi (pas de collision unity).
7. Journal attendu (jeu cuit, Pocolov 5.5 dans Mods/)
Démarrage, inchangé (T7) : Modules : lpr_hair_pocolov refuse : moteur : conteneur 4 (jeu 5), registre 17 (jeu 24) ; …,
puis … non charge : 1 pak(s) demonte(s) …, puis la fenêtre Modules : fenetre d'avertissement, 1 mod(s) refuse(s).
Nouveau, une fois par ouverture du gestionnaire :
LogLifePlay: Display: Modules : gestionnaire, 1 mod(s) refuse(s) marque(s)
Aucune ligne au tri (▲/▼) ni aux images suivantes. Ne doivent pas apparaître :
Modules : gestionnaire, variable UniqueID absente de ModuleTick_C … (Warning : lignes non marquées) ; … 0 mod(s) …
alors que Pocolov est dans la liste (clé UniqueID non reconnue). Sans mod refusé : aucune ligne « gestionnaire ».
8. Plan d'essai (après BUILD par lp-builder et empaquetage ; jeu de référence LifePlay_Build_5.8_U7_P10)
Le jeu P10 est empaqueté : le code T9 n'y est pas. Compilation .\Tools\Build.ps1 -Lot U7, puis empaquetage Development
(Tools\BuildDebug.ps1) vers un dossier neuf (ex. LifePlay_Build_5.8_U7_P11) avec le même Mods\lpr_hair_pocolov
(cuit 5.5) et le même Content\Modules\lpr_hair_pocolov. Sauvegardes du joueur mises de côté comme en P10.
- Lancer ; fenêtre « Mod compatibility warning » → OK (non-régression T7).
- Écran titre → Mod Manager. Attendu : « Pocolov Hairstyles (not loaded) », ligne teintée rouge atténué, case grisée dans l'état choisi (cochée ici), auteur inchangé ; les autres lignes inchangées. Capture même cadrage que la capture utilisateur.
- Survol de la ligne (nom ou case) : infobulle
Not loaded: built with an older engine (format 4, game 5): rebuild the mod for LifePlay 2026.10.2.0; le panneau de détail montre toujours le.lpmod(survol Blueprint intact). - Clic sur la case : sans effet. Clic sur le nom : noter si la coche change (point ouvert § 9.6).
- ▲/▼ sur Pocolov puis sur une autre ligne : marque conservée, pas de double suffixe, aucune nouvelle ligne de journal.
- Confirm, rouvrir : marque présente dès l'ouverture, une nouvelle ligne Display, pas de double suffixe.
- Relancer le jeu : Pocolov toujours dans la liste avec le choix laissé (ModEnableds non modifié par le C++).
- Journal : compter
Modules : gestionnaire(= nombre d'ouvertures) ; aucun Warning « UniqueID absente ». - Non-régression sans mod refusé :
Mods\lpr_hair_pocolovdéplacé (versBackup_5.5\U7) → gestionnaire normal, aucune ligne « gestionnaire ». Ne pas lever le contrôle Moteur avec Pocolov 5.5 (plantage T4).
9. Écarts à la fiche et points ouverts
- Identification :
FLPModGuard::GetVerdicts()au lieu deIsRefused(<id>)(même source, donne aussi les raisons de l'infobulle) ; clé double nom du plugin +MODULE_UNIQUEID(la ligne porteMODULE_UNIQUEID, la garde le nom du plugin ; égaux pour Pocolov, établi § 2). - Infobulle : préfixe « Not loaded: » devant les raisons jointes par « ; » (repli « see the mod compatibility warning » si la liste était vide, cas non attendu).
- Teinte appliquée à toute la ligne (
UUserWidget::SetColorAndOpacity: texte, case, flèches), pas seulement au texte. - Ligne de journal écrite aussi avec N = 0 à l'ouverture (diagnostic) ; Warning unique ajouté si
UniqueIDmanque. - Ticker dédié par image, enregistré seulement s'il y a un mod refusé ; le ticker 0,5 s existant est inchangé.
- Point ouvert : le clic sur le nom (
HoverButton, estimé § 2) appelle toujoursGI.ToggleMod: le joueur peut encore changer son choix enregistré, et la case désactivée suivrait la liaison. Rien n'est chargé pour autant (garde au démarrage). Options si l'orchestrateur veut l'empêcher : (a) laisser ainsi (choix du joueur, recommandé) ; (b)HoverButton->SetIsEnabled(false)(perte probable du survol qui affiche le.lpmod, à vérifier) ; (c) retirer le délégué BlueprintOnClickedde la ligne (intrusif). Non fait sans décision. - Observation hors périmètre :
LPHairstyleSubsystemajoute un mod refusé à la liste des mods actifs par défaut (MODULE_DEFAULT_ENABLED, journal P10 l. 887) : c'est pourquoi Pocolov apparaît coché.
10. Compte rendu (sk-protocol)
[sk-protocol] Skills présents : sk-protocol, ue-cpp-build, lp-build, lp-ue-compat.
- Résultat : réussi (PASS-STATIC proposé, non compilé) ; 2 fichiers modifiés, aucun Blueprint.
- Preuves : § 2 (relevés
etat/), § 4 (sources moteur 5.8fichier:ligne). - Chiffres : T9 = +128 (
.cpp), +16/−1 (.h) (git diff --no-index --stat) ; EOL LF conservées (442 et 78 lignes, 0 CRLF). - Incertitudes : identité du 2ᵉ événement (
HoverButton) et liaison de la case : estimées ; rendu (teinte, infobulle) : à voir en jeu (§ 8) ; compilation non faite. - Écarts : § 9 ; fichiers écrits :
D:\Game\LifePlay-master 5.8\Source\LifePlay\LPModInfoSubsystem.cpp,D:\Game\LifePlay-master 5.8\Source\LifePlay\LPModInfoSubsystem.h, ce livrable. - Suite : lp-builder doit compiler la copie 5.8 (
.\Tools\Build.ps1 -Lot U7) puis empaqueter pour l'essai § 8, état : code T9 écrit, non compilé, non commité.