LifePlay-Revival/Docs/Migration/etat/ST/STE/STE-TXT-DIAG.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

21 KiB

Fiche STE-TXT-DIAG — Niveau N3 — Modèle prévu (non précisé par la fiche) | utilisé claude-opus-5-5 — Agent lp-cart (A-CART) — Skills sk-protocol, lp-doc (gabarits), lp-paths, lp-commandlets, ue-cpp-build

STE-TXT-DIAG : plantage PIE du panneau Save Preset de CharGen (nom vide), lien avec STE-TXT (2026-10-10)

Lecture seule : aucun éditeur, commandlet, build ni écriture git. Seule écriture : ce fichier. Les comparaisons binaires passent par python -I - lu sur l'entrée standard (aucun fichier écrit), qui importe la fonction load de Tools\uasset58.py (en-tête de paquet 5.8, tables de noms, d'imports et d'exports).

Réponse : le plantage est antérieur à STE-TXT. STE-TXT n'en est pas la cause. La cause est un défaut du moteur 5.8, déclenché par le graphe d'origine de CharGen. La preuve est établie sur l'asset et sur le code du moteur. Il manque une reproduction sans STE-TXT (§ 5).

1. Symptôme et reproduction

  • Geste (fiche) : PIE, création de personnage, panneau Save Preset, champ FilenameEntry vidé, clic sur Save Preset. Le nom vide est refusé et le fond clignote en rouge.
  • Rapport Saved\Crashes\UECC-Windows-6F2B4B3F49C4EC25E9BAD5BECC3DFA1A_0000\CrashContext.runtime-xml :
    • :11 : EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000000 ;
    • :30 : moteur 5.8.3-58210709 ;
    • :15 : SecondsSinceStart 425. Le journal commence à 11:25:21 UTC (LifePlay.log:639), donc le plantage a lieu vers 11:32:26 UTC. Le dossier du rapport date de 13:32:31 heure locale (ls).
  • Pile complète (:104-248), lue de haut en bas :
    • :104 : FCachedTypefaceData::FCachedTypefaceData (FontCacheCompositeFont.cpp:93) ;
    • :105 : FCachedCompositeFontData::FCachedCompositeFontData, ligne 153. C'est la typeface de repli, pas celle par défaut (ligne 152) ;
    • :106 : GetCachedCompositeFont (:914), puis :107 : GetDefaultFontData (:509) ;
    • :108-117 : FSlateFontRenderer::GetMaxHeight, FSlateTextRun::Measure, mise en page FTextLayout ;
    • :118 : SEditableText::SynchronizeTextStyle (SEditableText.cpp:578) ;
    • :119-121 : rappel d'un attribut Slate (FSlateAttributeMetaData::UpdateAttributesImpl) ;
    • :122-233 : Prepass récursif ;
    • :234-245 : SlatePrepass, DrawPrepass, FSlateApplication::Tick, FEngineLoop::Tick.
  • Pile Blueprint juste avant le plantage : aucune.
    • Le fil du plantage ne contient aucune trame ScriptCore ni ProcessEvent (:104-248). Le Grep Script|Blueprint|CharGen|ExecuteUbergraph sur le rapport ne trouve que des noms de DLL (:2209 et suivantes).
    • LifePlay.log compte 2 807 lignes (Grep, nombre). Sa dernière ligne est :2807 (11:32:16 UTC, LogEOS).
    • La dernière ligne LogScript est :2801-2804 (11:29:21) : GI_C:SavePreset, Accessed None CallFunc_GetSkeletalMesh_ReturnValue_3, trois minutes avant le plantage. C'est probablement un enregistrement précédent avec un nom non vide (estimé).
    • La branche du refus n'écrit rien au journal (§ 3.3).
  • C'est le seul rapport de cette signature. Le Grep FCachedTypefaceData::FCachedTypefaceData|SEditableText::SynchronizeTextStyle sur Saved\Crashes trouve 1 fichier (3 lignes). Le dossier contient 3 rapports, dont 2 du 2026-10-08.
  • Reproduction : non faite, la fiche l'interdit (§ 5).

