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

30 KiB

Fiche STE-H3b — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-opus-5-5 — Agent lp-cart — Skills sk-protocol, lp-mcp (§ 3-4), lp-commandlets, lp-paths, ue-cpp-build (préchargés), lp-doc (gabarits)

STE-H3b-SPEC : gardes F2 / F3 restantes du moteur de scènes (sites get / set / modifyActorVar, _30, _41) (2026-10-10)

Lecture seule stricte (aucun éditeur, commandlet, build ni écriture hors de ce fichier). Copie D:\Game\LifePlay-master 5.8, branche ue5.8. Gabarit SPEC : D:\Game\LifePlay-master 5.8\.claude\skills\lp-doc\gabarits.md:36-38. Suite de STE-H3-SPEC.md (gardes G1 à G6) : mêmes conventions (§ 2.1 de H3S), numérotation G7 et suivantes, R9 et Q4 et suivants. Statut : partiel. 4 gardes spécifiées (G7, G8, G10, G11) ; G9 (modifyActorVar) arrêtée : dump de la fonction absent (§ 2.4) ; G10 et G11 ont deux variantes, choix de l'utilisateur (Q4, Q5).

Abréviations (chemins absolus) :

  • D = D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\dumps\ ; CF = D GI__CallFunction.txt ; CRB = D GI__CallFunctionReturnBool.txt (585 nœuds, STE-D2) ; GAV = D GI__getActorVar.txt ;
  • H3S = D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\STE-H3-SPEC.md ;
  • L2 = D:\Game\LifePlay_Build_5.8_STB-JEU2_Development\Windows\LifePlay\Saved\Logs\LifePlay.log (journal STB-JEU2) ;
  • AI = D:\Game\LifePlay-master 5.8\Content\Modules\vin_Base\AI\ (routines .lpai) ;
  • UE = D:\Game\Launcher\Engine\UE_5.8\Engine\Source\ (moteur installé, lu).

État du Blueprint : MD5 de Content\BPs\GI.uasset = 606eb43714c1f4317300b797edd02e62 (commande md5sum "/d/Game/LifePlay-master 5.8/Content/BPs/GI.uasset"), égal à l'état STE-GI (STE-TACHES.md:17, « GI 606EB437… ») ; git status --short -- Content/BPs/GI.uasset = M (STE-GI non commité) ; dernier commit du fichier bc4d91f (STC). Les dumps D datent de STE-D / STE-D2 (MD5 d93785fc…) ; STE-GI n'a touché que l'EventGraph (fiche § 3) : les nœuds de CallFunction et CallFunctionReturnBool cités ici sont ceux du GI actuel (estimé fort ; contrôle P4). STE-H3 (G1-G6) n'est pas encore implémentée (STE-TACHES.md:19).

1. Objectif mesurable

Supprimer, sans changer ce que le jeu fait, les lectures restantes de personnage vide citées par Q3 de H3S (H3S:196-198, décision « oui, fiche à part », STE-TACHES.md:32). Référence L2, comptes Grep rejouables (§ Constats) :

Famille (motif Grep sur le journal de jeu) L2 Attendu après H3 + H3b
F3, property CallFunc_Array_Get_Item_41 (CallFunctionReturnBool) 14 0 (G11)
F3, property CallFunc_Array_Get_Item_30 (CallFunction) 4 0 (G10 ; 4 si Q4 = c)
F2 suivie d'un F1 dans getActorVar (multiligne, § Constats) 71 F2 du site supprimée (G7)
F2 suivie d'un F1 dans setActorVar (multiligne) 16 F2 du site supprimée (G8)
F2 suivie de _41 ou de Per (multiligne) 9 (7 + 2) 2 (les 2 Per de getRelatedPerson restent, R13)
F2 Person_24_4B712C904750AD4CE1580DBEBD9E7396' of length 0 / CHECKING: 351 / 2 318 baisse de 94 lignes (71 + 16 + 7) à parcours égal, en plus de H3
property Per in (getRelatedPerson) 4 4 (hors SPEC, R13)

Gardes : CallFunction site getActorVar (G7, 2 nœuds), site setActorVar (G8, 2 nœuds), site modifyActorVar (G9, arrêtée), commande getUntil (G10, _30, 7 nœuds en variante a) ; CallFunctionReturnBool commande hasRelationship (G11, _41, 6 nœuds en variante a). Total (variantes a) : 17 nœuds créés, 4 break_pins, 37 connect_pins, 3 set_pin_value (+ relectures), 0 suppression.

2. Fichiers touchés, ordre

