LifePlay-Revival/Docs/Migration/etat/ST/STE/STE-H5c-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
Raw Blame History

Fiche STE-H5c — 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é

STE-H5c-DIAG : origine des Accessed None ... property Person dans GI.Dress en J4 (2026-10-10)

Résultat : hypothèse de départ réfutée pour 10 paquets sur 11 (≈ 91 % des lignes), indécise pour le 11e. La personne nulle vient surtout de Room.getKnownNpcsHere : GetSpecific rend None pour la clé d'IA de la compagne, qui suit le joueur de bâtiment en bâtiment, et Dress s'exécute ensuite en entier sur None. Imputation à F-a : non établie ; estimée improbable comme cause directe, car le déclencheur dépend du parcours (compagne présente en J4, absente en C0 et J3). Aucun commandlet, éditeur, build ni jeu lancé ; seul ce fichier est écrit.

Sources lues (toutes en lecture) : J4 = copie ...\scratchpad\J4-LifePlay.log, C0 = ...\scratchpad\C0-LifePlay.log (dossier scratchpad de la fiche, rubrique 3), J3 = D:\Game\LifePlay_Build_5.8_STF-STE-LISIB_Development\Windows\LifePlay\Saved\Logs\LifePlay.log. Dumps de etat\ST\STE\dumps\ (abrégés) : CSP = GI__clearScenePersons_D6.txt, DR = GI__Dress_D6.txt, GS = GI__GetSpecific_D6.txt, RAG = GI__removeAlreadyGot_D6.txt, RM = Room__EventGraph_D6.txt, EG = GI__EventGraph_D6-M1.txt, AV = GI__AddVariable_D5.txt, DD = GI__destroyDummy_D4.txt, SD = GI__SpawnDummy_D4.txt, CCW = GI__CheckConditionsWho.txt (lot STE-D, 5.8), CF = GI__CallFunction_apres-GARDES.txt ; L6f = etat\portage55\L6f\L6f_dump_GI.txt (GI 5.5, flux de données seulement). Moteur : D:\Game\Launcher\Engine\UE_5.8\Engine\Source (OH = Runtime\Core\Private\Misc\OutputDeviceHelper.cpp, SC = Runtime\CoreUObject\Private\UObject\ScriptCore.cpp).

1. Symptôme et reproduction

Pas de reproduction (interdite par la fiche) : lecture du journal J4. Recompte fait avec Grep (outil), contrôles positifs : UNHIDE Persons = 25 (J4), 27 (C0), 30 (J3), mêmes valeurs que STE-J4.md:56 et :65.

  • GI_C:Dress:64X (une ligne par avertissement de Dress) : 32 713 lignes dans J4 (Grep, mode count). STE-J4.md:59 donne 32 716 pour GI_C:Dress: (motif plus large, écart de 3 non expliqué).
  • Un paquet = un appel de Dress sur None : chacun commence par un seul Attempted to access index 0 from array 'Person_24_…' of length 0 (repli de Dress, § 3.1), puis des blocs de 7 lignes (pile Room) ou 11 lignes (pile clearScenePersons). 11 paquets, pas 13 :
# Pile index 0 (ligne J4) dernière ligne Dress blocs horloge du journal [trame] UNHIDE suivant [Person_C_2147481884] 1 moves to avant
1 Room 14759 34969 2 887 20:08:09.362 [648] → .500 [653] 34988 12661, 12711 community_centre
2 Room 37446 57656 2 887 20:08:27.596 [690] → .688 [691] 57703 37262 department_store
3 Room 59592 79802 2 887 20:08:49.153 [926] → .257 [927] 79821 58538 department_store
4 Room 80124 100334 2 887 20:08:51.886 [66] → .982 [67] 100374 79875 community_centre
5 clearScenePersons 101080 ≈ 132 827 (calcul) ≈ 2 886 20:09:11.086 [184] → .244 [184] — (NextButton) —
6 Room 136466 156676 2 887 20:09:42.132 [0] → .237 [4] 156716 134181, 136288 community_centre
7 Room 159206 179416 2 887 20:10:23.529 [429] → .633 [432] 179456 156834 community_centre
8 Room 180334 200544 2 887 20:10:30.186 [817] → .285 [818] 200563 156834 community_centre
9 Room 205056 225266 2 887 20:11:42.156 [57] → .254 [60] 225288 204343 pub
10 Room 229187 249397 2 887 20:14:15.347 [49] → .448 [51] 249419 228874 home
11 Room 250273 277182 3 844 20:14:50.477 [115] → .611 [118] 277203 249765 home

