162 lines
24 KiB
Markdown
162 lines
24 KiB
Markdown
|
|
Fiche GIREV-MCP-01 — Niveau N1 — Modèle prévu non précisé par la fiche | utilisé claude-sonnet-5-5 — Agent lp-mcp (lecture seule) — Skills sk-protocol, lp-mcp, sk-change-safety
|
|||
|
|
# GIREV-MCP-01 : lecture MCP de GI pour GQ1 (garde D2 de `SavePreset`) et GQ4 (message de F6 / C11) (2026-10-21)
|
|||
|
|
|
|||
|
|
Lecture seule par `unreal-mcp` (éditeur headless pid 21652, port 8000, jeton de Big Boss ; non lancé, non fermé). Aucune écriture, aucune sauvegarde, aucune compilation. Seul ce fichier est écrit. Préalable : `GIREV-PRE.md` § 3.2 M2, M4, § 5 points 1 et 4, § 6 GQ1 et GQ4. Décisions de l'utilisateur citées par l'ordonnateur : GQ1 « oui » (établir le rôle de la garde avant de décider), GQ4 « on le rebranche et on évalue ».
|
|||
|
|
|
|||
|
|
Notation : `EG` = `/Game/BPs/GI.GI:EventGraph`, `SP` = `/Game/BPs/GI.GI:SavePreset`.
|
|||
|
|
|
|||
|
|
## Résumé (à lire en premier)
|
|||
|
|
|
|||
|
|
1. **GQ1 : la garde D2 est inerte aujourd'hui et redondante** (établi pour l'inertie, estimé pour le rôle). Le littéral est `Characters\0.lpcharacter` (un antislash, une extension) ; **aucun** des 11 appelants lus ne passe un `File` de cette forme (tous : séparateur `/`, pas d'extension, ou nom saisi par le joueur). Le rôle voulu probable : ne jamais écrire le fichier du « slot 0 ». Cette protection existe déjà, effective, en amont : `SaveSlot > 0` dans `DestroyPerson` (`IfThenElse_436`) et dans `SavePerson` (`IfThenElse_18`). Recommandation : **(a) laisser** (0 écriture) ; (b) supprimer reste neutre ; (c) corriger le littéral change le comportement du seul appelant non gardé (`ContactMenu`) et n'a pas de rôle prouvé.
|
|||
|
|
2. **GQ4 : le message n'est pas du code mort** (établi). `K2Node_CallFunction_20748` (`ShowTutorial`, String) et `K2Node_CallFunction_13122` (`PrintString`) sont bien orphelins (`execute` sans liaison), **mais** `K2Node_CallFunction_340` (`ShowTutorialTxt`, même titre, même contenu, `Force` et `Warning` à `true`) est atteint par `IfThenElse_2861.else` : le message « missing crucial *.lpcharacter files » **s'affiche déjà** quand le chargement d'une partie ne lit rien dans `Player.lpcharacter`. La prémisse de GIREV-PRE M2 (« le message deviendrait atteignable ») est donc fausse pour le texte visible ; elle est vraie seulement pour le `PrintString` de journal.
|
|||
|
|
3. **Conséquence pour « on le rebranche »** : rebrancher `_20748` ferait afficher le message **deux fois** (établi par les liaisons). Les trois voies utiles sont au § B.5 ; recommandation : supprimer `_20748` et `_13122` (C11) et **réécrire le texte de `_340`** (2 `set_pin_value` sur des broches Text, faisabilité à confirmer).
|
|||
|
|
|
|||
|
|
## 1. Appels MCP (tous en lecture, dans l'ordre)
|
|||
|
|
|
|||
|
|
| # | Appel (toolset / outil) | Arguments | Résultat |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| 1 | `list_toolsets` | — | liste complète, `editor_toolset.toolsets.blueprint.BlueprintTools` présent : connexion établie |
|
|||
|
|
| 2 | `AssetTools.load_asset` | `/Game/BPs/GI` | `/Game/BPs/GI.GI` |
|
|||
|
|
| 3 | `BlueprintTools.get_node_infos` | `SP.K2Node_IfThenElse_2970`, `SP.K2Node_CallFunction_19325` | liaisons et littéral (§ A.1) |
|
|||
|
|
| 4 | `BlueprintTools.find_nodes` | `EG`, titre `SavePreset` | `_104`, `_16676`, `_8085` |
|
|||
|
|
| 5 | `get_node_infos` | ces 3 nœuds | broches `File`, `Var`, `StatOnly`, `IncludeStat` |
|
|||
|
|
| 6 | `get_node_infos` | `EG` `Concat_12`, `_2523`, `_827` | littéraux de `File` |
|
|||
|
|
| 7 | `get_node_infos` | `EG` `Concat_698`, `VariableGet_87`, `CallFunction_105`, `VariableGet_19305`, `CallFunction_8086` | `Saves/` + `Slot` + `/Characters/`, `Prefix`, `ToString(SaveSlot)` |
|
|||
|
|
| 8 | `get_graphs` (outil inexistant : « Unknown tool get_graphs ») puis `ObjectTools.list_properties` (refusé : paramètre `instance` manquant) | — | rien utilisé ; la liste des graphes de GI est tirée des dumps (§ A.2) |
|
|||
|
|
| 9-11 | `find_nodes` titre `SavePreset` | `GI:GeneratePerson`, `GI:GenerateCreature`, `GI:saveOldPlayer` | 2, 1, 1 appelants |
|
|||
|
|
| 12-13 | `get_node_infos` | `saveOldPlayer.CallFunction_1`, `GeneratePerson` `_20437`, `_684`, `GenerateCreature` `_684` ; leurs `Concat_2411` / `_827` | `File` |
|
|||
|
|
| 14 | `get_node_infos` | `GeneratePerson.CallFunction_4486`, puis `MacroInstance_1386` | `ToString` d'un `IncrementInt` |
|
|||
|
|
| 15-19 | `find_nodes` titre `SavePreset` | `/Game/UI/StatMenu`, `/Game/UI/ContactMenu`, `/Game/BPs/Room`, `/Game/UI/CharGen`, `/Game/UI/Builder` (graphe `EventGraph`) | 1, 1, 1 (événement), 1, 1 |
|
|||
|
|
| 20 | `get_node_infos` | les 5 nœuds ci-dessus | `Room` et `Builder` = événement `SavePreset` de `Room`, pas celui de GI |
|
|||
|
|
| 21-22 | `get_node_infos` | `StatMenu`/`CharGen` `CallFunction_5136`, `_5135` ; `ContactMenu` `Concat_827`, `CallFunction_8086` | `File` = texte du champ (StatMenu, CharGen) ; `Saves/_session/Characters/` + `VariableGet_4523` + `ToString` (ContactMenu) |
|
|||
|
|
| 23 | `get_node_infos` | `EG.IfThenElse_436`, `_4453`, `_39` | garde `SaveSlot > 0` de `DestroyPerson` |
|
|||
|
|
| 24 | `get_node_infos` | `EG` `_20748`, `_13122`, `_340`, `IfThenElse_2861` | broches du message (§ B.1) |
|
|||
|
|
| 25 | `get_node_infos` | `EG` `CallFunction_177`, `IfThenElse_2377`, `CallFunction_213` | condition `Len(...) > 0`, branche `Load` |
|
|||
|
|
| 26 | `get_node_infos` | `EG` `CallFunction_176`, `CustomEvent_17`, `Concat_15` | événement `DuplicateCharacters(Load, Slot)`, chemin `Player.lpcharacter` |
|
|||
|
|
| 27 | `get_node_infos` | `EG` `CallFunction_173`, `_408`, `_13784`, `VariableSet_541` | `LoadTxt` (ModdingExtra), `LoadPreset`, `SaveTxt` |
|
|||
|
|
| 28 | `find_nodes` | `EG`, titre `DuplicateCharacters` | `CustomEvent_17`, `CallFunction_14865`, `CallFunction_14866` |
|
|||
|
|
| 29 | `get_node_infos` | `CallFunction_14865`, `_14866` ; `CustomEvent_955`, `_16` | appelants : événements `LoadGame` et `SaveGame` |
|
|||
|
|
|
|||
|
|
Lectures hors MCP : Read `GIREV-PRE.md` ; `rg -a -l` sur `Content`, `Source`, `Plugins`, `Saved` ; `rg --no-ignore -a` sur les dumps `STE-ORG4cV_LPDumpFunction_20261014-103731.txt` (« GEV »), `STE-H10V_…20261013-071350.txt`, `L6f_dump_GI.txt` (5.5) ; Read `STE-H10-SPEC.md:160-200`.
|
|||
|
|
|
|||
|
|
## A. GQ1 : garde D2 de `SavePreset`
|
|||
|
|
|
|||
|
|
### A.1 Liaisons et valeur exacte (appels 3, établi)
|
|||
|
|
|
|||
|
|
- `SP.K2Node_IfThenElse_2970` : `execute` ← `FunctionEntry_799`.then ; `Condition` ← `CallFunction_19325`.ReturnValue ; **`then` : aucune liaison** (la fonction s'arrête) ; `else` → `IfThenElse_10253`.execute.
|
|||
|
|
- `SP.K2Node_CallFunction_19325` (`Utilities|String|EndsWith`) : `SourceString` ← `FunctionEntry_799`.pin 1 (`File`) ; `InSuffix` = `Characters\0.lpcharacter` (le dump JSON montre `"Characters\\0.lpcharacter"`, soit **un seul antislash**) ; `SearchCase` = `IgnoreCase`.
|
|||
|
|
- Conclusion de lecture : la garde ne vaut que pour un `File` finissant littéralement par `Characters\0.lpcharacter`, c'est-à-dire avec antislash **et** extension.
|
|||
|
|
|
|||
|
|
### A.2 Appelants de `SavePreset` de GI et valeur de `File` (appels 4-7, 9-22, établi)
|
|||
|
|
|
|||
|
|
Recherche : `find_nodes` titre `SavePreset` sur le graphe de chaque BP, plus `rg -a -l SavePreset Content` (BP contenant la chaîne : `GI`, `StatMenu`, `ContactMenu`, `Room`, `CharGen`, `Builder` ; **aucun** dans `Person`, `PC`, `MainMenu`). Les graphes de fonction de GI viennent du dump 5.5 (`L6f_dump_GI.txt:17470`, `:17701`, `:36223`, `:37957` → `GeneratePerson` ×2, `GenerateCreature`, `saveOldPlayer`) puis relus par MCP. Les graphes de fonction de `StatMenu`, `ContactMenu`, `CharGen` n'ont pas été énumérés (aucun outil de liste de graphes trouvé, appel 8) : un appelant dans une fonction de ces trois BP reste possible (incertain).
|
|||
|
|
|
|||
|
|
| # | Appelant (nœud) | `File` | Extension / séparateur | Garde D2 déclenchée ? |
|
|||
|
|
|---|---|---|---|---|
|
|||
|
|
| 1 | `EG.CallFunction_104` (dans `DestroyPerson`, `CustomEvent_3172`) | `Saves/_session/Characters/` + `Prefix` + `ToString(SaveSlot)` (`Concat_12`) | `/`, sans extension | non |
|
|||
|
|
| 2 | `EG.CallFunction_8085` (événement `SavePerson`, `CustomEvent_32`) | idem (`Concat_827`) | idem | non ; précédé de `IfThenElse_18` ← `Greater_IntInt(SaveSlot, 0)` (`CallFunction_2016`, dump `STE-ORG4cV:18040`) : jamais pour le slot 0 |
|
|||
|
|
| 3 | `EG.CallFunction_16676` (dans `DuplicateCharacters`, branche `Load` = faux) | `Saves/` + `Slot` + `/Characters/` + `Player` (`Concat_698` puis `_2523`) | `/`, sans extension | non |
|
|||
|
|
| 4 | `GeneratePerson.CallFunction_20437` | `Saves/_session/Characters/` + `ToString(IncrementInt)` (`Concat_2411`, `CallFunction_4486`, `MacroInstance_1386`) | `/` | non ; compteur incrémenté donc ≥ 1 (estimé : valeur initiale non lue) |
|
|||
|
|
| 5 | `GeneratePerson.CallFunction_684` | `Saves/_session/Characters/F` + chaîne (`Concat_827`) | `/` | non |
|
|||
|
|
| 6 | `GenerateCreature.CallFunction_684` | `Saves/_session/Characters/C` + chaîne | `/` | non |
|
|||
|
|
| 7 | `saveOldPlayer.CallFunction_1` | littéral `Saves/_session/Characters/OldPlayer` | `/` | non |
|
|||
|
|
| 8 | `StatMenu.EventGraph.CallFunction_5375` | texte du champ `TextBox` (`GetText` → `ToString`), `StatOnly` = vrai | libre (saisie du joueur) | non, sauf saisie volontaire du suffixe exact |
|
|||
|
|
| 9 | `CharGen.EventGraph.CallFunction_5375` | idem, `StatOnly` = faux, `IncludeStat` ← `EnumEquality_0` | libre | idem |
|
|||
|
|
| 10 | `ContactMenu.EventGraph.CallFunction_509` | `Saves/_session/Characters/` + `VariableGet_4523` + `ToString(…)` (`Concat_827`, `CallFunction_8086` ← `VariableGet_3021`) | `/` | non ; **seul appelant non gardé par `SaveSlot > 0` identifié** : la valeur de `VariableGet_3021` et la condition `CallFunction_72` n'ont pas été relues (incertain) |
|
|||
|
|
| — | `Room.CustomEvent_15` et `Builder.CallFunction_27` | n'appellent pas `GI.SavePreset` : événement `SavePreset(Path)` **propre à `Room`** | — | sans objet |
|
|||
|
|
|
|||
|
|
Aucun appelant ne passe un `File` avec antislash ni avec l'extension : le suffixe de la garde ne peut correspondre qu'à une saisie volontaire (et CG2 C7 filtre déjà `..`, `/`, `\` côté `CharGen`, `GIREV-PRE.md` § 3.2 M5).
|
|||
|
|
|
|||
|
|
### A.3 Qui crée, lit ou utilise `Characters/0.lpcharacter` (établi pour les absences, estimé pour le sens)
|
|||
|
|
|
|||
|
|
- **Existence sur disque** : `Content/Saves/` contient `Default/Characters/Player.lpcharacter` et `_session/Characters/{1,2,3}.lpcharacter` ; aucun `0.lpcharacter` (`find` sur `Content/Saves`). `Saved/Saves` absent de ce dépôt. Aucun fichier `*0.lpcharacter` ailleurs : `rg -a -l "0\.lpcharacter"` sur `Content`, `Source`, `Plugins`, `Saved/Saves`, `Docs` ne répond que `GI.uasset` et des dumps/fiches (`STE-H10-SPEC.md:176`, dumps `STE-H10V`, `STE-D9`, `L6f`). Aucune occurrence dans `Content/Modules` pour ce nom (la seule mention de `lpcharacter` y est `vin_Interracial/scenes/set_stereotypes.lpscene`) ; `Source` : seule mention `LPStringCompat.h:9` (commentaire sur les 141 préréglages).
|
|||
|
|
- **Journal du build COM21** (`COMMUN-21-BILAN.md:40`) : après une session, `Saved\Saves\_session\Characters\1.lpcharacter` créé ; relevé à 3 fichiers, aucun `0`.
|
|||
|
|
- **Le joueur n'est pas le slot 0** : le joueur est enregistré sous `…/Characters/Player` (appelant 3, `Concat_15` ajoute `Player.lpcharacter` : `EG.CommutativeAssociativeBinaryOperator_15.B` = `Player.lpcharacter`) et `Default/Characters/Player.lpcharacter` ; l'ancien joueur sous `OldPlayer` (appelant 7). Le slot 0 (`Prefix` vide, `SaveSlot` 0) est donc une personne sans emplacement attribué (estimé : l'unité de test `STA-T2b-PERSON-DIAG.md:203` lie `Len(Prefix) == 0` aux « numérotés » 1, 2, 3…).
|
|||
|
|
- **Qui écrirait `0.lpcharacter`** : un appel de `SavePreset` avec `Prefix` vide et `SaveSlot` 0 (cas des appelants 1, 2, 10) ; `SP.Append_762` ajoute `.lpcharacter` après la garde (`GIREV-PRE.md` § 3.2 M5), donc le fichier produit serait bien `Saves/_session/Characters/0.lpcharacter`. Les appelants 1 et 2 sont fermés au slot 0 par `SaveSlot > 0` : `DestroyPerson` — `EG.IfThenElse_436` (`Condition` ← `CallFunction_106`, `A` ← `VariableGet_86`.SaveSlot dans le dump `STE-ORG4cV:6474`) : `then` → `IfThenElse_39` (chaîne vers la sauvegarde), `else` → `IfThenElse_4453` → `IfThenElse_1766` (suite après `RestoreCbe`, `STE-H10-SPEC.md:172`) ; la seule liaison d'exécution vers `CallFunction_104` vient de `IfThenElse_216.then` et `VariableSet_393.then` (appel 5, établi). Que `CallFunction_106` soit bien `Greater_IntInt(SaveSlot, 0)` n'a pas été relu (estimé d'après `STE-H10-SPEC.md:168`).
|
|||
|
|
- **Qui lit `0.lpcharacter`** : aucun lecteur trouvé. Les lectures de personnage passent par `LoadPreset` (`CallFunction_213`, `_408`, chemin `…/Player.lpcharacter`) ; aucun chemin `Characters/0` dans les dumps.
|
|||
|
|
|
|||
|
|
### A.4 Conclusion GQ1
|
|||
|
|
|
|||
|
|
- **Rôle voulu probable (estimé)** : empêcher l'écriture d'un fichier « slot 0 » par `SavePreset`. La forme du littéral (antislash, extension complète) évoque une version ancienne où `File` était un chemin complet de fichier Windows ; la fonction a ensuite reçu l'extension en interne (`Append_762`), ce qui a rendu la garde inopérante.
|
|||
|
|
- **Se déclenche-t-elle aujourd'hui ?** Non : établi pour les 10 appelants lus (§ A.2) ; incertain pour d'éventuels appelants dans des fonctions de `StatMenu`/`ContactMenu`/`CharGen` non énumérées et pour la valeur de `SaveSlot` côté `ContactMenu`.
|
|||
|
|
- **Effets** :
|
|||
|
|
- **(a) laisser** : aucun changement ; la garde reste un code inerte de 2 nœuds ; 0 écriture MCP. Le slot 0 est déjà protégé par `SaveSlot > 0` (appelants 1, 2).
|
|||
|
|
- **(b) supprimer** : comportement inchangé tant que la garde est inerte (établi par A.2) ; coût estimé 5 écritures (`break_pins` ×2 sur `IfThenElse_2970`, `connect_pins` `FunctionEntry_799` → `IfThenElse_10253`, `delete_node` ×2) ; perte d'une défense dormante si un appelant futur passe cette forme.
|
|||
|
|
- **(c) corriger le littéral** (par exemple `Characters/0` sans extension) : **change le comportement** pour tout `File` finissant ainsi, c'est-à-dire pour l'appelant 10 (`ContactMenu`) s'il passe un slot 0 avec préfixe vide : il n'écrirait plus `0.lpcharacter`. Effet inconnu faute de preuve que ce cas se présente ; `set_pin_value` seul ne marque pas le paquet (`GIREV-PRE.md` § 3.9). **Non recommandé.**
|
|||
|
|
- **Recommandation : (a)**, éventuellement (b) si l'utilisateur veut supprimer le code mort ; (c) seulement si un test montre qu'un `0.lpcharacter` est produit en jeu (essai : build Development, parcours `ContactMenu` sur une personne de slot 0, relevé de `Saved\Saves\_session\Characters\`).
|
|||
|
|
|
|||
|
|
## B. GQ4 : message de F6 / C11
|
|||
|
|
|
|||
|
|
### B.1 Broches lues (appel 24, établi)
|
|||
|
|
|
|||
|
|
| Nœud | `execute` | `then` | Valeurs |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| `EG.K2Node_CallFunction_20748` (`|ShowTutorial`, String) | **aucune liaison** | aucune | `Title` = `Save Missing Character Data!` ; `Content` = `The save you just loaded is missing crucial *.lpcharacter files. Please copy your old LifePlay\Content\Saves folder into the directory of the current version of the game. You can Alt Tab and do this copying (no need to exit the game), then try load the save again.` ; `Force` = true ; `Warning` = true |
|
|||
|
|
| `EG.K2Node_CallFunction_13122` (`Development|PrintString`) | **aucune liaison** | → `CallFunction_340`.execute | `InString` = `Missing characters from save` ; `bPrintToScreen` = true ; `bPrintToLog` = true ; `TextColor` = (R=0, G=0.66, B=1, A=1) ; `Duration` = 2.0 ; `Key` = None |
|
|||
|
|
| `EG.K2Node_CallFunction_340` (`|ShowTutorialTxt`, Text) | ← `13122`.then **et** `IfThenElse_2861`.else | aucune | `Title` = NSLOCTEXT « Save Missing Character Data! » ; `Content` = NSLOCTEXT, **même texte** que `_20748` ; `Force` = true ; `Warning` = true |
|
|||
|
|
|
|||
|
|
Code mort : `_20748` et `_13122` (aucun `execute` entrant). **Pas code mort : `_340`**, atteint par `2861.else` ; `ShowTutorialTxt` convertit ses deux Text en String et appelle `ShowTutorial` avec `Force` et `Warning` (`STE-ORG4cV…:18487-18516`, `CustomEvent_33`, `CallFunction_136/137/138`). Donc l'écran du message est identique à celui que produirait `_20748`.
|
|||
|
|
|
|||
|
|
### B.2 Contexte amont (appels 24-29, établi)
|
|||
|
|
|
|||
|
|
Fonction : événement personnalisé `DuplicateCharacters(Load: bool, Slot: string)` (`EG.CustomEvent_17`), appelé par :
|
|||
|
|
- `CallFunction_14865` avec `Load` = true, `Slot` ← `CustomEvent_955` (événement `LoadGame(Name, Index)`) ;
|
|||
|
|
- `CallFunction_14866` avec `Load` = false, `Slot` ← `CustomEvent_16` (événement `SaveGame(Name, Index, Notes)`).
|
|||
|
|
|
|||
|
|
Chaîne (`Load` = vrai) : `IfThenElse_2377` (`Condition` ← `CustomEvent_17`.Load) `then` → **`IfThenElse_2861`** (`Condition` ← `CallFunction_177` = `Len(...) > 0`, B = 0 ; `A` ← `CallFunction_176` = `Len(S)` ; `S` ← `CallFunction_173`.`SaveTextA` = `LoadTxt`(`FileNameA` = `Append_15`) ; `Append_15` = `Saves/<Slot>/Characters/` + `Player.lpcharacter`) :
|
|||
|
|
- `then` (texte non vide) → `CallFunction_213` (`LoadPreset`, même `Path`, `Blend` = faux) → `CallFunction_408` (`LoadPreset`, `Blend` = vrai) ;
|
|||
|
|
- **`else`** (texte vide : fichier absent ou illisible) → `CallFunction_340` : le message.
|
|||
|
|
`2377.else` (`Load` = faux) → `CallFunction_16676` (`SavePreset` du joueur).
|
|||
|
|
|
|||
|
|
Sens de la condition « personnages manquants » (établi pour la lecture, estimé pour l'intention) : le chargement d'une partie ne rend aucune lecture de `Saves/<Slot>/Characters/Player.lpcharacter`. Seul le fichier du joueur est testé, pas les numérotés `1.lpcharacter`, `F…`, `C…` (le texte dit « missing crucial *.lpcharacter files » au pluriel : estimé, c'est le fichier crucial qui sert de témoin).
|
|||
|
|
|
|||
|
|
### B.3 Le message est-il déjà vu aujourd'hui ?
|
|||
|
|
|
|||
|
|
- Oui, sur un chargement dont `Player.lpcharacter` est absent de toutes les racines : **atteignable** (établi par les liaisons). Aucune preuve qu'il se soit présenté : le journal COM23 ne porte ni son texte ni `Missing characters` (`GIREV-PRE.md` n° 23) ; le bilan COM21 n'a relevé aucun `LoadTxt ECHEC` autre que `OldPlayer` et `ModLauncher.config` (`COMMUN-21-BILAN.md:53`, `:66`), donc `Player.lpcharacter` a été lu.
|
|||
|
|
- Avec F6 (`FIX1-F6-SPEC.md:33`) la lecture de `Saves/<Slot>/…` prend `<Saved>/Saves/<Slot>` si le dossier existe, sinon `<Content>/Saves/<Slot>`, sinon `<Saved>` : un ancien emplacement de `Content/Saves` est donc toujours lu (repli). Le message n'apparaît qu'en l'absence du fichier dans ces racines.
|
|||
|
|
|
|||
|
|
### B.4 Faux positifs et fréquence (estimé, aucun essai)
|
|||
|
|
|
|||
|
|
- Une partie enregistrée par ce jeu écrit toujours `Player.lpcharacter` : `SaveGame` → `DuplicateCharacters(Load=false)` → `SavePreset` (appelant 3). Pas de faux positif pour une partie créée par la build courante (non essayé en jeu).
|
|||
|
|
- Un `LoadGame` de partie « neuve » : la nouvelle partie utilise `Content/Saves/Default/Characters/Player.lpcharacter` (présent au dépôt) ; que la nouvelle partie passe par `LoadGame("Default")` n'est pas établi (appelants de `LoadGame` non lus). Pas de faux positif si `Default` est lu avec repli.
|
|||
|
|
- Partie sans personnage : le message se déclenche, comme voulu (le texte parle de fichiers manquants).
|
|||
|
|
- Fréquence attendue : rare (partie copiée d'une autre version sans `Characters`, dossier supprimé, ou slot renommé). Le jeu écrit déjà `LoadTxt ECHEC | '<chemin>'` au journal dans ce cas (`COMMUN-21-BILAN.md:66`) : le `PrintString` ajouterait une seconde trace.
|
|||
|
|
|
|||
|
|
### B.5 Où « rebrancher » et ce que cela donnerait (propositions, estimé)
|
|||
|
|
|
|||
|
|
| Voie | Écritures MCP | Effet visible | Remarque |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **V1. Relier `_20748`** (la demande littérale) | 2 (`connect_pins` d'un `execute` vers `_20748`, par exemple `2861.else`, puis rupture de `2861.else` → `_340`) | le même message **deux fois** si les deux restent reliés ; une fois si `_340` est coupé | n'apporte rien : `_340` est déjà ce nœud. **Non recommandé.** |
|
|||
|
|
| **V2. Relier seulement le `PrintString` `_13122`** | 2 : `break_pins` (`2861.else` → `_340`.execute) et `connect_pins` (`2861.else` → `_13122`.execute) ; `_13122.then` → `_340` déjà relié | message à l'écran inchangé + ligne de journal `Missing characters from save` (Development) + texte bleu 2 s à l'écran (`PrintString` n'imprime rien en Shipping, `CG2-SPEC-01.md:115`) | trace redondante avec `LoadTxt ECHEC` ; `Key` = None : s'empile |
|
|||
|
|
| **V3 (recommandée). Supprimer `_20748` et `_13122`, réécrire le texte de `_340`** | 2 `delete_node` (+ 1 `break_pins` implicite) puis 2 `set_pin_value` (broches Text `Title`, `Content` de `_340`) | message corrigé au prochain chargement manquant ; aucune autre différence | la clé NSLOCTEXT (`[3787EBBA…]`, `F9D9C9AF…`) peut être perdue ou conservée selon le comportement du MCP sur une broche Text : **incertain** (essai éditeur sur une copie). Les suppressions marquent le paquet ; `set_pin_value` seul ne le ferait pas (`GIREV-PRE.md` § 3.9). |
|
|||
|
|
|
|||
|
|
Nouveau texte proposé (à valider, adapté à la redirection F6 vers `Saved/Saves`, `FIX1-F6-SPEC.md:32-33`) :
|
|||
|
|
- `Title` : conserver `Save Missing Character Data!`.
|
|||
|
|
- `Content` : `The save you just loaded is missing crucial *.lpcharacter files. Saves are now kept in LifePlay\Saved\Saves. If this save comes from an older version, copy its folder from your old LifePlay\Content\Saves (the folder named like the save) into LifePlay\Saved\Saves of the current version, then try to load the save again. You can Alt Tab and do this copying (no need to exit the game).`
|
|||
|
|
- `Force` = true, `Warning` = true : inchangés (valeurs actuelles de `_340`) ; aucune raison établie de les modifier.
|
|||
|
|
|
|||
|
|
Évaluation chiffrée (estimé) : V3 = 4 à 5 écritures, risque très faible (suppression de nœuds sans exécution entrante), une seule différence visible pour le joueur : le texte, uniquement dans le cas où le message s'affiche déjà. Preuve : relecture `get_node_infos` de `_340` et compilation ; en jeu, un chargement volontairement sans `Player.lpcharacter` (copie d'essai d'un slot, fichier renommé) lit l'écran et le journal (`LoadTxt ECHEC` attendu).
|
|||
|
|
|
|||
|
|
## C. Établi / estimé / incertain
|
|||
|
|
|
|||
|
|
**Établi (appels MCP cités)** : littéral, liaisons et `then` vide de la garde (appel 3) ; `File` de 10 appelants (appels 5-7, 12-14, 21-22) ; `Room`/`Builder` n'appellent pas `GI.SavePreset` (appel 20) ; `_20748` et `_13122` sans `execute` entrant, `_340` atteint par `2861.else`, textes et valeurs (appel 24) ; condition `Len(LoadTxt(Saves/<Slot>/Characters/Player.lpcharacter)) > 0` et appelants `LoadGame` / `SaveGame` (appels 25-29) ; `ShowTutorialTxt` = `ShowTutorial` après conversion (dump `STE-ORG4cV:18487-18516`) ; aucun `0.lpcharacter` dans les dossiers et sources cherchés.
|
|||
|
|
|
|||
|
|
**Estimé** : rôle de la garde (écriture du slot 0 interdite) ; slot 0 sans emplacement attribué ; `CallFunction_106` = `SaveSlot > 0` ; compteur de `GeneratePerson` ≥ 1 ; fréquence et faux positifs du message ; nombre d'écritures.
|
|||
|
|
|
|||
|
|
**Incertain (essai qui trancherait)** : appelants de `SavePreset` dans les fonctions de `StatMenu`, `ContactMenu`, `CharGen` (lister leurs graphes, `rg --no-ignore` sur de futurs dumps `LPDumpFunction -Fn=*`) ; valeur de `SaveSlot` et condition `CallFunction_72` côté `ContactMenu` (lire `VariableGet_3021`, `_4523`) ; conservation de la clé NSLOCTEXT par `set_pin_value` (essai sur une copie) ; si la nouvelle partie passe par `LoadGame("Default")` (lire les appelants de `CustomEvent_955`) ; fin de la chaîne `IfThenElse_1766` (non suivie).
|
|||
|
|
|
|||
|
|
## D. Écarts à la fiche et à GIREV-PRE
|
|||
|
|
|
|||
|
|
- **GIREV-PRE M2 est à corriger** : `_20748` n'est pas « le message affiché » mais un doublon mort de `_340` (qui l'est). « Le message deviendrait atteignable » (§ 3.2 M2) est faux pour l'écran ; la décision GQ4 « on le rebranche » repose sur cette prémisse : à re-soumettre à l'utilisateur avec V1/V2/V3.
|
|||
|
|
- GIREV-PRE M4 écrit que le suffixe a un antislash : confirmé (un seul).
|
|||
|
|
- Appel 8 : `get_graphs` n'existe pas et `list_properties` demande `instance` ; la liste des graphes n'a pas été obtenue par MCP (sans conséquence sur les chiffres de GI, tirés des dumps puis relus).
|
|||
|
|
|
|||
|
|
## Fichiers
|
|||
|
|
|
|||
|
|
- Écrit : `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\REL\GIREV\GIREV-MCP-01.md`.
|
|||
|
|
- À commiter : `A Docs/Migration/etat/REL/GIREV/GIREV-MCP-01.md` (par le gardien, sur ticket). Aucun autre fichier écrit ; éditeur laissé ouvert (pid 21652).
|
|||
|
|
|
|||
|
|
Tours : 36 / 40 (comptés à la main ; `python -I Tools/FicheStats.py --lot GIREV` fait foi)
|
|||
|
|
|
|||
|
|
À verser : `lp-mcp` § 3 — dans un BP, `find_nodes {graph:{refPath:"/Game/UI/X.X:EventGraph"}, title}` fonctionne sans `load_asset` préalable ; `get_graphs` n'existe pas ; un événement personnalisé et un appel peuvent porter le même nom (ex. `Room.SavePreset` ≠ `GI.SavePreset`) : lire le `type_id` du nœud (`Presets|SavePreset` pour GI, `AddEvent|Custom|SavePreset` ou `|SavePreset` pour Room). Avant de déclarer un nœud de message « mort », chercher son jumeau de type Text (`ShowTutorialTxt`) : il peut porter le même texte et être vivant.
|