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

27 KiB
Raw Blame History

Fiche STE-H4 — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-opus-5-5 — Agent lp-cart (DIAG, lecture seule) — Skills sk-protocol, lp-commandlets (lecture), lp-paths ; ue-cpp-build préchargé, non utilisé ; lp-doc (gabarits)

STE-H4-DIAG : F5 « No SkeletalMesh », cause, coût et voies comparées (2026-10-11)

Résultat : hypothèse confirmée. F5 = lectures de sockets sur le CharacterMesh0 vidé des mannequins en réserve (100 % des 20 488 lignes, entre un DESTROY et le SPAWN suivant). 69 % viennent du moteur lui-même (mise à jour des 5 composants du Blueprint Person attachés à des sockets quand l'acteur bouge), 31 % d'un lecteur CenterBrow (suivi de tête). Coût mesuré dans J5 : nul. 3 765 trames ne portent que des lignes F5, sans autre marqueur : médiane 17 ms, maximum 47 ms, aucune ≥ 50 ms. F5 n'explique pas les saccades. Les 90 trames longues de J5 tombent sur le SPAWN (52), la fin de scène (DESTROY, 13), le CHECKING: (14), le chargement (3) et les clics d'interface (5). Aucun éditeur, commandlet, build ni jeu ; seul ce fichier est écrit.

Copie D:\Game\LifePlay-master 5.8, HEAD 4283c13 (fiche, rubrique 3). Abréviations (chemins absolus) :

  • J5 = %USERPROFILE%\AppData\Local\Temp\claude\D--Game-LifePlay-master-5-8\37530d8d-c780-4a57-8fbd-bcb010aa6408\scratchpad\J5-LifePlay.log (35 839 lignes, 21:52:35.467 → 22:05:32.936) ; J4 = même dossier, J4-LifePlay.log.
  • Dumps D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\dumps\ : PEG4 = Person__EventGraph_D4.txt (2026-10-10T20:17:12, Person non modifié depuis : fiche, rubrique 3), DD4 = GI__destroyDummy_D4.txt, SD4 = GI__SpawnDummy_D4.txt, CS4 = Person__ClearSMCs_D4.txt, RM5 = Room__EventGraph_V5.txt.
  • UE = D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Engine\Private\Components\ (moteur installé, lu).
  • Paquets lus en binaire (table de noms, lecture seule) : D:\Game\LifePlay-master 5.8\Content\BPs\{Person,GI,Room,Daily,Daily_F}.uasset avec Tools/uasset58.py (fonctions load, locate, clsname).

1. Symptôme et reproduction

Reproduction en jeu interdite : lecture de J5. Comptes faits par un script Python lu sur l'entrée standard (python -I - J5-LifePlay.log <<'EOF' … EOF, aucun fichier écrit ; motif GetSocketInfoByName\(([^)]*)\): No SkeletalMesh for Component\(CharacterMesh0\) Actor\(… (Person_C_\d+)\)) :

  • No SkeletalMesh : 20 493 lignes = 20 488 avertissements LogSkinnedMeshComp + 5 lignes du résumé LogLifePlay (à partir de J5:35769). Composant : CharacterMesh0 seul (20 488). Contrôle : 20 493 = STE-J5.md:53.
  • Par socket : CenterBrow 6 408, Head 5 632, pelvis 2 816, chestUpper 2 816, hip 2 816. Head = 2 × 2 816.
  • Par acteur (somme 20 488) : Person_C_2147481861 13 123, …1909 1 575, …1981 1 571, …1957 1 551, …1933 1 525, …1837 680, …1885 463.
  • Forme type, établie. J5:2115 test0304 DESTROY… index Person_C_2147481885 ; J5:2116-2120, même trame [385], même milliseconde (:038) : Head, Head, pelvis, chestUpper, hip ; J5:2121 DestroyDummy was from DestroyPerson ; J5:2123 CenterBrow ; trame [386] (J5:2128-2144, toutes à :085) : le même groupe de 5, au moins 3 fois.
  • Comptes voisins : FlushAsyncLoading 403, DESTROY 89, index SPAWN 94 (mêmes valeurs que STE-J5.md:29, 53).

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

H4 : F5 vient de lectures de sockets sur le maillage vidé (par ResetVars, STE-H2b-DIAG.md § 3.2) des mannequins en réserve, et ces lignes ne causent pas de trame longue. Les saccades restantes ont d'autres causes. Réfutée si : des F5 tombent sur des mannequins actifs, ou si les trames qui ne portent que du F5 sont plus longues que les autres.

3. Essai et résultat brut

3.1 Q-a : où et quand (établi)

  • 100 % en réserve. Chaque ligne F5 est classée selon le dernier DESTROY ou SPAWN de son acteur qui la précède (motifs DESTROY.*index (Person_C_\d+) et (Person_C_\d+)\s+index SPAWN). Les 20 488 lignes sont toutes en état « réserve », 0 en état « actif ». Chacun des 89 intervalles de réserve porte du F5 (« intervalles sans F5 : 0 »).
  • Groupes de 5 (Head ×2, pelvis, chestUpper, hip) : 2 816 groupes = 14 080 lignes (68,7 %). Le premier tombe dans la trame du DESTROY, puis environ 1 par image (intervalle médian 17 ms) pendant 0,26 à 0,83 s (≤ 42 groupes, typiquement 0,67 s), puis plus rien jusqu'au SPAWN suivant. Exemples : …1861 DESTROY J5:4694, 31 groupes sur 0,50 s, puis 49 s de réserve sans groupe ; …1837 DESTROY J5:7693, 33 groupes sur 0,52 s, puis 459 s de réserve.
  • CenterBrow : 6 408 lignes (31,3 %). Par acteur : …1861 5 373, …1837 515, …1885 318, …1981 126, …1957 66, …1909 10, …1933 0. Une par image (intervalle médian 17 ms sur …1861) et en longues séries : jusqu'à 22,3 s après le DESTROY de J5:15686 (1 333 lignes), 20,0 s après J5:10056, 17,8 s pour …1837. Elles ne sont présentes que dans 33 des 89 intervalles.
  • Ventilation par trame (blocs de lignes de même [n]) : 7 092 blocs avec F5 ; 5 220 blocs à 1 ligne (CenterBrow seul), 637 à 5, 757 à 6, 152 à 20, 86 à 21 (4 mannequins en réserve ensemble), maximum 50.
  • Mannequins recyclés : les 4 acteurs …1981, …1957, …1933 et …1909 sont détruits ensemble (4 DESTROY dans une trame, test1303 OpenSpace, ex. J5:3118-3158), puis recréés un par trame (J5:2655-2970, trames [702]-[705]).

3.2 Q-a : lecteur des groupes de 5 = le moteur (établi)

  • SCS de Person (table de noms, index FName lus dans les exports SCS_Node_* de Person.uasset par uasset58.load) : SCS_Node_1 DirtyTalkSM → AttachToName = head ; SCS_Node_4 FirstPersonSM → head ; SCS_Node_5 CensoreSM → pelvis ; SCS_Node_7 CensoreBoobsSM → chestUpper ; SCS_Node_8 ButtonSM → hip. Tous ont pour parent CharacterMesh0. HairSM, PenisSM et ParticleSM n'ont pas de socket. Les 5 sockets apparaissent dans le même ordre que dans le journal. head s'affiche Head : un FName se compare sans casse et s'affiche avec la première casse enregistrée (estimé).
  • ClearSMCs (appelé par ResetVars, _372) détruit les enfants de Mesh dont le nom ne finit pas par SM (CS4:118-137 : EndsWith('SM'), else → DestroyComponent). Les 5 composants ci-dessus restent donc attachés au maillage vidé.
  • Moteur : UpdateChildTransforms met à jour chaque enfant attaché (UE SceneComponent.cpp:2927-2950). Un enfant à socket appelle Parent->GetSocketTransform(SocketName) (UE SceneComponent.cpp:731), qui appelle GetSocketInfoByName (UE SkinnedMeshComponent.cpp:3535). Celle-ci avertit dès que l'asset est nul (UE SkinnedMeshComponent.cpp:3598-3614). Un groupe = un déplacement du maillage sans corps. Aucun nœud Blueprint n'est en cause.
  • Déclencheur du premier groupe : destroyDummy exécute SetActorHiddenInGame → ResetVars (_1) → K2_SetActorTransform (_2, (0,0,0), bTeleport = false) → Valid = false (DD4:148-170, 249-251). Le maillage est déjà vidé (_433, PEG4:13248-13253) quand l'acteur est déplacé, d'où le groupe J5:2116-2120 avant DestroyDummy was from (J5:2121).
  • Groupes suivants (≈ 0,67 s) : estimé. Le capsule continue de bouger après la téléportation, probablement le CharacterMovement en chute ou en freinage. Aucun changement de mode de mouvement n'existe dans PEG4 (Grep SetMovementMode|DisableMovement|StopMovementImmediately|SetComponentTickEnabled → 0 ; SetActorTickEnabled : 2 nœuds, PEG4:9713, 9718, hors chemin du DESTROY). Une chute libre de 0,67 s ferait ≈ 2,2 m (calcul). L'essai qui tranche est la voie C.
  • Les autres lecteurs de sockets de Person ne sont pas en cause : la routine physique (abdomenLower, abdomenUpper, chestLower, PEG4:9692-9989) n'apparaît pas dans J5 (0 ligne pour ces sockets). LPPersonPropGuardSubsystem n'appelle que DoesSocketExist (LPPersonPropGuardSubsystem.cpp:177), qui n'avertit pas (UE SkinnedMeshComponent.cpp:3709-3719). LPSecondScreenSubsystem.cpp:31 est gardé par GetSkinnedAsset().

3.3 Q-a : lecteur de CenterBrow (estimé fort ; dumps requis)

Lecteurs possibles (tous établis comme nœuds GetSocketLocation(CenterBrow)) :

  • Person FaceHeadtrackTarget (K2Node_CustomEvent_66, PEG4:13541) : _451 lit HeadtrackTarget.Mesh → HeadtrackAimLocation et _450 lit self.Mesh (PEG4:13048-13063, 19401-19411), puis K2_SetActorRotation(self) (_442, PEG4:13026-13032). Appelants (index FName dans les exports) : GI faceEachOther, GI centerAttention, Room moveToBedIfPossible. Le Person ReceiveTick ne l'appelle pas (PEG4:9628-9637 → Gate → routine physique).
  • GI CalculateHeadtrack (K2Node_CallFunction_1 et _3, graphe CalculateHeadtrack de GI.uasset, non dumpé), appelé par l'EventGraph de Daily et Daily_F. Ce sont des AnimBlueprints (classes AnimBlueprint, AnimBlueprintGeneratedClass ; noms BlueprintUpdateAnimation, TryGetPawnOwner, HeadtrackTarget, CalculateHeadtrack dans leur table de noms).
  • GI getNearestDummy (K2Node_CallFunction_0 et _1, non dumpé), appelé par Room (_215, _216 → HeadtrackTarget, RM5:2457-2476), par Person (_641, _887, PEG4:14897-14920) et par GI centerAttention.

Attribution (estimé fort) : les séries ont une ligne par image pendant 17 à 22 s, donc un lecteur appelé à chaque image. Seul CalculateHeadtrack en a un, BlueprintUpdateAnimation d'un vivant dont le HeadtrackTarget est resté sur un mannequin caché. Le mannequin en réserve ne lit pas son propre CenterBrow (…1933 : 0 ligne en 305 groupes de réserve) : son instance d'animation ne tourne vraisemblablement pas sans corps (UE SkeletalMeshComponent.cpp:1164, d'après STE-H2b-DIAG.md § 3.7). La chaîne exacte (qui garde la cible, pourquoi jusqu'à 57 s) demande les dumps du § 5.

3.4 Q-b : coût, trames longues de J5 (établi)

Méthode (comme STE-H5c-DIAG.md § 3.5) : une trame = un bloc de lignes de même [n]. Durée de la trame n ≈ horodatage de la 1re ligne de n+1 moins celui de la 1re ligne de n, seulement quand n+1 suit n (modulo 1000). Seuil : 50 ms. Mesurées : 9 375 paires sur 11 649 blocs (≈ 45 700 trames en 777 s à 17 ms : les trames sans ligne ne sont pas vues). Durée médiane 17 ms. 90 trames ≥ 50 ms, total 18 417 ms.

Les trames qui ne portent que du F5 ne sont pas plus longues. Trames sans FlushAsyncLoading ni marqueur (DESTROY, SPAWN, CHECKING:, UNHIDE, LoadMap, Synchronously, DestroyDummy, MouseCaptureMode) :

Lignes F5 dans la trame Trames Médiane p99 Max ≥ 50 ms
0 162 17 43 92 1
≥ 1 (dont 1 : 2 869 ; 2-6 : 579 ; 7-15 : 51 ; 16-25 : 251 ; ≥ 26 : 15) 3 765 17 18 47 0

Les lignes d'un groupe partagent la même milliseconde (J5:2116-2120 ; 3 groupes à :085, J5:2128-2144) : moins de 1 ms par groupe. Même contrôle sur J4 : 3 954 trames F5 sans marqueur, médiane 17 ms. 3 sont ≥ 50 ms (max 284) : J4 contient encore les paquets Dress de STE-H5c-DIAG.md, non marqués ici (estimé).

Classement des 90 trames longues de J5 par cause probable (règle : 1re classe vérifiée dans la trame, dans l'ordre du tableau) :

Classe Trames Total ms Au-delà de 17 ms Lignes F5 Avec FAL
Chargement (≥ 1 s ou LoadMap) 3 8 262 8 211 0 2
SPAWN (index SPAWN) 52 4 167 3 283 258 40
Fin de scène (DESTROY / DestroyDummy) 13 2 539 2 318 123 0
CHECKING: 14 1 832 1 594 23 1
FlushAsyncLoading seul 2 436 402 0 2
Clic d'interface (MouseCaptureMode) 5 1 089 1 004 0 0
Autre 1 92 75 0 0

J4, mêmes classes : 2 / 50 / 11 / 15 / 2 / 4 / 12.

  • Fin de scène (« saccades en fin de scène ») : 13 trames de 62 à 331 ms, dont 10 seules à plus de 150 ms : [385] J5:2009-2127 331 ms ; [332] J5:4652-4728 271 ; [483] J5:9304-9371 274 ; [894] J5:8681-8752 258 ; [193] J5:7668-7724 224 ; [187] J5:18855-18923 220 ; [818] J5:27245-27292 213 ; [526] J5:19300-19347 184 ; [873] J5:15669-15716 182 ; [67] J5:33141-33188 151. Temps avant la ligne DESTROY : 71 à 283 ms (déshabillage, rhabillage, stats : Stripped …, Dressed …, ex. J5:2090-2114). Temps après : 48 à 114 ms. F5 y vaut 5 à 6 lignes par trame. Cause probable (estimé) : le travail Blueprint de fin de scène et destroyDummy, pas F5. Le plus grand écart interne suit souvent le clic (MouseCaptureMode → HideCursorDuringCapture, 29 à 54 ms).
  • SPAWN : séries de 4 trames de 55 à 105 ms quand le joueur entre dans un lieu (ex. [702]-[705] J5:2655-2970 : 59, 71, 68, 98 ms ; [141]-[144] J5:12008-12237 ; [755]-[758] J5:35371-35640). 40 des 52 portent un FlushAsyncLoading. Les lignes F5 (10 à 31 par trame) viennent des mannequins encore en réserve et baissent de 10 à chaque reprise (30 → 20 → 10) : effet, pas cause.
  • FlushAsyncLoading : 403 lignes, dont 45 dans des trames longues (SPAWN 40, chargement 2, CHECKING: 1, seul 2). Ligne qui précède : DressSavedActual 145, Meubles assis ou couches 72, CHECKING: 84, index SPAWN 24, CenterBrow 21 (simple voisinage). Les plus grands écarts suivent un FAL : 348 ms (J5:959→960, chargement), 138 ms (J5:4625→4626, trame [671] de 232 ms), 116 ms (J5:9199→9200, trame [61] de 192 ms). Estimé : chargements synchrones de vêtements ou de meubles (Dress au SPAWN, places assises).

Réponse Q-b : les rafales F5 ne coïncident avec aucune trame longue qui leur soit propre (0 sur 3 765). Elles ne sont présentes dans des trames longues que comme passagères (SPAWN, DESTROY, CHECKING:). FlushAsyncLoading est présent dans 45 trames longues sur 90, surtout au SPAWN.

3.5 Q-c : voie B, ne pas vider le corps au DESTROY

  • Nœud : Person EventGraph, ResetVars, K2Node_CallFunction_433 (SetSkinnedAssetAndUpdate, NewMesh vide), dont l'entrée self est reliée à K2Node_VariableGet_241.Mesh, _242.HairSM et _247.PenisSM (PEG4:13245-13253, mêmes lignes que dans STE-H2b-DIAG.md). On retire le seul lien self ← VariableGet_241.Mesh. 0 nœud créé. Si break_pins coupe les 3 liens, on reconnecte _242 et _247.
  • Effet F5 : 20 488 → ≈ 0 (estimé fort). Les groupes et les CenterBrow visent tous des mannequins en réserve (§ 3.1) ; avec un corps, GetSocketInfoByName n'avertit plus, même si le socket manque (UE SkinnedMeshComponent.cpp:3598-3602).
  • Effet sur les saccades : aucun attendu. F5 ne coûte rien de mesurable (§ 3.4).
  • F4 / G-H2 : 0 conservé. Au SPAWN, Race vide force toujours UpdatePlayerMeshWithMorphs ; la garde prend then et lit les morphs de l'ancien corps, remis à zéro (STE-H2b-DIAG.md § Voie B).
  • Mauvais sexe ou mauvaise race à la reprise : le nouveau corps est posé dans la même image par LoadPreset → PlayerChangeRace (STE-H2b-DIAG.md § 3.3-3.4 : Race vide → UpdatePlayerMeshWithMorphs → UpdatePlayerMesh). L'ancien corps n'est donc pas visible (estimé fort), sauf sur le chemin LoopUpdateAI StatOnly = true (R-B1 de H2b). SpawnDummy choisit le mannequin sur DummyPersonsInUse et Valid, pas sur le corps (SD4:126-151, 180-183) : R-B4 de H2b est levé (établi).
  • Mémoire (non chiffrée). ≤ 7 mannequins (7 acteurs en réserve dans J5) gardent une référence à leur corps. Corps sur disque, non cuits, morphs compris : Content/Heavy/Daz/Bridget/bridget_gp.uasset 138,9 Mo, Content/Heavy/Daz/Michael/michael.uasset 55,0 Mo. Ce sont probablement les corps de MeshSexRace (non lu ; estimé). Surcoût d'asset nul si un vivant porte le même corps (asset partagé) ; sinon le corps reste chargé, au plus un par couple (sexe, race) gardé en réserve. Par composant s'ajoutent les poids de morphs, les tampons d'os et l'instance d'animation Daily / Daily_F.
  • Processeur (estimé, à mesurer). Avec un corps et AlwaysTickPose (UE Character.cpp:125, cité par H2b), l'AnimBlueprint des ≤ 7 mannequins cachés reprendrait BlueprintUpdateAnimation et CalculateHeadtrack à chaque image. Aujourd'hui, sans corps, ils ne le font pas (§ 3.3). C'est du calcul en plus à chaque image, en échange de lignes de journal qui ne coûtent rien.
  • Comportement : un vivant dont le HeadtrackTarget est un mannequin caché vise déjà l'origine. Sans corps, GetSocketTransform rend la transformation du composant (UE SkinnedMeshComponent.cpp:3529, 3551-3569), placé près de (0,0,-90). Avec B, il viserait le front du mannequin, à l'origine aussi : direction presque inchangée (estimé).

3.6 Q-d : autres voies

  • C, couper le déplacement du mannequin en réserve (groupes, 14 080 lignes, 69 %).

    1. GI destroyDummy : remettre la téléportation avant le vidage. Couper K2Node_CallFunction_0.then → _1.execute, _1.then → _2.execute et _2.then → VariableSet_0.execute, puis relier _0.then → _2.execute, _2.then → _1.execute et _1.then → VariableSet_0.execute (DD4:148-165, 249-251).
    2. Après la téléportation, nouveau nœud CharacterMovementComponent::DisableMovement (ou SetMovementMode(None)), cible Dummy.CharacterMovement (nouveau VariableGet sur l'entrée Dummy).
    3. GI SpawnDummy : nouveau SetMovementMode(Walking) entre K2Node_VariableSet_0.then (Valid = true) et K2Node_FunctionResult_0.execute (SD4:137-138, 180-183), cible = élément choisi par K2Node_MacroInstance_1.

    Bilan : 2 à 3 nœuds créés, 3 coupures, 5 à 7 liens. Effet : groupes ≈ 0 (estimé : suppose que le mouvement de 0,67 s vient du CharacterMovement). CenterBrow inchangé. Risque : un mannequin repris sans mouvement restauré ne marcherait plus (effet visible) ; MakeDummyPersons (mannequins neufs) n'est pas concerné. Mémoire : nulle.

  • C0, ordre seul (étape 1 de C) : 0 nœud créé, 3 coupures, 3 liens. Retire le groupe de la trame du DESTROY, soit 89 × 5 = 445 lignes (estimé). Les ≈ 0,67 s de groupes suivants restent. Risque faible : ResetVars replace déjà le maillage (_17).

  • D, garde ou cause du CenterBrow (6 408 lignes, 31 %). Garde dans GI CalculateHeadtrack avant K2Node_CallFunction_1 et _3 : IsValid(Target) et non caché, ou corps présent. Ou bien, à la cause : vider le HeadtrackTarget des vivants qui visent un mannequin au DESTROY, ou exclure les mannequins cachés de getNearestDummy. Effet : 6 408 → 0. Peut aussi corriger un regard tourné vers l'origine jusqu'à 57 s (incertain). Nœuds et liens non nommables : dumps requis (§ 5).

  • E, couper le tick ou l'animation au DESTROY (proposition de STD-SCN-DIAG.md:165) : SetActorTickEnabled(false) n'arrête pas le composant de mouvement, qui a son propre tick (estimé). Pour supprimer les groupes, il faut couper le mouvement : cela revient à C.

  • A de H2b (corps provisoire avant LoadPreset) : l'état en réserve ne change pas, F5 non plus. Écartée pour F5.

  • Abstention : F5 n'a pas de coût mesuré. Le gain se limite à la taille du journal (20 493 lignes sur 35 839, soit 57 %).

Voie Fichier, nœuds Création / liens F5 attendu Saccades Mémoire Risque principal
B Person _433 0 / −1 lien ≈ 0 aucun effet ≤ 7 corps référencés + AnimBP actifs, à mesurer calcul d'animation en réserve ; R-B1 StatOnly
C GI destroyDummy + SpawnDummy 2-3 / 3 coupures, 5-7 liens −14 080 (estimé) aucun effet nulle mouvement non restauré au SPAWN
C0 GI destroyDummy 0 / 3 coupures, 3 liens −445 aucun effet nulle faible
D GI CalculateHeadtrack ou les poseurs de HeadtrackTarget dumps requis −6 408 aucun effet nulle regard modifié (voulu ?)
Abstention — — 20 493 — — journal à 57 % F5

3.7 Q-e : protocole de mesure (build Development, console ~)

But : trancher B (mémoire, animation) contre C / D, et chiffrer les trames SPAWN et de fin de scène. Même parcours que J5 (compagne qui suit, entrées dans des lieux, scènes jusqu'au bout).

  1. Après le chargement de la sauvegarde, avant toute scène : memreport -full (point M0), obj list class=SkeletalMesh, obj list class=AnimInstance. Noter le nombre et le total de chaque liste.
  2. Afficher stat unit et stat unitgraph (temps Frame et Game) pour toute la partie, puis stat game et stat anim.
  3. Entrer dans un lieu avec 4 personnes (série SPAWN) : noter les pics de Game. Finir une scène (DESTROY) : noter le pic.
  4. Après 2 ou 3 scènes (mannequins en réserve), rester 30 s sans rien faire : moyenne de Game et temps d'animation (stat anim). Puis memreport -full (M1) et les deux obj list.
  5. En option, sur une scène : stat startfile, finir la scène, stat stopfile. Le fichier va dans Saved\Profiling.
  6. Comparer avant et après le correctif, sur le même parcours :
    • nombre d'AnimInstance et de SkeletalMesh (B en ajoute au plus 7 et 2) ;
    • écart M1 − M0 de la mémoire du processus (memreport) ;
    • temps Game et stat anim au repos, avec des mannequins en réserve ;
    • dans le journal, refaire le classement du § 3.4 : nombre et total des trames ≥ 50 ms par classe, lignes F5, FAL. Seuil proposé : B est neutre si Game au repos varie de moins de 0,2 ms et la mémoire de moins de quelques dizaines de Mo (seuils à fixer par l'utilisateur).

4. Verdict : confirmée

  • Établi : 100 % de F5 sur des mannequins en réserve (§ 3.1). Les groupes de 5 sont la mise à jour moteur des 5 composants SCS attachés à des sockets, sur un maillage vidé par ResetVars et laissé en place par ClearSMCs (§ 3.2). Le premier groupe vient de la téléportation de destroyDummy placée après ResetVars. Coût nul : 0 trame ≥ 50 ms sur 3 765 trames F5 seules, médiane 17 ms. Les trames longues relèvent du SPAWN, de la fin de scène, du CHECKING:, du chargement et des clics ; FlushAsyncLoading est présent dans 45 d'entre elles sur 90 (§ 3.4).
  • Estimé : lecteur CenterBrow = GI CalculateHeadtrack, appelé à chaque image par l'AnimBlueprint Daily / Daily_F d'un vivant qui vise un mannequin caché (§ 3.3). Mouvement de ≈ 0,67 s dû au CharacterMovement après la téléportation (§ 3.2). Coûts de B (§ 3.5).
  • Incertain : chaîne exacte du HeadtrackTarget (qui le pose, pourquoi il reste) ; corps de MeshSexRace ; réglages CharacterMovement et animation du CDO de Person ; journalisation en Shipping (bUseLoggingInShipping absent de Source/*.Target.cs, défaut moteur non relu).

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

  • H7 (N3, lp-cart) : la série SPAWN (52 trames, 4,2 s dans J5) vient de LoadPreset / Dress et des chargements synchrones (40 FAL sur 52 trames). À instruire avec les noms des paquets chargés (-LogCmds="LogStreaming Verbose" en jeu, à confirmer).
  • H8 (N3, lp-cart) : la fin de scène (13 trames de 62 à 331 ms) vient du travail Blueprint avant le DESTROY (déshabillage, rhabillage, stats : 71 à 283 ms) et de destroyDummy (48 à 114 ms après).
  • Dumps manquants (lot STE-D8), arrêt sur ce point pour la voie D (rien lancé ici ; éditeur fermé ; lp-commandlets) :
    .\Tools\RunCommandlet.ps1 -Lot STE-D8 -Commandlet LPDumpFunction -Args '-BP=GI -Fn=CalculateHeadtrack -Pins -Exec'
    .\Tools\RunCommandlet.ps1 -Lot STE-D8 -Commandlet LPDumpFunction -Args '-BP=GI -Fn=getNearestDummy -Pins -Exec'
    .\Tools\RunCommandlet.ps1 -Lot STE-D8 -Commandlet LPDumpFunction -Args '-BP=Daily -Fn=EventGraph -Pins -Exec'
    .\Tools\RunCommandlet.ps1 -Lot STE-D8 -Commandlet LPDumpFunction -Args '-BP=Daily_F -Fn=EventGraph -Pins -Exec'
    .\Tools\RunCommandlet.ps1 -Lot STE-D8 -Commandlet LPDumpFunction -Args '-BP=GI -Fn=centerAttention -Pins -Exec'
    .\Tools\RunCommandlet.ps1 -Lot STE-D8 -Commandlet LPDumpFunction -Args '-BP=GI -Fn=faceEachOther -Pins -Exec'
    
    Que LPDumpFunction accepte un AnimBlueprint (-BP=Daily) est incertain. Le CDO de Person (CharacterMovement, Mesh.VisibilityBasedAnimTickOption) s'obtiendrait par LPDumpCDO, options à lire dans son .h (incertain). Pour B, C et C0, aucun dump ne manque : les nœuds sont nommés aux § 3.5-3.6.

Questions à l'utilisateur

  • Q-H4-1 : F5 ne coûte rien de mesurable dans J5. Le traiter maintenant pour la lisibilité du journal (57 % de ses lignes), ou s'abstenir ?
  • Q-H4-2 : si vous le traitez, quelle voie : B (1 lien, F5 ≈ 0, mémoire et animation en réserve à mesurer), C (mouvement coupé, −69 %, restauration au SPAWN), C0 (ordre seul, −445 lignes), D (garde CenterBrow, −31 %, dumps requis), ou C + D ?
  • Q-H4-3 : lancer les 6 dumps STE-D8 du § 5 (préalable à D et à l'explication du HeadtrackTarget qui reste sur un mannequin caché) ?
  • Q-H4-4 : ouvrir H7 (série SPAWN avec chargements synchrones) et H8 (trames de fin de scène) pour les saccades restantes ?
  • Q-H4-5 : faire la mesure du § 3.7 avant de décider (B en particulier), ou décider sur la lecture statique ?
  • Q-H4-6 : un vivant qui garde pour cible un mannequin caché jusqu'à 57 s (tête tournée vers l'origine, effet visible incertain) : faut-il l'instruire comme défaut de jeu, indépendamment de F5 ?

Fichiers à commiter (dépôt jeu, branche ue5.8, ticket au gardien) :

  • A Docs/Migration/etat/ST/STE/STE-H4-DIAG.md

Tours : 41 / 60

Constats

  • Outils hors Grep, Read et Glob, tous en lecture seule. Python lu sur l'entrée standard (python -I - <fichier> <<'EOF') pour les comptes de J5 et J4, les durées de trame et le parcours des liens d'exécution de PEG4 ; aucun fichier écrit. Tools/uasset58.py (locate, et load / clsname importés) et une lecture d'octets des .uasset pour les tables de noms et les index FName (SCS de Person, appelants de FaceHeadtrackTarget, CalculateHeadtrack, getNearestDummy). Grep sur des .uasset n'est pas probant (STE-H2b-DIAG.md, Constats).
  • Pour la reprise, la méthode de mesure des trames (§ 3.4) mérite un outil (Tools/FrameStats.py, à proposer en fiche IMPL) : aucun script n'a été rangé.
  • Grep chestUpper sur Content\Modules → 0 ; sur Source → 0 ; sur Plugins de la copie et de l'addon 5.8 → 0. Sur Content, hors packs d'animation, seuls GI.uasset et Person.uasset portent chestUpper / CenterBrow avec un GetSocket*.
  • Comptes par acteur et par socket recoupés : groupes 2 816 = (20 488 − 6 408) / 5 ; somme des acteurs = 20 488 ; somme des CenterBrow par acteur = 6 408.
  • Nombre de tours estimé ; python -I Tools/FicheStats.py --lot STE fait foi.