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
FilenameEntryvidé, 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:SecondsSinceStart425. 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 pageFTextLayout;: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
ScriptCoreniProcessEvent(:104-248). Le GrepScript|Blueprint|CharGen|ExecuteUbergraphsur le rapport ne trouve que des noms de DLL (:2209et suivantes). LifePlay.logcompte 2 807 lignes (Grep, nombre). Sa dernière ligne est:2807(11:32:16 UTC, LogEOS).- La dernière ligne
LogScriptest:2801-2804(11:29:21) :GI_C:SavePreset, Accessed NoneCallFunc_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).
- Le fil du plantage ne contient aucune trame
- C'est le seul rapport de cette signature. Le Grep
FCachedTypefaceData::FCachedTypefaceData|SEditableText::SynchronizeTextStylesurSaved\Crashestrouve 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à_65etK2Node_VariableSet_1146/_1147sont 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.txtporte 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 ditGreater_IntInt(Len, 0); je ne l'ai pas relu ; - then →
K2Node_CallFunction_5375(enregistrement) ; - else →
K2Node_VariableSet_1147.
- execute ←
K2Node_VariableSet_1147(:1195450-1195460) : nœud Set deEditableTextBox.WidgetStylesurFilenameEntry(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_62et_64(EditableTextBoxStyle,:1192103-1192125et:1192136-1192158) : toutes leurs broches viennent deK2Node_BreakStruct_62, qui casseK2Node_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) ;FocusedForegroundColorn'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 :
TextStyleest recopié du style courant (:1184408→:1192118,:1192151). La couleur posée par STE-TXT est recopiée avec. - ERR-025 (
Make_64sans police) n'est pas présent : la brocheTextStylede_64est reliée, en 5.8 comme dans le dump 5.5 (L4-CX-B04_dump_apres_CharGen_EventGraph.txt:1063). - ERR-021 : la broche
Fontn'existe plus sur ce Make (ShowPinForPropertiessansFont,:1192105) ; le membre s'appelle désormaisFont_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 deEditableTextBox.WidgetStyle: CharGen_1146/_1147et StatMenu_1146/_1147(:1415089-1415110). S'y ajoutent leurs copiesExecuteUbergraph_*. 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 :
-
WidgetStylea 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 deSetter(UE_5.5\…\EditableTextBox.h:48-49).- Le setter s'appelle par défaut
Set+ nom de la propriété, soitSetWidgetStyle(Programs\Shared\EpicGames.UHT\Types\UhtClass.cs:1199,:1203). - Ce n'est pas une UFUNCTION (
EditableTextBox.h:261), donc il n'y a pas deBlueprintSetter. La compilation Kismet ne remplace un nœud Set que pour unBlueprintSetter(Editor\BlueprintGraph\Private\K2Node_VariableSet.cpp:501-519) : le nœud reste un Set.
- Le setter s'appelle par défaut
-
La VM appelle ce setter, à travers une valeur temporaire. Dans
UObject::execLet, quandHasSetter()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_InContainerpasse parCallSetter(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). - une valeur temporaire est allouée sur la pile virtuelle de la VM (
-
UEditableTextBox::SetWidgetStyledonne à Slate l'adresse de son paramètre. Il copie le style dans le membre, puis appelleMyEditableTextBlock->SetStyle(&InStyle)(Runtime\UMG\Private\Components\EditableTextBox.cpp:392-398).SynchronizePropertiesdonne au contraire&WidgetStyle(:133). -
SEditableTextBox::SetStylegarde ce pointeur. Il enregistreStyle = InStyle, ainsi que les pointeursBorderImage*qui visent l'intérieur de ce style (Runtime\Slate\Private\Widgets\Input\SEditableTextBox.cpp:113-131). Après l'étape 2,Stylevise une temporaire détruite : le pointeur pend. -
Le Prepass suivant relit la police à travers ce pointeur. L'attribut
FontdeSEditableTextest lié àSEditableTextBox::DetermineFont(SEditableTextBox.cpp:65), qui renvoieStyle->TextStyle.Font(:342-346).- Quand cette valeur change, l'attribut appelle
SynchronizeTextStyle(SEditableText.cpp:37-38; pileCrashContext:118-121). SynchronizeTextStylerecopie 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), puisGetDefaultFontData, puisInFontInfo.GetCompositeFont()(FontCacheCompositeFont.cpp:504-509).
- Quand cette valeur change, l'attribut appelle
-
Quelle donnée est fausse : ce n'est pas une police « vide ».
- Une
FSlateFontInfovalide sansFontObjectniCompositeFontrenvoie la police de dernier recours ounullptr(SlateFontInfo.cpp:192-207,LegacySlateFontInfoCache.cpp:313-325).nullptrest 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 parcourantFonts(:90-93) à l'adresse 0 : un tableau aux données nulles mais de taille non nulle. Cela n'existe pas dans unFCompositeFontvivant. - Estimé : l'objet lu n'est pas un
FCompositeFontvalide mais de la mémoire réutilisée. C'est cohérent avec une police lue à travers le pointeur pendant de l'étape 4.
- Une
-
La couleur ne joue pas.
GetMaxHeightne reçoit que la police (SlateFontRenderer.cpp:200).- La branche couleur de
SynchronizeTextStylen'agit que si un attributColorAndOpacityest posé (SEditableText.cpp:553-562,:386).SEditableTextBoxn'en passe aucun (SEditableTextBox.cpp:61-93). - La couleur de STE-TXT est copiée avec le reste de
TextStyledans la temporaire. Elle ne crée ni n'évite le pointeur pendant.
-
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&WidgetStylereçue parSynchronizeProperties, 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) :
- Aucun ticket Epic trouvé sur ce mécanisme.
- Un fil de forum 5.7 décrit un plantage quand on réapplique au runtime le style d'une EditableTextBox par le nœud Set. Il ne donne ni pile ni réponse : https://forums.unrealengine.com/t/editing-the-font-size-of-an-editable-text-box-is-still-not-available-not-working-since-2022/2832618
- UE-147566 : style d'Editable Text modifié au runtime mais non reflété (5.0, corrigé en 5.2 selon le résumé de recherche). La page renvoie HTTP 403 et n'a pas été lue : https://issues.unrealengine.com/issue/UE-147566
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 WidgetStyled'une EditableTextBox exécuté par un Blueprint laisseSEditableTextBox::Stylesur 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.SynchronizePropertiesest publique (Widget.h:938,EditableTextBox.h:270) et redonne à Slate l'adresse du membre (EditableTextBox.cpp:133). WidgetStyleest public et non déprécié en 5.8 (EditableTextBox.h:50-52). En 5.5, à vérifier en BUILD (:47-49, sectionpublicestimé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 : cibleFilenameEntry, style issu deK2Node_MakeStruct_62ou_64. Cela modifie le graphe : il faut une nouvelle fiche (STE-TXT.md§ 6). - À vérifier en VAL :
SynchronizePropertiesréapplique le texte par sa liaison (EditableTextBox.cpp:130-134) ; le texte saisi doit être conservé.
- Écrire directement le membre évite
- 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 :
SetWidgetStyledevrait passer&WidgetStyleet non&InStyle. Sans effet tant que le moteur installé n'est pas corrigé. - Registre : réserver une ligne ERR. Signature : AV
FCachedTypefaceDatasousSEditableText::SynchronizeTextStyle, après un nœudSet WidgetStyled'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 statusdu jeu : seul CharGen est modifié dansContent). 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.dmpau débogueur avec les symboles 5.8.3, et vérifier queSEditableTextBox::Stylepointe hors de l'objetUEditableTextBox.
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.mdn'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 aveccd /d/, sans fichier écrit. - Une passe
difflibsur tout l'ubergraph (tâche de fondbnwu14rk3) 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.