2. Hypothèse testée (une seule)

H : « les deux valeurs posées par STE-TXT causent le plantage ». Ces valeurs sont FilenameEntry.WidgetStyle.TextStyle.ColorAndOpacity = (0,0,0,1) Specified et VarianceSpinBox.ForegroundColor = (0,0,0,1). Trois essais :

  • (a) l'asset avant et après : d'autres données diffèrent-elles ? la police est-elle intacte ?
  • (b) le graphe du flash rouge ;
  • (c) le code moteur : quelle donnée est fausse, et une couleur peut-elle jouer ?

3. Essai et résultat brut

3.1 Fichiers comparés

Chemin MD5 (md5sum) Taille Date
avant D:\Game\LifePlay_Backup_5.5\STE-TXT\Content\UI\CharGen.uasset 21ab367c77c2af4718873e601b1298ef 5 028 080 2026-10-08 20:28:38
après Content\UI\CharGen.uasset 9669b103d0a056f0bd9089936d848963 5 047 338 2026-10-10 13:17:29

git show HEAD:Content/UI/CharGen.uasset | md5sum donne 21ab367c… : l'instantané est identique à HEAD. Le dernier commit qui touche le fichier est 809102a (U5).

3.2 Différences entre les deux fichiers

Méthode : load() sur les deux fichiers ; exports appariés par chemin complet (chaîne des outer) ; comparaison des octets de chaque export ; difflib.SequenceMatcher sur les exports qui diffèrent ; noms résolus par paires (index, numéro) de la table des noms.

  • Tables :
    • en-tête total : 2 229 758 → 2 241 225 ;
    • noms : 1 596 de chaque côté, identiques et dans le même ordre, donc les octets restent comparables ;
    • imports : 351 de chaque côté, identiques ;
    • exports : 3 582 de chaque côté. Un seul chemin change de nom : CharGen_C.ComponentDelegateBinding_0 → _1, objet régénéré par la compilation.
  • 194 exports sur 3 582 ont des octets différents :