Un seul fichier : Content\BPs\GI.uasset, graphes de fonction CallFunction (G7, G8, G10) et CallFunctionReturnBool (G11). Ni l'EventGraph, ni les fonctions appelées (getActorVar, setActorVar, modifyActorVar, getRelatedPerson, hasRelationship), ni le C++, ni le contenu des modules. Ordre : après l'IMPL de STE-H3 (G1 à G6), puis G8, G7 (exige G2), G11, G10. G9 : non exécutable (§ 2.4).

2.0 Préalables (dans l'ordre, avant tout create_node)

  • P1. IMPL STE-H3 faite (G1-G6 compilées, enregistrées) ; réponses de l'utilisateur à Q4 (G10) et Q5 (G11).
  • P2. Dumps « avant » neufs des 2 graphes (GI a changé avec STE-GI puis changera avec H3) : .\Tools\RunCommandlet.ps1 -Lot STE-H3b -Commandlet LPDumpFunction -Args '-BP=GI -Fn=CallFunction -Pins -Exec' et ... -Args '-BP=GI -Fn=CallFunctionReturnBool -Pins -Exec' ; MD5 de GI.uasset relevé (valeur de retour du repli).
  • P3. Gel annoncé (lp-mcp § 1.7), .\Tools\Snapshot.ps1 -Lot STE-H3b (GI.uasset), AssetTools.load_asset /Game/BPs/GI.
  • P4. Pour chaque nœud existant cité : get_node_infos {nodes:[{refPath:"/Game/BPs/GI.GI:<Graphe>.K2Node_<Nom>"}]} ; les liens doivent égaler la colonne « avant » (§ 2.2 à 2.6) ; tout écart arrête la garde concernée.
  • P5. type_id hors lp-mcp § 3 (G10, G11 seulement), lus par find_node_types {graph:{refPath:"/Game/BPs/GI.GI:<Graphe>"}, type_id_filter:"<filtre>", context_pins:[]} ; après create_node, get_node_infos doit montrer la classe et la fonction attendues, sinon arrêt et repli (§ 3) :
Nœud Filtre Attendu (estimé) Contrôle get_node_infos
AddVariable (G10-A) AddVariable Classe|GI|AddVariable (forme lp-mcp § 3) appel GI_C::AddVariable, broches comme CallFunction_203
Map Find (G10-F, variante a) Map puis Find catégorie Utilities|Map, nom Find (UE Runtime\Engine\Classes\Kismet\BlueprintMapLibrary.h:48-49), libellé localisé à lire fonction Map_Find, pure
Make Array (G10-M) Array / Tableau nœud K2Node_MakeArray (libellé localisé incertain) classe K2Node_MakeArray
hasRelationship (G11-H, variante a) hasRelationship Classe|GI|hasRelationship appel GI_C::hasRelationship, pur (pas de broche execute) comme CallFunction_177622
Set BoolToReturn (G11-S) BoolToReturn Variables|…|DéfinirBoolToReturn (lp-mcp § 3) K2Node_VariableSet de la même variable que VariableSet_57739 (`

2.1 Conventions communes

Reprises à l'identique de H3S § 2.1 (H3S:55-70) : type_id Branch = Utilitaires|ContrôleDeFlux|Branche, IsValid = Utilitaires|IsValid, IsValidIndex = Utilitaires|Tableau|IsValidIndex ; indices de broches par direction (Branch entrée exécution 0 / Condition 1, sorties then 0 / else 1 ; VariableSet entrées exécution 0 / valeur 1, sortie then 0 ; tous les autres relus par get_node_infos avant connect_pins, valeurs attendues estimées : IsValid Object entrée 1, ReturnValue sortie 0 ; IsValidIndex TargetArray entrée 1, Index entrée 2, ReturnValue sortie 0) ; IsValidIndex Index laissé à 0 (relu) ; cascades de Branch, jamais AND / OR / Select purs ; une sortie de données peut alimenter plusieurs entrées, une entrée d'exécution peut recevoir plusieurs liens ; après chaque graphe : compile_blueprint + hyper_blueprint_debug_inspect {blueprintAssetPath:"/Game/BPs/GI.GI", graphName:"<Graphe>"} = 0 diagnostic ; save_assets {asset_paths:["/Game/BPs/GI"]} à la fin. Ajouts H3b : nom complet de la broche du tableau = Person_24_4B712C904750AD4CE1580DBEBD9E7396 (noté Person_24_…) ; broches génériques (wildcard) : câbler d'abord la broche typée (G10-F.TargetMap avant Key ; G10-M.Array vers G10-A.Float avant [0]), puis set_pin_value ; valeur littérale relue par get_node_infos. « Chemin non valide » (lp-mcp § 4) : refaire ce que l'exécution fait aujourd'hui avec la référence nulle. Avec un contexte nul, la VM saute l'expression et efface la valeur rendue (UE Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:3234-3244) : Prefix lu = "", SaveSlot lu = 0, donc la clé Prefix + Conv_IntToString(SaveSlot) vaut "0" (établi).

2.2 G7 — site getActorVar de CallFunction (F2 : 71 dans L2) — CF

Avant : CallFunction_141 (GetVariable, cas SwitchString_22.getActorVar) .then → CallFunction_142.execute, Variable → BreakStruct_40 (CF:4793-4798) ; BreakStruct_40.Person_24_… → GetArrayItem_51.Array (CF:4801-4809), index 0, Output → 142.Person (CF:4811-4814) ; 142 = getActorVar (fonction de GI, self vide), then → CallFunction_143.execute, Var ← GetArrayItem_52, Float → MakeArray_96.[0] (CF:4815-4821) ; 143 = AddVariable (Name ← VariableGet_103, Class = 'Float', Float ← MakeArray_96), then vide (CF:4828-4846). Après : IsValidIndex G7-I, Branch G7-B ; break_pins (141.then, 142.execute) ; connect_pins (5) : 141.then → G7-B.execute (0) ; BreakStruct_40.Person_24_… → G7-I.TargetArray ; G7-I.ReturnValue → G7-B.Condition (1) ; G7-B.then (0) → 142.execute ; G7-B.else (1) → 143.execute. Comportement : aujourd'hui, tableau vide → F2 (UE Runtime\Engine\Private\KismetArrayLibrary.cpp:472-478), getActorVar(None) rend, une fois G2 posée, FunctionResult_1.Float = '0.0' (GAV:125-127, H3S § 2.3), puis 143 écrit [0.0]. Après : 142 non exécuté, 143 lit la sortie Float de 142 jamais écrite dans ce cadre ; le cadre de CallFunction (fonction, pas l'ubergraph) est alloué et mis à zéro à chaque appel (UE ScriptCore.cpp:984-993 ; cadre persistant réservé à l'ubergraph, UE Runtime\Engine\Private\BlueprintGeneratedClass.cpp:1882-1897) : [0.0]. Identique à l'état après G2 (estimé fort) ; par rapport à l'état actuel (avant G2), identique si ActorVars n'a pas de clé "0" (R1 de H3S, déjà accepté par Q1 = A). Élément nul dans un tableau de longueur 1 : pas de F2, G2 le traite dans getActorVar (R14).

2.3 G8 — site setActorVar de CallFunction (F2 : 16 dans L2) — CF

Avant : CallFunction_150 (GetVariable, cas setActorVar) .then → CallFunction_162.execute, Variable → BreakStruct_45 (CF:4851-4860) ; BreakStruct_45.Person_24_… → GetArrayItem_63.Array (CF:4867), index 0, Output → 162.Person (CF:4869-4872) ; 162 = setActorVar (Var ← GetArrayItem_64, Float ← GetArrayItem_65), then vide (CF:4873-4879). Après : IsValidIndex G8-I, Branch G8-B ; break_pins (150.then, 162.execute) ; connect_pins (4) : 150.then → G8-B.execute ; BreakStruct_45.Person_24_… → G8-I.TargetArray ; G8-I.ReturnValue → G8-B.Condition ; G8-B.then → 162.execute. G8-B.else : rien. Comportement : setActorVar(None) n'écrit rien, avant comme après G1 (H3S § 2.2, établi), et 162.then est vide. Après : rien n'est appelé. Identique (établi).

2.4 bis G9 — complément de l'orchestrateur LOT STE (2026-10-10, après STE-D3)

Dump STE-D3 dumps\GI__modifyActorVar_D3.txt (31 nœuds, code 0). modifyActorVar(Person = None) : Prefix et SaveSlot lus sur la personne vide (avertissements Accessed None), clé Concat("" , "0") = "0", Map_Find puis boucle, puis Map_Add(ActorVars, "0", …) : écriture parasite de ActorVars["0"] (CallFunction_1, CallArrayFunction_1). Les 5 fonctions déjà dumpées sont identiques ligne pour ligne entre STE-D / STE-D2 et STE-D3 (GI 606EB437…) : les nœuds cités par cette SPEC restent valables. Forme retenue : celle de G8. IsValidIndex G9-I, Branch G9-B ; break_pins (CallFunction_144.then, CallFunction_163.execute) ; connect_pins (4) : 144.then → G9-B.execute ; BreakStruct_39.Person_24_… → G9-I.TargetArray ; G9-I.ReturnValue → G9-B.Condition ; G9-B.then → 163.execute. G9-B.else : rien (163.then est vide, CF:5143-5149). Comportement : avec une personne, identique ; sans personne, l'écriture ActorVars["0"] et les avertissements disparaissent. Décision de l'utilisateur (2026-10-10, dans la session LOT STE) : « Oui, poser G9 », par analogie avec Q2 (G5). L2 : 0 occurrence (Grep GI_C:modifyActorVar = 0).

2.4 G9 — site modifyActorVar de CallFunction — arrêtée (dump manquant)

Structure relevée : CallFunction_144 (GetVariable, cas modifyActorVar) .then → CallFunction_163.execute, Variable → BreakStruct_39 (CF:5111-5120) ; BreakStruct_39.Person_24_… → GetArrayItem_49.Array (CF:5127), index 0, Output → 163.Person (CF:5129-5132) ; 163 = modifyActorVar (Var ← GetArrayItem_50, Float ← GetArrayItem_53), then vide (CF:5143-5149). Forme probable : celle de G8 (IsValidIndex + Branch, else vide). Blocage : ce que fait modifyActorVar(None) (chemin « non valide ») ne se lit dans aucun dump (Glob **/*modifyActorVar* sous etat\ : 0 fichier). Garde non spécifiée, sans improviser. Commande à joindre à un STE-D3 : .\Tools\RunCommandlet.ps1 -Lot STE-D -Commandlet LPDumpFunction -Args '-BP=GI -Fn=modifyActorVar -Pins -Exec'. Constat L2 : 0 lecture fautive dans modifyActorVar (Grep GI_C:modifyActorVar : 0 ligne) ; la F2 de ce site, si elle existe, n'est pas attribuable (le message F2 ne nomme pas la fonction).

2.5 G10 — commande getUntil de CallFunction (F3 _30, 4 dans L2) — CF, variante selon Q4

Avant : CallFunction_200 (GetVariable, cas getUntil) .then → CallFunction_203.execute, Variable → BreakStruct_56 (CF:5674-5683) ; BreakStruct_56.Person_24_… → GetArrayItem_78.Array (CF:5690), index 0, Output → VariableGet_150.self (Prefix) et VariableGet_151.self (SaveSlot) (CF:5692-5701) → Conv_IntToString 201 et Concat_StrStr CommutativeAssociativeBinaryOperator_3 → CallFunction_202.Key (CF:5702-5710) ; 202 = Map_Find pur, TargetMap ← VariableGet_152.AI_Untils, Value → MakeArray_147.[0] (CF:5711-5719) ; 203 = AddVariable (Name ← VariableGet_153.VariableName, Class = 'Float', Array = 'false', Bool ← MakeArray_149, Float ← MakeArray_147, String ← MakeArray_148, Person ← MakeArray_146, Building vide), then vide (CF:5720-5742). Pourquoi pas « else → 203 » comme G6 : l'entrée Float de 203 vient d'une chaîne pure (Map_Find ← Concat ← Prefix / SaveSlot ← GetArrayItem_78), réévaluée quand 203 s'exécute : les deux lectures fautives resteraient. Le chemin « non valide » doit donc rejouer AddVariable avec la clé "0". Après, variante a (rejeu exact) : IsValidIndex G10-I, Branch G10-B1, IsValid G10-V, Branch G10-B2, Map Find G10-F, Make Array G10-M, AddVariable G10-A (7 nœuds) ; break_pins (200.then, 203.execute) ; connect_pins (16) :

  1. 200.then → G10-B1.execute ; 2. BreakStruct_56.Person_24_… → G10-I.TargetArray ; 3. G10-I.ReturnValue → G10-B1.Condition ;
  2. G10-B1.then → G10-B2.execute ; 5. GetArrayItem_78.Output → G10-V.Object ; 6. G10-V.ReturnValue → G10-B2.Condition ;
  3. G10-B2.then → 203.execute ; 8. G10-B1.else → G10-A.execute ; 9. G10-B2.else → G10-A.execute ;
  4. VariableGet_152.AI_Untils → G10-F.TargetMap ; 11. G10-F.Value → G10-M.[0] ; 12. G10-M.Array → G10-A.Float ;
  5. VariableGet_153.VariableName → G10-A.Name ; 14. MakeArray_149.Array → G10-A.Bool ; 15. MakeArray_148.Array → G10-A.String ; 16. MakeArray_146.Array → G10-A.Person. set_pin_value : G10-F.Key = 0 (chaîne) ; G10-A.Class = valeur relue sur 203 (Float) ; G10-A.Array = false (relire, ne poser que si le défaut diffère). G10-A.then : rien (comme 203). Comportement (a) : aujourd'hui, personne nulle → Until = [Map_Find(AI_Untils, "0").Value], soit la valeur de la clé "0" si elle existe, sinon la valeur remise à zéro (UE Runtime\Engine\Private\BlueprintMapLibrary.cpp:35-55, ResetToDefault l. 49) : 0.0. Après : même appel, même clé, même AddVariable. Identique (établi par construction). Variante b (valeur neutre) : sans G10-F (6 nœuds, 14 liens : sans 10 et 11), G10-M.[0] = 0.0. Diffère de l'actuel quand AI_Untils a une clé "0" (Q4). Variante c : pas de garde (_30 reste à 4 lignes).

2.6 G11 — commande hasRelationship de CallFunctionReturnBool (F3 _41, 14 dans L2 ; F2 : 7) — CRB, variante selon Q5

Avant : cas SwitchString_77.hasRelationship → CallFunction_177620 (GetVariable, CRB:162, 1267-1272), Name ← VariableGet_128293.ActualVariable, .then → VariableSet_57739.execute, Variable → BreakStruct_6891 (CRB:1273-1276) ; BreakStruct_6891.Person_24_… → GetArrayItem_12254.Array (CRB:1283), index 0, Output → VariableGet_128294.self (Prefix) et VariableGet_128295.self (SaveSlot) (CRB:1285-1294) → Conv_IntToString 177621 et Concat_StrStr CommutativeAssociativeBinaryOperator_16749 → CallFunction_177622.Slot (CRB:1295-1303) ; 177622 = hasRelationship pur, Types ← VariableGet_128296.ActualParameters, sortie hasRelationship → VariableSet_57739.BoolToReturn (CRB:1304-1310) ; VariableSet_57739.then → IfThenElse_8994.execute (CRB:1311-1315) ; IfThenElse_8994 : Condition ← Reverse, then → FunctionResult_0 (rend !BoolToReturn), else → FunctionResult_1 (rend BoolToReturn) (CRB:300-302, 325-338). Même raison qu'en G10 : l'entrée de VariableSet_57739 vient d'une chaîne pure, réévaluée ; le chemin « non valide » rejoue l'affectation. Après, variante a (rejeu exact) : IsValidIndex G11-I, Branch G11-B1, IsValid G11-V, Branch G11-B2, hasRelationship G11-H, Set BoolToReturn G11-S (6 nœuds) ; break_pins (177620.then, VariableSet_57739.execute) ; connect_pins (12) :

  1. 177620.then → G11-B1.execute ; 2. BreakStruct_6891.Person_24_… → G11-I.TargetArray ; 3. G11-I.ReturnValue → G11-B1.Condition ; 4. G11-B1.then → G11-B2.execute ; 5. GetArrayItem_12254.Output → G11-V.Object ;
  2. G11-V.ReturnValue → G11-B2.Condition ; 7. G11-B2.then → VariableSet_57739.execute ; 8. G11-B1.else → G11-S.execute ; 9. G11-B2.else → G11-S.execute ; 10. VariableGet_128296.ActualParameters → G11-H.Types ;
  3. G11-H.hasRelationship → G11-S.BoolToReturn (entrée 1) ; 12. G11-S.then (0) → IfThenElse_8994.execute. set_pin_value : G11-H.Slot = 0 (chaîne). Comportement (a) : aujourd'hui, personne absente → F2, BoolToReturn = hasRelationship("0", Types), puis IfThenElse_8994. Après : même appel pur avec Slot = "0", même variable, même suite. Identique (établi par construction). Variante b (valeur neutre) : sans G11-H (5 nœuds, 10 liens : sans 10 et 11), G11-S.BoolToReturn = false (relu). Identique seulement si hasRelationship("0", …) est faux (Q5). Variante c : pas de garde.

2.7 Correspondance nom compilé → nœud (_30, _41)

Méthode de H3S § 2.8 (le suffixe _N ne se lit pas dans un dump) : empreinte dans L2 et contenu joué.

  • _41 = GetArrayItem_12254 (hasRelationship), estimé fort :
    • empreinte : par événement, 1 F2 puis 2 lectures _41 (L2:21375-21397), soit un Array_Get sur tableau vide dont la sortie est lue par 2 propriétés dans une seule évaluation ; dans CRB, 4 GetArrayItem ont une sortie vers 2 self (Grep Output +-> K2Node_VariableGet_\d+\.self, K2Node_VariableGet_\d+\.self : CRB:709, 738, 1288, 2522), soit isSameGender (519, 521), hasRelationship (12254), wantsBabies (34) ;
    • moment : les 7 événements (14 lignes : L2:21377, 21388, 22906, 22917, 24344, 24355, 25676, 25687, 26940, 26951, 28458, 28469, 29515, 29526) tombent entre 21:32:11.093 et 21:32:21.141, dans la rafale du cas B (AI absente, H3S § 4 Q1) ;
    • contenu : dans AI, la seule condition If qui appelle une fonction booléenne sur une personne est AI\high_priority\so_follows.lpai:7 If AI.hasRelationship(Spouses, Dating) (Grep ^\s*(If|Elseif|ElseIf)\b.*\b\w+\.\w+\( sous AI : 7 lignes, les 6 autres sur Dest, Current, Type) ; les scènes vérifiées autour des 7 événements (lignes CHECKING: les plus proches, ex. L2:21374, 22893, 24336, 25663, 26935, 28449, 29512) n'appellent ni hasRelationship, ni wantsBabies, ni isSameGender (Grep ^(OTHER|WHO|WHERE): sur ces .lpscene).
  • _30 = GetArrayItem_78 (getUntil), estimé fort :
    • empreinte : par événement, 2 lectures _30 sans F2 propre (L2:12087-12105, 22396-22414) : tableau de longueur 1 qui contient None ; la seule F2 précède les 2 Per de getRelatedPerson (L2:12063-12085, 22372-22394) ;
    • suite L2:22372-22438 = so_follows.lpai:8-17 : getRelatedPersonQuick (F2 + 2 Per ; CallFunction_175951, son Return part dans AddVariable 12409 via MakeArray_120.[0], CF:2431-2467, d'où SO = [None]), SO.getUntil() (2 _30), SO.getBuilding(current) et SO.getBuilding(work) (2 _33, L2:22416-22434), « [AI] 4 moves to (test0104) » (destination vide, L2:22436), « for 1.0 hours by 4 » (L2:22437), SO.delete() (« DestroyDummy was from callfunction Delete », L2:22438) ; l'événement de L2:12063-12106 s'arrête après _30 (Until - HoursElapsed > 1 faux) ;
    • candidats de même forme dans CF (Grep du motif ci-dessus : CF:2751, 5522, 5695, 6113, 7000) : deletePerson (2368), setUntil (75, = _31, H3S), getUntil (78), setWantsBabies (99), setDatingID (144) ; seul getUntil est dans so_follows.lpai. Statut : estimé fort ; la VAL tranche (comptes à 0, § 7). Écart possible : R9.

3. Repli

  • Avant écriture : instantané .\Tools\Snapshot.ps1 -Lot STE-H3b (P3) ; MD5 de départ relevé (P2).
  • Échec de compilation, diagnostic, type_id introuvable (P5) ou lien relu différent : arrêt, .\Tools\Restore.ps1 -Lot STE-H3b éditeur fermé (GI entier, retour à l'état après H3), puis contrôle MD5 = valeur de P2.
  • Après commit (gardien) : git revert du commit du ticket STE-H3b (n'annule pas STE-H3 si commits distincts).
  • Indépendance : G8, G10, G11 sont indépendantes entre elles et de H3 ; G7 exige G2 (sinon R1 de H3S s'applique). Une réponse c à Q4 ou Q5 retire seule la garde concernée.

4. Risques R#, questions Q#

Q4 (utilisateur) — G10, getUntil sur personne nulle : (a) rejeu exact Map_Find(AI_Untils, "0") (7 nœuds, comportement identique) ; (b) Until = 0.0 (6 nœuds) ; (c) pas de garde. Établi : la clé "0" d'AI_Untils est écrite aujourd'hui par setUntil avec AI vide (H3S § 2.6), écriture supprimée par G5 (Q2 acceptée, STE-TACHES.md:29) ; dans L2 elle existait à 21:32:11 (PNJ 4 envoyé suivre un partenaire inexistant vers une destination vide, L2:22436). (b) changerait ce cas (le PNJ ne bouge plus), ce qui ressemble à une correction mais n'est pas « comportement inchangé ». Avec G5 posée, (a) et (b) ne diffèrent plus que pour une sauvegarde qui contient déjà la clé "0" (essai : LPDumpSave, § 7.4). Recommandation : (a), conforme à Q1 = A.

Q5 (utilisateur) — G11, hasRelationship sur personne absente : (a) rejeu exact hasRelationship("0", Types) (6 nœuds, identique) ; (b) BoolToReturn = false (5 nœuds) ; (c) pas de garde. Estimé : dans L2, aucune des 7 évaluations n'a été suivie d'un getRelatedPerson fautif (les 4 lignes Per sont à L2:12065-12078 et 22374-22387, hors des 7 événements), donc hasRelationship("0", Spouses, Dating) y a probablement rendu faux ; non établi sans dump de hasRelationship (clé "0" = joueur ? R1 de H3S). Recommandation : (a).

Q6 (orchestrateur) — dumps manquants (STE-D3) : .\Tools\RunCommandlet.ps1 -Lot STE-D -Commandlet LPDumpFunction -Args '-BP=GI -Fn=modifyActorVar -Pins -Exec' (G9, bloquante) ; ... -Args '-BP=GI -Fn=getRelatedPerson -Pins -Exec' (R13 : F2 + Per, 2 événements, 4 lignes) ; ... -Args '-BP=GI -Fn=hasRelationship -Pins -Exec' (Q5 b seulement).

  • R9 : correspondances _41 → GetArrayItem_12254 et _30 → GetArrayItem_78 estimées (§ 2.7). Autres candidats : isSameGender (519, 521 : un seul des deux absent donne aussi 1 F2 + 2 lectures), wantsBabies (34) ; deletePerson, setWantsBabies, setDatingID. Si _41 ou _30 reste > 0 en VAL : rapport, pas de correctif improvisé.
  • R10 : G7 repose sur la sortie non écrite de 142 (cadre mis à zéro, § 6) et sur G2 posée avant (ordre § 2).
  • R11 : type_id d'AddVariable, Map_Find, MakeArray, hasRelationship, Set BoolToReturn hors lp-mcp § 3 (P5) ; broches génériques de Map_Find et MakeArray typées au câblage ; échec → arrêt et repli, pas de delete_node.
  • R12 : masquage : les variantes a gardent les comportements du chemin nul (PNJ envoyé vers une destination vide, hasRelationship du créneau "0"), liés au cas B (H5) et au retour nul de getRelatedPerson.
  • R13 : non couvert : F2 + 2 Per dans getRelatedPerson (L2:12063-12085, 22372-22394, fonction sans dump) ; autres lecteurs de Person[0] (R7 de H3S).
  • R14 : G7 et G8 n'ajoutent pas d'IsValid : l'élément nul d'un tableau de longueur 1 ne lève pas de F2 au site et est traité dans la fonction appelée (G2, G1).

5. Interdits

  • Aucune modification de l'EventGraph, des fonctions appelées (getActorVar, setActorVar, modifyActorVar, getRelatedPerson, hasRelationship), du C++ ; G9 non posée sans dump et complément de SPEC.
  • Aucune correction de contenu (Content\Modules\…\*.lpai, .lpscene), aucun nœud AND / OR / Select pur, aucun FunctionResult créé, aucun delete_node.
  • Pas d'écriture HyperAIStudio (lp-mcp § 1.1) ; outils Epic seulement ; pas d'IMPL sans P1 à P5.
  • Pas de commit par l'agent : ticket au gardien (lp-repo).

6. Valeurs moteur lues dans le moteur installé (UE = D:\Game\Launcher\Engine\UE_5.8\Engine\Source\)

  • Message F1 / F3 « Accessed None trying to read (real) property X in not an UClass » : UE Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:3213-3216 ; contexte nul : expression sautée, valeur rendue effacée (ClearValue), :3234-3244.
  • Cadre d'une fonction script : alloué puis mis à zéro s'il n'est pas persistant, ScriptCore.cpp:984-993 ; cadre persistant seulement pour la fonction ubergraph : Runtime\Engine\Private\BlueprintGeneratedClass.cpp:1882-1897.
  • Message F2 « Attempted to access index %d from array '%s' of length %d » : Runtime\Engine\Private\KismetArrayLibrary.cpp:472-478 ; GenericArray_IsValidIndex sans message : :583-589.
  • Map_Find pur, catégorie Utilities|Map, nom affiché Find : Runtime\Engine\Classes\Kismet\BlueprintMapLibrary.h:48-49 ; clé absente → valeur remise au défaut : Runtime\Engine\Private\BlueprintMapLibrary.cpp:35-55 (l. 47-50).
  • Suffixe _N et ordre de compilation : repris de H3S § 6 (KismetCompilerMisc.h:287-302, KismetCompiler.cpp:3918-3927, EdGraphCompiler.cpp:244-249), non relus ici.

7. Critères de VAL (commande → attendu)

  1. Dumps après IMPL (.\Tools\RunCommandlet.ps1 -Lot STE-H3b -Commandlet LPDumpFunction -Args '-BP=GI -Fn=<f> -Pins -Exec') comparés à P2 : CallFunction +11 nœuds (G7 2, G8 2, G10a 7 ; +10 si Q4 = b, +4 si c ; base H3 : 1 550, H3S:258) ; CallFunctionReturnBool 585 → 591 (Q5 = a), 590 (b), 585 (c) ; liens du § 2 relus ; python Tools\DiffRemplacementNoeuds.py sans autre écart.
  2. hyper_blueprint_debug_inspect 0 diagnostic pour CallFunction et CallFunctionReturnBool ; CompileAllBlueprints éditeur fermé : 0 erreur (lp-validate).
  3. Journal de jeu (build Development, parcours STB-JEU2, STD-SCN-DIAG.md:198-206), Grep en mode count :
    • property CallFunc_Array_Get_Item_41 → 0 (L2 : 14) ;
    • property CallFunc_Array_Get_Item_30 → 0 (L2 : 4 ; inchangé si Q4 = c) ;
    • multiligne of length 0[^\n]*\r?\n[^\n]*\r?\n[^\n]*property (CallFunc_Array_Get_Item_41|Per) in → nombre de lignes property Per in / 2 (L2 : 9 = 7 + 2) ;
    • Person_24_4B712C904750AD4CE1580DBEBD9E7396' of length 0 / CHECKING: → inférieur au rapport mesuré en VAL de H3, de l'ordre de 94 / 2 318 = 0,041 à parcours égal (L2 : 351 / 2 318 = 0,151 avant H3) ;
    • property Per in → information (L2 : 4, R13) ;
    • moves to \(test0104\) → information (L2 : 1, L2:22436) : présent possible en variante a, absent attendu en b ;
    • hours by [1-9] → ≥ 1 si le parcours contient des routines de PNJ valides (L2 : 7), non-régression de l'IA ;
    • dénominateur CHECKING: (L2 : 2 318) ; index SPAWN > 0 avant de mesurer (lp-validate § 5).
  4. Q4 / Q5 : LPDumpSave -File=<sauvegarde du parcours> -Out=<txt> (lp-commandlets) avant / après : clés "0" d'AI_Untils et d'ActorVars relevées (même essai que H3S § 7.4).

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

  • A Docs/Migration/etat/ST/STE/STE-H3b-SPEC.md

Tours : 33 / 60

Constats

  • Comptes rejoués sur L2 (Grep) : CallFunc_Array_Get_Item_(30|41) → 4 et 14 lignes (contenu, numéros cités § 2.7) ; multiligne Function /Game/BPs/GI\.GI_C:CallFunction\r?\n\s+Function /Game/BPs/GI\.GI_C:(getActorVar|setActorVar|modifyActorVar)\r?\n → 174 ; multiligne Function /Game/BPs/GI\.GI_C:\w+\r?\n\s+Function /Game/BPs/GI\.GI_C:getActorVar\r?\n → 142 ; donc getActorVar 142 (toutes depuis CallFunction) + setActorVar 32 (H3S:72) + modifyActorVar 0 = 174 ; GI_C:modifyActorVar|GI_C:getUntil|GI_C:hasRelationship → 0 ; GI_C:(modifyActorVar|getRelatedPerson): → 4 (les 4 Per).
  • F2 suivie d'une lecture fautive (multiligne Script Msg: Attempted to access index 0 from array 'Person_24_…' of length 0[^\n]*\r?\n[^\n]*\r?\n[^\n]*property (Person|Per|CallFunc_Array_Get_Item_\d+) in) → 285 sur 351 ; dont suivie d'un F1 getActorVar → 71, d'un F1 setActorVar → 16, de _41 ou Per → 9.
  • getRelatedPerson reçoit un nom de variable (Person ← VariableGet_127193.VariableGet, CF:2435, 2441-2442 ; VariableGet est une chaîne, VariableSet_163.VariableGet ← Split.LeftS, CF:452-456) : la F2 et les Per naissent dans la fonction, sans dump.
  • Grep de etat\…\dumps : passer glob *__*.txt (les .txt y sont ignorés par git) ; un motif finissant par $ ne trouve rien dans ces dumps (fins de ligne CRLF) : essai de cette fiche.
  • Écart de chemin : aucun ; journal et gabarits aux chemins DOCMV (D:\Game\LifePlay-master 5.8\Docs\Journal_Modifications.md, D:\Game\LifePlay-master 5.8\.claude\skills\lp-doc\gabarits.md) ; journal non relu (aucune entrée nécessaire ici).