Blocs Room = (dernière − première + 1) / 7 : 20 209 / 7 = 2 887 (paquets 1-4, 6-10), 26 908 / 7 = 3 844 (paquet 11) : établi. Paquet 5 : 32 713 − (9 × 2 887 + 3 844) = 2 886 blocs (estimé : suppose une ligne GI_C:Dress:64X par bloc) ; il finit avant la ligne 132838 (20:09:11.244 [184], lignes hors paquet relues 132838-132897) : établi.

  • Écarts à STE-J4.md:70-71 : le premier paquet est à 20:08:09.362 (ligne 14708), pas à 20:06:42 (l'UNHIDE de la ligne 7331 n'a pas de paquet) ; 11 paquets (10 Room + 1 clearScenePersons), aucun de 3 444 trouvé. Les paquets précèdent l'UNHIDE (même trame que l'UNHIDE pour les paquets Room), ils ne le suivent pas.
  • Deuxième élément nul dans clearScenePersons à 20:13:51.833 (lignes 228772-228800), sans paquet Dress.
  • C0 et J3 : 0 ligne de cette famille (STE-J4.md:57-65, non recompté ici).

2. Hypothèse testée

H (orchestrateur) : clearScenePersons parcourt PersonsUsedThisScene et appelle Dress(DirectPerson = élément) ; un AIDummy ajouté à cette liste (ou à Variables) par une routine d'IA rendue possible par F-a, puis détruit, laisse une référence nulle.

3. Essai et résultat brut

3.1 Amplificateur commun : GI.Dress sur une personne nulle (Q-a, Q-b) — établi

  • Dress teste DirectPerson par IsValid ; si invalide, il lit GetVariable(PersonVariable) puis Person_24[0] dans la variable locale Person (DR:580-588, 33-57). Les deux branches se rejoignent à K2Node_Knot_1 → VariableSet_11 (DR:738-740) sans autre test : tout le corps s'exécute avec Person = None. Les deux appelants passent PersonVariable vide (RM:2404-2413, CSP:110-119) ; le journal montre alors index 0 … of length 0 (ex. 14759, 101080), puis les lectures via None.
  • Le message Accessed None trying to read (real) property X in not an UClass est émis quand le contexte est un pointeur nul (SC:3203-3216) ; un objet détruit mais non nul donne un autre message (SC:3191-3196). Les éléments en cause sont donc nuls.
  • Q-b (2 887 par paquet) : un seul appel de Dress par paquet (un seul index 0 par paquet, tableau du § 1). Boucle dominante, estimée : ForEachLoop sur CVars (MacroInstance_896, DR:26-32) × ForEachLoopWithBreak sur ClothTable (MacroInstance_361, DR:294-301), avec une lecture de Person.Race par tour (VariableGet_3 ← VariableGet_8071.Person, DR:617-633) ; la sortie (Break) ne vient qu'à la correspondance d'un nom. Décomposition exacte incertaine : décalages masqués (Dress:64X) et taille de ClothTable connue seulement à l'exécution. Le nombre ne dépend pas du lieu (2 887 à community_centre, department_store, pub, home ; 3 844 une fois à home).

3.2 Voie Room : 10 paquets sur 11, 29 827 blocs (Q-a) — établi, sauf mention

