16 KiB
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 0dans L2, toutes entre 21:32:09 et 21:32:21 (Grephours bysur L2 : 31 lignes, dont 24by 0de L2:20397 à L2:29995 et 7by [1-4], dont L2:22437by 4au 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'IAPlayScene→ReadSceneLine→CallFunction→getActorVar,Attempted to access index 0 from array 'Person_24_…' of length 0(L2:20255-20266), puisby 0(L2:20397). - Contexte de la rafale : déplacement du joueur vers
fast_foodjuste avant (UPDATE TIME ARRIVEDL2:19380,LOAD ROOM fast_foodL2: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) → macroAsyncMacroInstance_49,ItersPerTck = 7(EG:24915-24921) →IfThenElse_141[nextAi] (EG:25484-25488) →CheckingAiIndex++(EG:24945-24949) →UpdateAI()(EG:24941-24944).Completed→ minuterie 1 s surLoopUpdateAI(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élangeAI_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) → macroAsyncMacroInstance_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 cinqAddVariablede EG sontCompanion(EG:7555-7559),AI× 2 (EG:25021, 25153),PregTemp(EG:26887-26891),ImpregTemp(EG:27025-27029). Rien ne reposeAIentre deuxPlayScenedeMacroInstance_45. - Le corps de la boucle est lancé pour chaque
.lpaideLPAI(17 fichiers.lpaisousvin_Base\AIqui appellentsetUntil,STE-H3-SPEC.md:185) : à 3 par image, la routine d'un PNJ couvre plusieurs images. - La macro
GI:Asyncavance parDelay(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
Variablesdans EG :VariableGet_4294 'Variables'→Array_ClearCallArrayFunction_5412(EG:6616-6623). Grepvariable '[A-Za-z_]*(Var|var)[A-Za-z_]*'sur EG → 10 lignes, une seule'Variables'(EG:6616) ; les autres sontGlobalVariablesetActorVars. - Chemin :
UpdateCheckForScenes(CustomEvent_5587, EG:5897-5899) → … →PrintStringCHECKING: <scène> --- h1-h2 (test282)CallFunction_17120(EG:7974-7985) →IfThenElse_3233[délai dépassé] (EG:11762-11766) →else→IfThenElse_7289[Actions∋CurrentActionETAmenities∋CurrentAmenity] (EG:5924-5949) →then→IfThenElse_11057[CheckConditionsWhen.Within] (EG:7791-7800) →then→Array_Clear(Variables)(EG:6619-6623) →DummyPersonsBefore(EG:24434-24439) →CheckConditionsWhoCallFunction_8880(EG:5955-5961) →IfThenElse_10838[Matched] (EG:5962-5966) →else→PersU(EG:25315-25320) →ForEachLoop(EG:6627-6633) →IfThenElse_128(EG:24448-24452) →destroyDummyCallFunction_639(EG:23861-23866) →PrintString(test0304) DestroyDummy was from CheckScenes, WHO unmatchedCallFunction_735(EG:25216-25226). - Les deux autres entrées de
IfThenElse_10838sont mortes (CallFunction_16063et_634,execute (vide), EG:7941-7943, 23674-23676), comme celle deIfThenElse_10904(_16061, EG:7963-7965). Donc chaque ligne « WHO unmatched » du journal prouve unArray_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) → macroAsyncMacroInstance_39,ItersPerTck = PerTick(EG:23884-23890), conditionNot(GamePaused) AND CheckingForScenes(EG:23946-23950). - Aucune exclusion mutuelle : la condition de
MacroInstance_45(BooleanAND_65, EG:24880-24887) ne lit niCheckingForScenesninextAi; celle deMacroInstance_49(BooleanAND_68, EG:24931-24940 : index,MainMenuOn,SceneOn,followUp,CharGenOn,StatMenuOn,ContactsOn) non plus ; celle deMacroInstance_39ne lit aucun état de la boucle d'IA. Les deux boucles latentes tournent en même temps et partagentVariables.
3.3 Pistes de la fiche écartées (lecture)
- Entrelacement de deux routines d'IA : impossible, la boucle externe n'appelle
UpdateAIque sinextAiest vrai (EG:25484-25488) ;nextAipasse à faux pendantMacroInstance_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 chaquePlayScene, EG:17189-17194 → EG:6070-6073) ne remet à zéro queCurrentLine,CurrentLinePerson,SneakPassed(EG:6061-6069, 10011-10016, 18837-18842) ;clearScenePersonsest sauté pour un.lpai(IfThenElse_137,Not(EndsWith '.lpai'), EG:25330-25334, 25404-25421) et ne lit pasVariables(CSP, Grepvariable ':PersonsUsedThisScene,pe,Companion,Interacting, …). clearVariable:GetVariablepuisDestroyPerson, sans lecture deVariables(CV:120-271).- Fonctions dumpées (CFG,
GI__CheckConditionsWho.txt,GI__ReadSceneLine.txt) : Grepvariable '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 deby 0suit unWHO 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) puisby 0(L2:20647, image 306) ; une ligneCHECKING: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
AIabsente,setUntilécritAI_Untils["0"]et nonAI_Untils[slot](STE-H3-SPEC.md:133, 151-152) ; la condition C deMacroInstance_45(AI_Untils[slot] <= HoursPassed, EG:24792-24796 → EG:24885) reste vraie et la boucle continue sur les.lpaisuivants, d'où plusieursby 0par PNJ (groupes de 3 aux images 298/306/314, 404/414/416, 617/621/623). Un PNJ dont un.lpairéussit dans le premier lot, avant tout vidage, sort normalement (by 4L2:22437,by 2L2: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
«
AIintrouvable 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 erreurAIpar 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 :
AIn'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) ;- 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) ; - dans L2, chaque groupe de
by 0suit un vidage prouvé parWHO 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
AIavant chaque.lpai. Ajouter unAddVariable(Name 'AI',Class 'Person',Array false,Person = MakeArray[AIDummy], copie deCallFunction_739) entreIfThenElse_148.elseetCallFunction_743.execute(EG:25750-25754, 24891-24895) : rompre148.else → 743.execute, relier148.else → nouveau.executeetnouveau.then → 743.execute. L'autre entrée de743(MacroInstance_43.LoopBody) est morte (WhileLoopsansexecute, 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.lpaiqui 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
CheckingForScenesounextAidans les conditions des macrosAsync) 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 deAI_Untilsdans la sauvegarde (LPDumpSave,lp-commandlets) ; aucungetActorVar/setActorVarsurPersonvide sousPlayScened'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 macroAsyncest un graphe de macro :LPDumpFunctionla 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 deIfThenElse_10838, absence d'exclusion entre les trois macrosAsync, comptes L2 (24by 0, 185 et 102WHO unmatched), ordre image 297 → 298. - Établi par un lot antérieur, non relu ici :
Async=Delay(0)(JM:738) ;GetVariablerend 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 deby 0= un même PNJ ;CallFunction_827(terme E de la condition deMacroInstance_45, EG:25986-25990) non lu. - Incertain : contenu de
AddVariable/GetVariable(non dumpés en 5.8) ; accès àGI.Variablesdepuis 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