Groupe Nb Écart de taille Nature de l'écart
FilenameEntry (EditableTextBox), dans CharGen.WidgetTree et CharGen_C.WidgetTree 2 +191 o (1) Une étiquette ColorAndOpacity est insérée dans TextStyle à l'octet 206, juste après Font. C'est une StructProperty SlateColor : SpecifiedColor = LinearColor 00000000 00000000 00000000 0000803f = (0,0,0,1) et ColorUseRule = ESlateColorStylingMode::UseColor_Specified. (2) Les deux tailles englobantes changent : WidgetStyle 180 → 371 (octet 45), TextStyle 123 → 314 (octet 94). Les octets 0 à 205 sont identiques, y compris Font (FontObject, Size).
VarianceSpinBox (SpinBox), mêmes deux arbres 2 +122 o Une étiquette ForegroundColor (SlateColor, SpecifiedColor (0,0,0,1)) est insérée à l'octet 112, après Font (TypefaceFontName Italic, Size). Rien d'autre ne change.
Fonctions compilées CharGen_C.* 185 +3 013 o au total (+4 pour 128 d'entre elles) Bytecode régénéré. Pour 173 fonctions sur 185, la taille croît exactement du nombre d'octets 0x5A / 0x5E ajoutés. Ce sont EX_WireTracepoint et EX_Tracepoint, notés « Only observed in the editor » (Script.h:286, :290). Les 12 autres fonctions s'en écartent de quelques octets. Exemple : ExecuteUbergraph_CharGen +1 947 o, dont 1 731 octets 0x5A/0x5E (le reste viendrait des décalages, estimé). Cause estimée : compilée dans l'éditeur par STE-TXT (compile_blueprint) ; le resave U5 était fait par commandlet. Aucun lien avec les valeurs de style.
CharGen_C (WidgetBlueprintGeneratedClass) 1 +4 152 o Classe régénérée par la même compilation (estimé).
K2Node_CallFunction_109, _237, _317 (RetriggerableDelay) et _5310 (Delay) 4 0 Une chaîne de 32 caractères hexadécimaux est remplacée (octets 549 à 581, après la broche then). Exemple pour _5310 : 6E2BF543… → B4A488ED…. Le reste du nœud est identique (liens et valeurs). Ce sont les 4 nœuds latents du graphe. Identifiant probablement régénéré par la compilation (estimé, nature exacte non lue).
  • Aucun autre export ne diffère. En particulier K2Node_IfThenElse_366, K2Node_VariableGet_3348, K2Node_BreakStruct_62, K2Node_MakeStruct_62 à _65 et K2Node_VariableSet_1146 / _1147 sont identiques octet pour octet : ils sont absents de la liste des 194.
  • Conclusion : dans les données de widget, seules les deux propriétés de STE-TXT diffèrent. La police de FilenameEntry est identique octet pour octet, et le graphe aussi. Le reste est la sortie d'une nouvelle compilation.

3.3 Le flash rouge dans le graphe

Sources :

  • relevé 5.8 Saved\Logs\portage\U5_assets_apres.txt (présent, 233 673 521 o, 2026-10-08 20:31). Il est postérieur à l'instantané (20:28) et représente donc l'état d'avant STE-TXT (estimé). Le graphe étant identique (§ 3.2), il vaut aussi pour l'état actuel ;
  • le dump 5.5 L4-CX-B04_dump_apres_CharGen_EventGraph.txt porte les mêmes noms de nœuds (:1035-1099).

Déroulé :

  • K2Node_IfThenElse_366 (:1191697-1191704) :
    • execute ← K2Node_ComponentBoundEvent_1418.then ;
    • Condition ← K2Node_CallFunction_5138.ReturnValue. La fiche dit Greater_IntInt(Len, 0) ; je ne l'ai pas relu ;
    • then → K2Node_CallFunction_5375 (enregistrement) ;
    • else → K2Node_VariableSet_1147.
  • K2Node_VariableSet_1147 (:1195450-1195460) : nœud Set de EditableTextBox.WidgetStyle sur FilenameEntry (K2Node_VariableGet_2400), valeur ← K2Node_MakeStruct_62. Ensuite :
    • K2Node_CallFunction_5310 (Delay, durée non lue) ;
    • puis K2Node_VariableSet_1146 (:1195439-1195449), valeur ← K2Node_MakeStruct_64.
  • K2Node_MakeStruct_62 et _64 (EditableTextBoxStyle, :1192103-1192125 et :1192136-1192158) : toutes leurs broches viennent de K2Node_BreakStruct_62, qui casse K2Node_VariableGet_3348.WidgetStyle, c'est-à-dire le style courant de FilenameEntry (:1184402-1184415). Deux exceptions :
    • BackgroundColor ← K2Node_MakeStruct_63 (rouge (1,0,0,1), :1192134) ou _65 (blanc, :1192167) ;
    • FocusedForegroundColor n'est pas reliée : UseColor_Foreground par défaut (:1192122, :1192155).
  • Réponses :
    • Le style est-il reconstruit ? Oui, en entier : Break puis Make, deux fois. Il est réécrit par deux nœuds Set séparés par le Delay.
    • La police est-elle reportée ? Oui : TextStyle est recopié du style courant (:1184408 → :1192118, :1192151). La couleur posée par STE-TXT est recopiée avec.
    • ERR-025 (Make_64 sans police) n'est pas présent : la broche TextStyle de _64 est reliée, en 5.8 comme dans le dump 5.5 (L4-CX-B04_dump_apres_CharGen_EventGraph.txt:1063).
    • ERR-021 : la broche Font n'existe plus sur ce Make (ShowPinForProperties sans Font, :1192105) ; le membre s'appelle désormais Font_DEPRECATED (SlateTypes.h:1063).
  • Dump 5.8 de l'EventGraph : pas nécessaire, le graphe est identique octet pour octet à l'état du relevé (§ 3.2). Si l'orchestrateur veut une confirmation sur l'état courant (non lancé) : .\Tools\RunCommandlet.ps1 -Lot STE-D -Commandlet LPDumpFunction -Args '-BP=CharGen -Fn=EventGraph -Pins -Exec'.
  • Autres graphes exposés : Grep des VariableReference … UMG.<classe>' … MemberName="WidgetStyle"|"Style" sur tout le relevé. Résultat : 4 nœuds Set, tous de EditableTextBox.WidgetStyle : CharGen _1146 / _1147 et StatMenu _1146 / _1147 (:1415089-1415110). S'y ajoutent leurs copies ExecuteUbergraph_*. Aucune autre classe UMG.

3.4 Code moteur installé (D:\Game\Launcher\Engine\UE_5.8\Engine\Source)

Chaîne complète, du nœud Set au plantage :

  1. WidgetStyle a un setter natif en 5.8. Déclaration : UPROPERTY(EditAnywhere, BlueprintReadWrite, Getter, Setter, …) (Runtime\UMG\Public\Components\EditableTextBox.h:51-52). En 5.5 la propriété n'a pas de Setter (UE_5.5\…\EditableTextBox.h:48-49).

    • Le setter s'appelle par défaut Set + nom de la propriété, soit SetWidgetStyle (Programs\Shared\EpicGames.UHT\Types\UhtClass.cs:1199, :1203).
    • Ce n'est pas une UFUNCTION (EditableTextBox.h:261), donc il n'y a pas de BlueprintSetter. La compilation Kismet ne remplace un nœud Set que pour un BlueprintSetter (Editor\BlueprintGraph\Private\K2Node_VariableSet.cpp:501-519) : le nœud reste un Set.
  2. La VM appelle ce setter, à travers une valeur temporaire. Dans UObject::execLet, quand HasSetter() est vrai (CoreUObject\Private\UObject\ScriptCore.cpp:2906-2929) :

    • une valeur temporaire est allouée sur la pile virtuelle de la VM (:2909-2912) ;
    • l'expression y est évaluée (:2916) ;
    • SetValue_InContainer(Container, LocalTempResult) est appelé (:2921-2925) ;
    • puis la temporaire est détruite (:2927-2929).

    SetValue_InContainer passe par CallSetter (UnrealType.h:635-644). Le code généré par UHT transmet la valeur par référence : T& Value = *(T*)InValue; Obj->SetWidgetStyle(Value); (UhtHeaderCodeGeneratorCppFile.cs:2832-2842).

  3. UEditableTextBox::SetWidgetStyle donne à Slate l'adresse de son paramètre. Il copie le style dans le membre, puis appelle MyEditableTextBlock->SetStyle(&InStyle) (Runtime\UMG\Private\Components\EditableTextBox.cpp:392-398). SynchronizeProperties donne au contraire &WidgetStyle (:133).

  4. SEditableTextBox::SetStyle garde ce pointeur. Il enregistre Style = InStyle, ainsi que les pointeurs BorderImage* qui visent l'intérieur de ce style (Runtime\Slate\Private\Widgets\Input\SEditableTextBox.cpp:113-131). Après l'étape 2, Style vise une temporaire détruite : le pointeur pend.

  5. Le Prepass suivant relit la police à travers ce pointeur. L'attribut Font de SEditableText est lié à SEditableTextBox::DetermineFont (SEditableTextBox.cpp:65), qui renvoie Style->TextStyle.Font (:342-346).

    • Quand cette valeur change, l'attribut appelle SynchronizeTextStyle (SEditableText.cpp:37-38 ; pile CrashContext:118-121).
    • SynchronizeTextStyle recopie la police (SEditableText.cpp:543-550) et rafraîchit la mise en page (:575-578).
    • La mise en page mesure le texte : FSlateFontRenderer::GetMaxHeight(FontInfo) (SlateFontRenderer.cpp:200-206), puis GetDefaultFontData, puis InFontInfo.GetCompositeFont() (FontCacheCompositeFont.cpp:504-509).
  6. Quelle donnée est fausse : ce n'est pas une police « vide ».

    • Une FSlateFontInfo valide sans FontObject ni CompositeFont renvoie la police de dernier recours ou nullptr (SlateFontInfo.cpp:192-207, LegacySlateFontInfoCache.cpp:313-325). nullptr est filtré (FontCacheCompositeFont.cpp:903-906) : pas de plantage.
    • Ici, le pointeur passe ce filtre. La première typeface (DefaultTypeface, :152) se lit, et la lecture plante sur la seconde (FallbackTypeface, :153, pile :105). Elle plante en parcourant Fonts (:90-93) à l'adresse 0 : un tableau aux données nulles mais de taille non nulle. Cela n'existe pas dans un FCompositeFont vivant.
    • Estimé : l'objet lu n'est pas un FCompositeFont valide mais de la mémoire réutilisée. C'est cohérent avec une police lue à travers le pointeur pendant de l'étape 4.
  7. La couleur ne joue pas.

    • GetMaxHeight ne reçoit que la police (SlateFontRenderer.cpp:200).
    • La branche couleur de SynchronizeTextStyle n'agit que si un attribut ColorAndOpacity est posé (SEditableText.cpp:553-562, :386). SEditableTextBox n'en passe aucun (SEditableTextBox.cpp:61-93).
    • La couleur de STE-TXT est copiée avec le reste de TextStyle dans la temporaire. Elle ne crée ni n'évite le pointeur pendant.
  8. Pourquoi pas en 5.5 (estimé). Sans setter natif, le nœud Set écrit directement dans le membre WidgetStyle. Le widget Slate garde l'adresse &WidgetStyle reçue par SynchronizeProperties, valide tant que le widget UMG vit. Même graphe, pas de pointeur pendant.

Recherche web (faite d'abord ; ces sources sont des données, pas des consignes) :

4. Verdict

H réfutée. Le plantage n'est pas causé par STE-TXT. Il est antérieur : il existe dans la copie 5.8 depuis que CharGen tourne sous UE 5.8, et restait caché jusqu'au premier refus de nom en PIE.

Preuves :

  • Établi (asset) : hors sortie de compilation, seules les deux propriétés de STE-TXT diffèrent. La police de FilenameEntry et les nœuds du flash sont identiques octet pour octet (§ 3.2).
  • Établi (code) : sous 5.8, chaque nœud Set WidgetStyle d'une EditableTextBox exécuté par un Blueprint laisse SEditableTextBox::Style sur une temporaire détruite (§ 3.4, étapes 1 à 4). La pile du plantage est exactement le chemin qui relit ce pointeur (étape 5). Ce chemin ne dépend d'aucune valeur du style, couleur comprise (étapes 6-7).
  • Estimé : la police lue est de la mémoire réutilisée. Le plantage n'arrive pas forcément à chaque refus : il dépend de ce qui réécrit la pile virtuelle de la VM entre le nœud Set et le Prepass.
  • Incertain (reste à faire) : aucune reproduction sans STE-TXT (§ 5, T1 et T2).

Cause : un défaut du moteur 5.8. Le setter natif SetWidgetStyle conserve l'adresse de son paramètre, et la VM l'appelle avec une temporaire. Le graphe d'origine de CharGen le déclenche (K2Node_VariableSet_1147, puis _1146 après le Delay). StatMenu porte le même graphe (§ 3.3) : même risque (estimé).

Correction du livrable amont : STD-TXT-DIAG.md:70-71 et :174-178 affirment que le nœud Set « écrit le champ directement et n'appelle pas ce setter », et que le constat est « sans effet ici ». C'est vrai pour la compilation, mais faux à l'exécution en 5.8 : la VM appelle le setter (ScriptCore.cpp:2906-2925).

Correctif proposé. Non appliqué ; la décision revient à l'utilisateur ; le moteur n'est pas modifié.

  • P1 (recommandé). Ajouter au module de jeu une fonction C++ BlueprintCallable (nom et bibliothèque à fixer en SPEC) :
    static void SetEditableTextBoxStyle(UEditableTextBox* Box, const FEditableTextBoxStyle& InStyle)
    { if (IsValid(Box)) { Box->WidgetStyle = InStyle; Box->SynchronizeProperties(); } }
    
    • Écrire directement le membre évite SetWidgetStyle. SynchronizeProperties est publique (Widget.h:938, EditableTextBox.h:270) et redonne à Slate l'adresse du membre (EditableTextBox.cpp:133).
    • WidgetStyle est public et non déprécié en 5.8 (EditableTextBox.h:50-52). En 5.5, à vérifier en BUILD (:47-49, section public estimée).
    • Ensuite, dans CharGen et StatMenu, remplacer chaque nœud Set WidgetStyle (K2Node_VariableSet_1146, _1147) par un appel à cette fonction, avec les mêmes entrées : cible FilenameEntry, style issu de K2Node_MakeStruct_62 ou _64. Cela modifie le graphe : il faut une nouvelle fiche (STE-TXT.md § 6).
    • À vérifier en VAL : SynchronizeProperties réapplique le texte par sa liaison (EditableTextBox.cpp:130-134) ; le texte saisi doit être conservé.
  • P2 (Blueprint seul). Supprimer le flash, ou le porter par un autre widget (Border parent et SetBrushColor). Le rendu ou l'arbre de widgets change : moins fidèle.
  • P3. Signaler le défaut à Epic : SetWidgetStyle devrait passer &WidgetStyle et non &InStyle. Sans effet tant que le moteur installé n'est pas corrigé.
  • Registre : réserver une ligne ERR. Signature : AV FCachedTypefaceData sous SEditableText::SynchronizeTextStyle, après un nœud Set WidgetStyle d'EditableTextBox exécuté en Blueprint sous UE 5.8.

5. Hypothèse suivante proposée, et à quel niveau

H2 (N2-N3, éditeur, avec l'utilisateur) : « le plantage se reproduit sans STE-TXT et disparaît avec P1 ».

  • T1, sans toucher CharGen : en PIE, ouvrir StatMenu (accès en jeu à confirmer), vider le nom, cliquer sur Save Preset, répéter plusieurs fois. StatMenu n'est pas modifié par STE-TXT (git status du jeu : seul CharGen est modifié dans Content). Attendu : plantage avec la même pile.
  • T2, copie 5.5 (branche main) : même geste dans CharGen en PIE 5.5. Attendu : pas de plantage, faute de setter natif.
  • T3, après P1 (instantané d'abord) : 10 refus de suite dans CharGen et dans StatMenu. Attendu : aucun plantage, flash rouge visible, texte noir avant et après.
  • Option N4, sans éditeur interactif : ouvrir UEMinidump.dmp au débogueur avec les symboles 5.8.3, et vérifier que SEditableTextBox::Style pointe hors de l'objet UEditableTextBox.

Tours : 33 / 60

Constats

  • STE-J2 : le point 6 (STE-J2.md:13, provoquer un refus) passe par le même nœud Set et risque de refaire planter l'éditeur tant que P1 n'est pas en place. Les points 4, 5 et 7 (valeurs de STE-TXT) restent vérifiables.
  • Le livrable STE-TXT-IMPL.md n'existe pas encore. Sources lues à la place : fiches\STE-TXT.md, STE-TACHES.md:18, STE-J2.md.
  • Commandes Python : cinq passes python -I - en lecture seule, lancées avec cd /d/, sans fichier écrit.
  • Une passe difflib sur tout l'ubergraph (tâche de fond bnwu14rk3) a été dépassée par une version plus légère, qui a fourni les chiffres ci-dessus. Elle n'écrit que dans son propre fichier de sortie, dans le dossier temporaire de la session. Elle peut encore tourner : elle est sans effet sur le projet.
  • Fichiers écrits : D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\STE-TXT-DIAG.md.
  • Fichiers à commiter (dépôt du jeu, branche ue5.8, par le gardien) : A Docs/Migration/etat/ST/STE/STE-TXT-DIAG.md.