Chaîne de Room (évènement getKnownNpcsHere, branche des routines d'IA) :

  1. AICurrentKeys = clés de GI.AI_Currents, mélangées (RM:3276-3288) ; boucle Async, 3 itérations par image (RM:3108-3112) ; clé courante GetArrayItem_7 (RM:3124-3127).
  2. IfThenElse_44 saute la clé si KnownNpcsHere la contient déjà (CallFunction_259, RM:2749-2759).
  3. IfThenElse_40 / _41 : AI_Currents[clé] trouvé et égal à CurrentPlayerBuilding (RM:2589-2629) ; IfThenElse_43 (RM:2678-2682).
  4. GetSpecific(Person = clé) (CallFunction_235, RM:2611-2618), sans test de validité du résultat, puis : Map_Add(KnownNpcsHere, Prefix + SaveSlot du résultat, résultat) (RM:2318-2339) → RemoveItem(PersonsUsedThisScene) (RM:3145-3151) → removeAlreadyGot → PlayIdle (RM:2388-2393) → SetActorHiddenInGame (RM:2394-2398) → Dress(DirectPerson = résultat) (RM:2404-2413) → TalkDirty (RM:2723-2727) → Knot_1.
  5. Journal, chaque paquet Room : 2 × CallFunc_GetSpecific_PersonToReturn, 3 × removeAlreadyGot property Person (lecture de Prefix et SaveSlot, RAG:6-9, 33-35), 3 × GetSpecific_PersonToReturn, index 0, blocs Dress, 3 × GetSpecific_PersonToReturn (ex. 14708-14759 puis 34970-34982). L'ordre suit celui des nœuds (correspondance ligne par nœud : estimée, décalages masqués).

Pourquoi GetSpecific rend None : pour une clé numérique, Slot = la clé (GS:9-17, 21-29), puis IfThenElse_3304 rend un résultat vide si Slot == 0 ou PersonsAlreadyGot contient Slot ou ActorTimeoutUntils[Slot] > HoursPassed (GS:192-203, 497-529 ; FunctionResult_2 sans PersonToReturn, GS:204-206). Le raccourci qui rend Companion n'existe que pour les rôles nommés (Boss, Landlord, Dating…, GS:142-161, 143). Laquelle des trois conditions a joué : incertain.

Déclencheur : la clé d'IA dont le bâtiment est celui du joueur. En J4, Rebecca (Person_C_2147481884, Slot: 1, ligne 2656) suit le joueur : EG pose Companion.setCurrentLocation(CurrentPlayerBuilding) (CallFunction_1001, EG:27949-27953 ; CallFunction_1000, EG:27966-27970) et le journal porte [Person_C_2147481884] 1 moves to <bâtiment>. Chaque paquet Room suit une telle ligne pour le bâtiment du joueur (tableau du § 1 ; bâtiment du joueur relevé par test0706 amenity, ex. 37051, 57881, 100384, 225296). Comptes (Grep \[Person_C_\d+\] \d+ moves to) : J4 15, C0 0, J3 0 ; moves to toutes sources : J4 41, C0 22, J3 46. Que setCurrentLocation écrive AI_Currents[slot] est estimé : la fonction de Person n'est pas dumpée (aucune occurrence d'AI_Currents dans les dumps Person__* ; dans EG, AI_Currents n'est écrit qu'en sauvegarde et chargement, EG:24428-24495).

Répétition : la clé ajoutée par Map_Add est Prefix + SaveSlot de None, donc "0" (estimé : valeurs par défaut "" et 0), jamais la clé d'IA "1" ; IfThenElse_44 ne la saute donc jamais et le paquet revient à chaque passage de getKnownNpcsHere tant que la compagne est dans le bâtiment du joueur. Effet de bord : KnownNpcsHere["0"] = None.

3.3 Voie clearScenePersons : 1 paquet, ≈ 2 886 blocs (Q-a) — mécanisme établi, origine incertaine

  • Établi : l'élément de pe (copie de PersonsUsedThisScene, CSP:4-22) est nul : 6 lignes CallFunc_Array_Get_Item in not an UClass dans clearScenePersons (101010-101070), puis Dress (101082).
  • Dress n'est appelé que si without est vrai ou si l'élément est dans Room.TempNpcs (CSP:94-105, 205-214, 132-136). without = élément == Interacting ou (KnownNpcsHere[Prefix+SaveSlot] trouvé et égal à l'élément) ou élément == Companion (CSP:33-78). Pour un élément nul, la clé vaut "0", et KnownNpcsHere["0"] = None posé par les paquets Room (§ 3.2) rend la condition vraie ; un Interacting nul aussi (estimé, les deux pistes ne se distinguent pas dans le journal). À 20:13:51, l'élément nul ne déclenche pas Dress (228772-228800) : cohérent avec without faux à ce moment (estimé).
  • Origine de l'élément nul : non établie.
    • AIDummy exclu (estimé) : destroyDummy sort sans rien faire si Dummy == AIDummy (IfThenElse_3.then vide, DD:282-294) ; AddVariable remplace AI sans détruire si SaveSlot != 0 (AV:250-259) ; l'objet AI imprime encore après 20:09:11 ([AI] 3 moves to garden_centre, 133077 ; dernières lignes 283051-283096).
    • CheckConditionsWho exclu (établi) : il n'ajoute Variable.Person[0] que si IsValid (CCW:196-204, 280-286).
    • SpawnDummy ne rend pas None dans son flux normal (SD:129-139, 176-178 : boucle jusqu'à un mannequin libre).
    • Écrivains restants sans garde visible : CallFunction → AddUnique(PersonsUsedThisScene, Interacting) (CF:5320-5326 ; None si Interacting est nul : candidat, estimé) ; dans L6f (5.5, sans broches d'exécution, gardes non vérifiables) : GeneratePerson 17664, Show 18364, getPerson 24084, GetSpecific 26075, getRelative 29581, GenerateCreature 36133, getCreature 36517, checkExistingDummies 44237, getPersonHere 46485 ; référence nettoyée par le ramasse-miettes après destruction d'un acteur (incertain).
    • L'élément nul existe déjà 12 s plus tôt : centerAttention le lit à 20:08:59.691 (100920-100959), et de même à 20:12:35 (228576-228612) avant le cas de 20:13:51. Total CallFunc_Array_Get_Item in not an UClass dans J4 : 17 lignes.
  • Effet de F-a à surveiller (estimé, hors symptôme) : avec AI présent, CheckConditionsWho d'une routine d'IA ajoute AIDummy (valide) à PersonsUsedThisScene, liste commune aux scènes du joueur ; clearScenePersons le passerait alors à DestroyPerson (fonction non dumpée). Cela ne produit pas d'Accessed None (objet valide).

3.4 Lien avec F-a (Q-c)

  • F-a n'écrit que Variables['AI'] = [AIDummy] (CallFunction_568, EG:30103-30114, sur IfThenElse_148.else, EG:25633-25637) : établi.
  • La voie Room ne lit ni Variables ni AI (RM, nœuds cités au § 3.2) ; le seul accès à Variables est le repli GetVariable('') de Dress, qui rend un tableau Person vide (journal), donc pas l'entrée AI de F-a, qui contient [AIDummy] (estimé : GetVariable 5.8 non dumpée).
  • « Le même chemin existait-il avant F-a ? » : oui, la branche IA de Room et le repli de Dress ne dépendent pas d'AI (estimé, lecture statique). Le déclencheur, la compagne qui suit le joueur, varie avec le parcours (piège de la rubrique 5) : 15 lignes dans J4, 0 dans C0 et J3.
  • Ordre des lignes : aucun CHECKING: … .lpai ni [AI] … moves to dans les paquets ; les paquets Room tombent au rafraîchissement de Room en fin de scène, juste avant UNHIDE (unhidePersonsNotInvolved, RM:3340-3343, après GenerateUnknownNpcs, RM:3171-3179).
  • Essai décisif (non fait, interdit ici) : rejouer avec GI B8B97C46 (sans F-a) un parcours où la compagne suit le joueur dans deux bâtiments, puis compter GetSpecific_PersonToReturn et GI_C:Dress: dans le journal.

3.5 Coût et saccades (Q-d)

  • Hors Shipping, chaque avertissement construit la pile de script (SC:711-719) ; 2 887 avertissements donnent 20 209 lignes par paquet.
  • L'horodatage et la trame sont lus au formatage de la ligne (FDateTime::UtcNow, GFrameCounter, OH:29-30). Bornes établies : paquet 1 : trame 648 encore en cours à 20:08:09.362 (14708) ; première ligne [649] à .441 (30010) ; trame 648 ≥ 79 ms. Paquet 5 : trame 184 de .086 (101010) à au moins .320 (132876) ; première [185] à .331 (132879) ; trame 184 ≥ 234 ms. Trame normale ≈ 16-17 ms (trames 520-551, lignes 7242-7299). Les autres paquets Room couvrent 92 à 138 ms de journal.
  • Estimé : les « saccades / gels » de fin de scène vus par l'utilisateur sont ces trames longues (1 à 11 par session), et le journal de 21 Mo est fait en majorité de ces paquets (≈ 32 713 × 7 lignes sur ≈ 283 000). En Shipping, la pile n'est pas construite (SC:711) : coût moindre, mais Dress parcourt toujours ses boucles sur None (estimé).

3.6 Commandes et comptes (Grep, outil ; chemins du § en-tête)

Motif Fichier Résultat
UNHIDE Persons J4 / C0 / J3 25 / 27 / 30
GI_C:Dress:64X (count) J4 32 713
Accessed None.*property Person (1re occurrence) J4 14720, removeAlreadyGot, 20:08:09.362
of length 0 in '/Game/Structs/Variable|property CallFunc_GetSpecific_PersonToReturn|GI_C:removeAlreadyGot:|DestroyDummy was from getKnown J4 221 lignes (dont résumé LogLifePlay : 80 GetSpecific, 30 removeAlreadyGot, l. 283772-283773)
moves to J4 / C0 / J3 41 / 22 / 46
\[Person_C_\d+\] \d+ moves to J4 / C0 / J3 15 / 0 / 0
CallFunc_Array_Get_Item in not an UClass J4 17
^\[2026\.10\.10-20\.08\.09:\d+\]\[648\] (count) J4 4 376 ; 1re [649] : 30010 ; 1re [650-653] : 30140
LogBlueprintUserMessages.*Person_C_2147481884 J4 SPAWN 2031 ; Rebecca 2309 ; Slot: 1 2656

4. Verdict

  • Réfutée pour les paquets Room (10 sur 11, 29 827 blocs ≈ 91 %) : la personne nulle ne vient pas de PersonsUsedThisScene mais du résultat None de GetSpecific, utilisé sans test par Room puis par Dress.
  • Indécise pour le paquet clearScenePersons (1 sur 11) : un élément nul de PersonsUsedThisScene est établi, son auteur ne l'est pas ; AIDummy est exclu (estimé).
  • Cause du volume (établie) : Dress n'a aucune garde après son repli GetVariable (DR:738-740).
  • Imputation à F-a : non établie ; estimée improbable comme cause directe (déclencheur lié au parcours). Elle reste à trancher par l'essai du § 3.4.

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

H6 : « la branche IA de Room.getKnownNpcsHere appelle GetSpecific sur la clé d'IA d'une personne déjà présente (la compagne), reçoit None et le transmet à Dress ; F-a n'y prend aucune part ». À confirmer par les dumps STE-D7 ci-dessous (N3, lp-cart) puis par l'essai sans F-a (preuve en jeu, décision de l'utilisateur). Correctif éventuel : SPEC N3, IMPL par MCP N2-N3.

Dumps manquants (lot STE-D7) ; arrêt sur ces points (rien lancé ici) :

  • .\Tools\RunCommandlet.ps1 -Lot STE-D7 -Commandlet LPDumpFunction -Args '-BP=Person -Fn=setCurrentLocation -Pins -Exec' : écrivain d'AI_Currents, clé utilisée, message moves to.
  • .\Tools\RunCommandlet.ps1 -Lot STE-D7 -Commandlet LPDumpFunction -Args '-BP=GI -Fn=GetVariable -Pins -Exec' : valeur rendue pour un nom vide (repli de Dress).
  • .\Tools\RunCommandlet.ps1 -Lot STE-D7 -Commandlet LPDumpFunction -Args '-BP=GI -Fn=DestroyPerson -Pins -Exec' : sort d'AIDummy et d'un élément nul en fin de scène ; destruction d'acteurs éventuelle.

Correctifs possibles (Q-e), comparés sans trancher :

Option Lieu et nœuds (MCP) Nœuds Effet attendu Risque
O1 garde Room Room EventGraph : nouveau IsValid (macro) ; couper CallFunction_235.then → CallFunction_199.execute ; 235.then → IsValid.exec ; Is Valid → 199.execute ; Is Not Valid → Knot_1.InputPin ; InputObject ← 235.PersonToReturn 1 nœud, 1 coupure, 4 liens supprime les 10 paquets Room et l'entrée KnownNpcsHere["0"] = None qui alimente le paquet 5 (estimé) faible ; GetSpecific reste appelé à chaque rafraîchissement pour la clé de la compagne (déjà le cas)
O2 garde Dress GI.Dress : nouveau IsValid (macro, ou KismetSystemLibrary::IsValid + Branch : 2 nœuds) ; couper Knot_1.OutputPin → VariableSet_11.execute ; Knot_1 → IsValid.exec ; Is Valid → VariableSet_11.execute ; Is Not Valid → rien (fin) ; InputObject ← VariableGet Person (existant ou nouveau) 1-2 nœuds (+1 VariableGet éventuel), 1 coupure, 3-4 liens supprime les 11 paquets, quel que soit l'appelant masque la cause amont (None silencieux) ; GI est l'asset gelé partagé (rubrique 3)
O3 garde clearScenePersons GI.clearScenePersons : nouveau IsValid ; couper MacroInstance_0.LoopBody → CallFunction_13.execute ; LoopBody → IsValid.exec ; Is Valid → 13.execute ; Is Not Valid → rien (tour suivant) ; InputObject ← MacroInstance_0.Array Element 1 nœud, 1 coupure, 4 liens supprime le paquet 5 et les 6 Array_Get_Item par élément nul faible ; laisse les paquets Room
O4 retirer F-a .\Tools\Restore.ps1 -Lot STE-H5b (GI B8B97C46) 0 ramène le cas B (18 en C0) ; d'après le § 3.4, ne supprimerait pas les paquets Room si une compagne suit le joueur (estimé) perte du correctif F-a
O5 F-a limité retirer AI de Variables après la routine (nœud clearVariable('AI') après CallFunction_743) 1-2 nœuds aucun effet attendu sur la voie Room, qui ne lit pas AI (estimé) ; limiterait l'ajout d'AIDummy à PersonsUsedThisScene (§ 3.3) inutile pour ce symptôme
O6 GetSpecific numérique rendre Companion si Companion.SaveSlot == Slot sur la voie numérique de GetSpecific ≈ 4-6 nœuds la compagne « trouvée » au lieu de None change le comportement du jeu ; SPEC nécessaire

Questions pour l'utilisateur :

  • Q-H5c-1 : faire l'essai décisif (§ 3.4, GI sans F-a, compagne qui suit le joueur) avant de décider du sort de F-a, ou décider sans cet essai ?
  • Q-H5c-2 : quel correctif : O1, O2, O3, une combinaison (ex. O1 + O3, ou O2 seul), O4, ou aucun pour l'instant ?
  • Q-H5c-3 : lancer les trois dumps STE-D7 ci-dessus pour lever les points estimés (écrivain d'AI_Currents, repli de GetVariable, DestroyPerson) ?
  • Q-H5c-4 : corriger STE-J4.md § 4 (11 paquets au lieu de 13, début à 20:08:09 et non 20:06:42, pas de paquet de 3 444, paquets avant UNHIDE), ou laisser ce livrable faire foi ?
  • Q-H5c-5 (choix de conception) : la clé d'IA d'une personne déjà présente (compagne) doit-elle être sautée par Room (O1), ou résolue vers la personne présente (O6) ?

Tours : 44 / 60

Constats

  • Fichiers écrits : D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\STE-H5c-DIAG.md (seul fichier, fins de ligne LF).
  • Fichiers à commiter (dépôt jeu, branche ue5.8, par le gardien) : A Docs/Migration/etat/ST/STE/STE-H5c-DIAG.md.
  • Écarts à la fiche : aucun commandlet lancé ; L6f (GI 5.5) a servi à lister les écrivains de PersonsUsedThisScene, sans les broches d'exécution (gardes non vérifiables) ; décompte des tours estimé, python -I Tools/FicheStats.py --lot STE fait foi.
  • Point annexe : GetSpecific appelle clearVariable(Var) à son entrée (GS:977-981) ; avec Var vide (Room, RM:2617), effet non vérifié (fonction non lue ici).