331 lines
30 KiB
Markdown
331 lines
30 KiB
Markdown
|
|
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` (`|Set<var>`) |
|
||
|
|
|
||
|
|
### 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` ;
|
||
|
|
4. `G10-B1.then` → `G10-B2.execute` ; 5. `GetArrayItem_78.Output` → `G10-V.Object` ; 6. `G10-V.ReturnValue` → `G10-B2.Condition` ;
|
||
|
|
7. `G10-B2.then` → `203.execute` ; 8. `G10-B1.else` → `G10-A.execute` ; 9. `G10-B2.else` → `G10-A.execute` ;
|
||
|
|
10. `VariableGet_152.AI_Untils` → `G10-F.TargetMap` ; 11. `G10-F.Value` → `G10-M.[0]` ; 12. `G10-M.Array` → `G10-A.Float` ;
|
||
|
|
13. `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` ;
|
||
|
|
6. `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` ;
|
||
|
|
11. `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).
|