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

16 KiB
Raw Blame History

Fiche STE-H5 — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-opus-5-5 — Agent lp-cart — Skills sk-protocol, ue-cpp-build, lp-commandlets, lp-paths

STE-H5-DIAG : variable AI absente pendant la rafale des routines d'IA (2026-10-10)

Lecture seule. Aucun éditeur, commandlet ni build. Abréviations (chemins sous D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\, sauf mention) :

  • EG = STE\dumps\GI__EventGraph_apres-GARDES.txt (état actuel, GI MD5 B8B97C46 selon l'orchestrateur) ;
  • EGS = STE\dumps\GI__EventGraph.txt (avant STE-GI) ; EGB = STB\dumps\GI__EventGraph.txt (époque du build STB-JEU2) ;
  • CFG = STE\dumps\GI__CallFunction_apres-GARDES.txt ; CV = STB\dumps\GI__clearVariable.txt ; CSP = STB\dumps\GI__clearScenePersons.txt ; GR = STA\dumps\GI__graphes.txt ;
  • L2 = D:\Game\LifePlay_Build_5.8_STB-JEU2_Development\Windows\LifePlay\Saved\Logs\LifePlay.log (journal STB-JEU2) ;
  • JM = D:\Game\LifePlay-master 5.8\Docs\Journal_Modifications.md ; RE = D:\Game\LifePlay-master 5.8\Docs\Registre_Erreurs.md.

Écart de source (consigne de l'orchestrateur) : EG remplace GI__EventGraph.txt. Les nœuds cités ont les mêmes numéros de ligne dans EGB, EGS et EG (contrôlé : CallArrayFunction_5412 EGB:6616-6623 = EG:6616-6623 ; IfThenElse_11057 EGB:7796-7800 = EG ; MacroInstance_45 EGB:25422-25428 = EG ; AddVariable('AI') EGS:25021 et 25153 = EG). La structure décrite ci-dessous est donc celle du build STB-JEU2 et celle de GI aujourd'hui.

1. Symptôme et reproduction

  • 24 lignes (test0104) for … hours by 0 dans L2, toutes entre 21:32:09 et 21:32:21 (Grep hours by sur L2 : 31 lignes, dont 24 by 0 de L2:20397 à L2:29995 et 7 by [1-4], dont L2:22437 by 4 au milieu de la rafale).
  • Première occurrence : image 297, la boucle de vérification des scènes passe par UpdateCheckForScenes → CheckConditionsWho (pile L2:20233-20246), crée puis détruit un mannequin (L2:20229, 20248) et écrit (test0304) DestroyDummy was from CheckScenes, WHO unmatched (L2:20254). Image 298 : routine d'IA PlayScene → ReadSceneLine → CallFunction → getActorVar, Attempted to access index 0 from array 'Person_24_…' of length 0 (L2:20255-20266), puis by 0 (L2:20397).
  • Contexte de la rafale : déplacement du joueur vers fast_food juste avant (UPDATE TIME ARRIVED L2:19380, LOAD ROOM fast_food L2:19383), donc temps de jeu écoulé et vérification des scènes relancée sur un nouveau lieu.
  • Reproduction : non rejouée (lecture seule). Sur le build J3 actuel, la garde G5 a retiré la ligne by 0 (consigne de l'orchestrateur) ; le symptôme n'est observable que dans L2.

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

H5-1 : AI n'est pas retirée par une routine d'IA ni par la fin d'une scène, mais par la boucle de vérification des scènes du joueur, qui vide toute la table des variables de scène (Array_Clear(Variables)) entre deux itérations de la boucle des fichiers .lpai d'un PNJ. Cette boucle ne pose AI qu'une fois, avant son départ, et avance par lots sur plusieurs images (macro Async) : les .lpai joués après un vidage trouvent AI absente.

3. Essai et résultat brut

Essai = lecture du graphe (EG) et confrontation au journal (L2). Aucun essai en jeu.

3.1 Où AI est posée (une fois par PNJ, avant la boucle)

  • LoopUpdateAI (CustomEvent_74, EG:24908-24910) → IfThenElse_134 (EG:24959-24963) → CheckingAiIndex = -1 (EG:24953-24958) → getAllSlots (EG:24911-24914) → AddVariable('AI', [AIDummy]) CallFunction_779 (EG:25017-25037) → nextAi = true (EG:25489-25494) → macro Async MacroInstance_49, ItersPerTck = 7 (EG:24915-24921) → IfThenElse_141 [nextAi] (EG:25484-25488) → CheckingAiIndex++ (EG:24945-24949) → UpdateAI() (EG:24941-24944). Completed → minuterie 1 s sur LoopUpdateAI (EG:24964-24974).
  • UpdateAI (CustomEvent_73, EG:24770-24772) → SetActorHiddenInGame(AIDummy) (EG:25292-25296) → IfThenElse_133 [AI_Untils[slot] <= HoursPassed] (EG:24831-24835, 24792-24796) → AIDummy.SaveSlot (EG:25072-25077) → IfThenElse_144 (EG:25505-25509) → Prefix, PopulateEachPerson, LoadPreset(StatOnly) (EG:25082-25087, 25565-25569, 25050-25056) → QueryStat('age') → IfThenElse_145 (EG:25510-25531) → mélange AI_High, AI_Med, LPAI (EG:24803-24827) → CheckingPkgIndex = 0 (EG:24862-24867) → AddVariable('AI', [AIDummy]) CallFunction_739 (EG:25149-25171) → nextAi = false (EG:25475-25480) → SkipAsync = false (EG:25864-25869) → macro Async MacroInstance_45, ItersPerTck = 3 (EG:25422-25428) → IfThenElse_148 [AIDummy.SaveSlot == 0] (EG:25742-25754) → else → PlayScene(LPAI[CheckingPkgIndex]) CallFunction_743 (EG:24891-24895) → CheckingPkgIndex++ (EG:24896-24900). Completed → nextAi = true (EG:25469-25474).
  • Aucun autre AddVariable('AI') : les cinq AddVariable de EG sont Companion (EG:7555-7559), AI × 2 (EG:25021, 25153), PregTemp (EG:26887-26891), ImpregTemp (EG:27025-27029). Rien ne repose AI entre deux PlayScene de MacroInstance_45.
  • Le corps de la boucle est lancé pour chaque .lpai de LPAI (17 fichiers .lpai sous vin_Base\AI qui appellent setUntil, STE-H3-SPEC.md:185) : à 3 par image, la routine d'un PNJ couvre plusieurs images.
  • La macro GI:Async avance par Delay(0) (établi en L7i, JM:737-739 ; macro non relue ici, pas de dump 5.8).

3.2 Où AI est effacée

  • Seule référence à la table Variables dans EG : VariableGet_4294 'Variables' → Array_Clear CallArrayFunction_5412 (EG:6616-6623). Grep variable '[A-Za-z_]*(Var|var)[A-Za-z_]*' sur EG → 10 lignes, une seule 'Variables' (EG:6616) ; les autres sont GlobalVariables et ActorVars.
  • Chemin : UpdateCheckForScenes (CustomEvent_5587, EG:5897-5899) → … → PrintString CHECKING: <scène> --- h1-h2 (test282) CallFunction_17120 (EG:7974-7985) → IfThenElse_3233 [délai dépassé] (EG:11762-11766) → else → IfThenElse_7289 [Actions ∋ CurrentAction ET Amenities ∋ CurrentAmenity] (EG:5924-5949) → then → IfThenElse_11057 [CheckConditionsWhen.Within] (EG:7791-7800) → then → Array_Clear(Variables) (EG:6619-6623) → DummyPersonsBefore (EG:24434-24439) → CheckConditionsWho CallFunction_8880 (EG:5955-5961) → IfThenElse_10838 [Matched] (EG:5962-5966) → else → PersU (EG:25315-25320) → ForEachLoop (EG:6627-6633) → IfThenElse_128 (EG:24448-24452) → destroyDummy CallFunction_639 (EG:23861-23866) → PrintString (test0304) DestroyDummy was from CheckScenes, WHO unmatched CallFunction_735 (EG:25216-25226).
  • Les deux autres entrées de IfThenElse_10838 sont mortes (CallFunction_16063 et _634, execute (vide), EG:7941-7943, 23674-23676), comme celle de IfThenElse_10904 (_16061, EG:7963-7965). Donc chaque ligne « WHO unmatched » du journal prouve un Array_Clear(Variables) exécuté juste avant, dans la même exécution.
  • Boucle de vérification : LoopCheckForScenes (CustomEvent_68, EG:23881-23883) → CheckingForScenes = true (EG:23915-23925) → PerTick = 12 ou 3 (EG:27383-27388, 30131-30142) → macro Async MacroInstance_39, ItersPerTck = PerTick (EG:23884-23890), condition Not(GamePaused) AND CheckingForScenes (EG:23946-23950).
  • Aucune exclusion mutuelle : la condition de MacroInstance_45 (BooleanAND_65, EG:24880-24887) ne lit ni CheckingForScenes ni nextAi ; celle de MacroInstance_49 (BooleanAND_68, EG:24931-24940 : index, MainMenuOn, SceneOn, followUp, CharGenOn, StatMenuOn, ContactsOn) non plus ; celle de MacroInstance_39 ne lit aucun état de la boucle d'IA. Les deux boucles latentes tournent en même temps et partagent Variables.

3.3 Pistes de la fiche écartées (lecture)

  • Entrelacement de deux routines d'IA : impossible, la boucle externe n'appelle UpdateAI que si nextAi est vrai (EG:25484-25488) ; nextAi passe à faux pendant MacroInstance_45 (EG:25475-25480) et redevient vrai à sa fin (EG:25469-25474). Les routines des PNJ sont successives.
  • Fin de scène : l'événement ClearSceneVariables (appelé au début de chaque PlayScene, EG:17189-17194 → EG:6070-6073) ne remet à zéro que CurrentLine, CurrentLinePerson, SneakPassed (EG:6061-6069, 10011-10016, 18837-18842) ; clearScenePersons est sauté pour un .lpai (IfThenElse_137, Not(EndsWith '.lpai'), EG:25330-25334, 25404-25421) et ne lit pas Variables (CSP, Grep variable ' : PersonsUsedThisScene, pe, Companion, Interacting, …).
  • clearVariable : GetVariable puis DestroyPerson, sans lecture de Variables (CV:120-271).
  • Fonctions dumpées (CFG, GI__CheckConditionsWho.txt, GI__ReadSceneLine.txt) : Grep variable 'Variables' → 0 chacune. GR ne liste que quatre fonctions de variables : AddVariable, GetVariable, ConvertAnyVariablesToText, clearVariable (GR:46-57, 288).

3.4 Journal (L2)

  • Grep DestroyDummy was from CheckScenes, WHO unmatched : 185 lignes dans L2, 102 entre 21:32:09 et 21:32:21.
  • Grep ^\[2026\.10\.09-21\.32\.(09|1\d|2[0-2]).*(WHO unmatched|hours by|testscene|DestroyDummy) : chaque groupe de by 0 suit un WHO unmatched (donc un vidage) : première ligne du groupe ← dernier vidage, en images : 298←297, 404←401, 513←502, 517←514, 525←521, 617←608, 676←666, 688←684, 787←781, 799←798, 893←888, 903←902, 992←988, 998←996.
  • Les deux boucles alternent dans la même image : CHECKING: …religious_discussion_family.lpscene --- 0.0-24.0 (L2:20524, image 306) puis by 0 (L2:20647, image 306) ; une ligne CHECKING: par image de 296 à 319 (Grep ^\[2026\.10\.09-21\.32\.09:\d+\]\[(29[6-9]|30\d|31\d)\]LogBlueprintUserMessages).
  • Effet de cascade (estimé fort) : avec AI absente, setUntil écrit AI_Untils["0"] et non AI_Untils[slot] (STE-H3-SPEC.md:133, 151-152) ; la condition C de MacroInstance_45 (AI_Untils[slot] <= HoursPassed, EG:24792-24796 → EG:24885) reste vraie et la boucle continue sur les .lpai suivants, d'où plusieurs by 0 par PNJ (groupes de 3 aux images 298/306/314, 404/414/416, 617/621/623). Un PNJ dont un .lpai réussit dans le premier lot, avant tout vidage, sort normalement (by 4 L2:22437, by 2 L2:30423).
  • Antécédent : le mécanisme a été vu en L7i sur la copie 5.5 (JM:727-730, 737-744) et ERR-003 est clos avec « AI introuvable seulement en jeu accéléré (interférence boucle des scènes / boucle d'IA, même mécanisme en 4.27) » (RE:17) ; A/B à parcours identique : 0 erreur AI par minute en 4.27 et en 5.5 (JM:750-759). Ce DIAG ajoute les nœuds exacts de 5.8 (CallArrayFunction_5412, CallFunction_739, MacroInstance_45) et la cascade.

4. Verdict : confirmée

H5-1 confirmée par lecture statique et journal, sans essai en jeu :

  1. AI n'est posée qu'une fois par PNJ (CallFunction_739, EG:25149-25171) avant une boucle latente de plusieurs images (MacroInstance_45, EG:25422-25428 ; Delay(0) JM:738) ;
  2. la boucle de vérification des scènes vide toute la table (Array_Clear(Variables), EG:6616-6623) à chaque scène candidate qui passe action, lieu et heure (EG:5924-5949, 7791-7800), sans exclusion avec la boucle d'IA (§ 3.2) ;
  3. dans L2, chaque groupe de by 0 suit un vidage prouvé par WHO unmatched (§ 3.4), la première ligne à une image d'écart (L2:20254 → L2:20397). Ce n'est pas une régression 5.8 : défaut d'origine, préexistant en 4.27, révélé par le rythme de jeu (déplacement ou temps accéléré : beaucoup de PNJ à traiter et vérification relancée sur un nouveau lieu) (RE:17, JM:758-759).

Correctif proposé (non appliqué ; change un comportement visible : question Q-H5-1 à l'utilisateur) :

  • F-a (le plus petit, local à la boucle d'IA) : reposer AI avant chaque .lpai. Ajouter un AddVariable (Name 'AI', Class 'Person', Array false, Person = MakeArray[AIDummy], copie de CallFunction_739) entre IfThenElse_148.else et CallFunction_743.execute (EG:25750-25754, 24891-24895) : rompre 148.else → 743.execute, relier 148.else → nouveau.execute et nouveau.then → 743.execute. L'autre entrée de 743 (MacroInstance_43.LoopBody) est morte (WhileLoop sans execute, EG:24975-24979). Effet attendu : les routines d'IA s'appliquent au PNJ (lieu courant, AI_Untils[slot]) au lieu de la clé "0" ; la boucle s'arrête au premier .lpai qui réussit, donc moins de routines jouées par PNJ ; les gardes G1-G11 deviennent sans effet pour le cas B (elles restent utiles au cas A).
  • F-b (écartée ici) : exclusion mutuelle (lire CheckingForScenes ou nextAi dans les conditions des macros Async) change la cadence des deux boucles ; F-c (vider seulement les variables de la scène vérifiée) touche le chemin des scènes du joueur. Les deux sont plus invasives que F-a.

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

Sans objet comme hypothèse concurrente (H5-1 confirmée). Suites proposées :

  • Décision utilisateur (Q-H5-1) : (A) laisser le défaut d'origine, masqué par G1-G11 (ERR-003 reste clos, comportement 4.27 conservé) ; ou (B) appliquer F-a (comportement des PNJ modifié en jeu accéléré).
  • Si (B) : SPEC + IMPL par MCP (N2-N3, lp-mcp, instantané Tools/Snapshot.ps1), puis preuve en jeu (N2, parcours de STB-JEU2 avec déplacement) : hours by [1-9] en hausse ; clé "0" absente de AI_Untils dans la sauvegarde (LPDumpSave, lp-commandlets) ; aucun getActorVar/setActorVar sur Person vide sous PlayScene d'un .lpai.
  • Confirmations statiques facultatives (N1, si l'orchestrateur le demande ; non lancées, interdit de la fiche) : .\Tools\RunCommandlet.ps1 -Lot STE -Commandlet LPDumpFunction -Args '-BP=GI -Fn=GetVariable -Pins -Exec' (variable non trouvée → structure vide, JM:729) et -Fn=AddVariable (remplacement par nom). La macro Async est un graphe de macro : LPDumpFunction la lit-il ? incertain, à essayer.

Tours : 44 / 60

Constats

Établi / estimé / incertain :

  • Établi : chemins et nœuds du § 3.1 et du § 3.2 (EG), seule référence Variables = EG:6616, entrées mortes de IfThenElse_10838, absence d'exclusion entre les trois macros Async, comptes L2 (24 by 0, 185 et 102 WHO unmatched), ordre image 297 → 298.
  • Établi par un lot antérieur, non relu ici : Async = Delay(0) (JM:738) ; GetVariable rend une variable vide si le nom est absent (JM:729) ; même mécanisme en 4.27 (RE:17, JM:750-759).
  • Estimé : cascade AI_Untils["0"] → boucle prolongée (§ 3.4) ; groupes de by 0 = un même PNJ ; CallFunction_827 (terme E de la condition de MacroInstance_45, EG:25986-25990) non lu.
  • Incertain : contenu de AddVariable / GetVariable (non dumpés en 5.8) ; accès à GI.Variables depuis un autre Blueprint (non cherché hors GI).

Constat annexe (hors hypothèse) : AIDummy n'est écrit dans EG que par VariableSet_258 et VariableSet_276, sur une chaîne sans entrée d'exécution (VariableSet_275 TempAI, execute (vide), EG:25362-25376 → destroyDummy → PrintString « DestroyDummy was from LoopUpdateAI » → SpawnDummy → VariableSet_258, EG:25041-25046, 25238-25248, 25006-25016) ; aucune ligne « was from LoopUpdateAI » dans L2. AIDummy est donc posé ailleurs (fonction ou autre Blueprint, non cherché) ; il est valide au moment de l'erreur (JM:727) et IfThenElse_148 l'exige (SaveSlot != 0).

Questions pour l'utilisateur :

  • Q-H5-1 : corriger le défaut d'origine par F-a (comportement visible modifié) ou le laisser masqué (ERR-003 clos) ?

Fichiers écrits : D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\STE-H5-DIAG.md. Fichiers à commiter (dépôt du jeu, branche ue5.8, par le gardien) :

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