LifePlay-Revival/Docs/Migration/etat/U58/U1/U1-T4a-IMPL.md

187 lines
17 KiB
Markdown
Raw Normal View History

Fiche U1-T4a — Niveau N3 — Modèle prévu opus-xhigh | utilisé Opus 5.5 (claude-opus-5-5) — Agent lp-impl — Skills sk-protocol, ue-cpp-build, lp-build, lp-ue-compat (préchargés) ; lp-commandlets, lp-paths (invoqués : outil Skill disponible ; ue-cpp-build déjà préchargé, non réinvoqué)
# U1-T4a — commandlet `LPAuditBlueprintCalls` (addon privé, lecture seule) — IMPL, non compilé
Statut : **écrit, non compilé, non exécuté** (interdit par la fiche : éditeur ouvert). Toute affirmation « compile »
reste à établir par la fiche N0 suivante. Légende : établi = lu dans les sources (fichier:ligne) ; estimé = déduit ;
incertain = à vérifier à la compilation ou à l'exécution.
## 1. Fichiers touchés (dépôt addon `D:\Game\LifePlay-Sandbox`, aucun commit)
| Fichier | Action |
|---|---|
| `Plugins/LPSandbox/Source/LPModTools/LPAuditBlueprintCallsCommandlet.h` | créé (51 lignes) |
| `Plugins/LPSandbox/Source/LPModTools/LPAuditBlueprintCallsCommandlet.cpp` | créé (~980 lignes, ASCII, fins de ligne LF comme les voisins) |
| `Plugins/LPSandbox/Source/LPModTools/LPModTools.Build.cs` | 2 dépendances privées ajoutées (diff § 2) |
| `D:\Game\LifePlay-master 5.5\Docs\Migration\etat\U58\U1\U1-T4a-IMPL.md` | ce livrable (`etat/` ignoré par git : `.gitignore:74`) |
`git -C D:\Game\LifePlay-Sandbox status --porcelain` après travail : `M LPModTools.Build.cs`, `?? …Commandlet.cpp`,
`?? …Commandlet.h`, `?? Tools/claude/` (déjà présent avant la fiche). Jeu : `M Docs/Migration/27_Plan_Migration_UE58.md`
**non modifié par moi** (seulement lu) — présent au moment du contrôle, à attribuer à l'orchestrateur. Rien d'inclus de
`LifePlay` ni `LifePlayEditorTools` ; aucun correctif de compatibilité UE4 touché.
## 2. Diff du Build.cs
```diff
@@ -38,7 +38,12 @@ public class LPModTools : ModuleRules
"SkeletalMeshUtilitiesCommon",
"SkeletalMeshDescription",
- "AnimationCore"
+ "AnimationCore",
+ // LPAuditBlueprintCalls (lot U1, fiche U1-T4a) : noeuds K2 des graphes Blueprint et FBlueprintMetadata
+ "BlueprintGraph",
+ // LPAuditBlueprintCalls : K2Node_CallFunction.h et K2Node_Event.h incluent KismetCompilerMisc.h
+ // (module KismetCompiler, dependance privee de BlueprintGraph, donc non transmise)
+ "KismetCompiler"
});
```
Justification (établi) : `K2Node_CallFunction.h:15` et `K2Node_Event.h:16` incluent `KismetCompilerMisc.h`
(`Editor/KismetCompiler/Public`) ; `BlueprintGraph.Build.cs` ne cite `KismetCompiler` qu'en privé. Même paire que
`LifePlayEditorTools.Build.cs` du jeu. `UMGEditor`, `Kismet`, `AnimGraph` **non ajoutés** : non nécessaires
(WidgetBlueprint / AnimBlueprint traités par la base `UBlueprint` et `GetAllGraphs` ; aucun `FBlueprintEditorUtils`,
`FKismetEditorUtilities` ni type d'AnimGraph utilisé).
## 3. Comportement
- Usage : `UnrealEditor-Cmd.exe <projet> -run=LPAuditBlueprintCalls [-Root=/Game[,/Autre]] [-Out=<dossier>] [-Limit=N]`.
Défaut des racines : `/Game`, `/ModdingExtra`, `/LPAnimCore` **s'ils sont montés** (LPAnimCore a
`CanContainContent: false` → ignoré et signalé ; ModdingExtra monté, `Content/` vide → 0 asset attendu). Racine
donnée mais non montée → erreur, code 1. Sortie par défaut `<projet>/Saved/Audit/BlueprintCalls/` (ignoré par git).
- Registre : `SearchAllAssets(true)` puis `ScanPathsSynchronous(racines)` (piège lp-commandlets), `GetAssetsByPaths`
récursif, disque seulement ; filtre `FAssetData::GetClass()->IsChildOf(UBlueprint)` **avant** tout chargement ;
tri par chemin ; `-Limit` après tri.
- Chargement un par un (`LoadObject<UBlueprint>`) ; `null` = échec listé. Toutes les 50 : `FinishAllCompilation()` puis
`CollectGarbage(RF_NoFlags)` (pratique du moteur, § 4).
- Graphes : `UBlueprint::GetAllGraphs` (Function, Macro, Ubergraph, DelegateSignature, graphes d'interfaces,
extensions, chacun avec `GetAllChildrenGraphs`) + `UEdGraphNode::GetSubGraphs` des nœuds (même paquet), dédoublonnés.
- Relevé par nœud : classe du nœud (toujours) ; `UK2Node_CallFunction` et dérivés → fonction (déclaration d'origine
par remontée `GetSuperFunction`) ; `UK2Node_Variable` hors `UK2Node_StructOperation` → propriété (`get`/`set`) ;
`UK2Node_BaseMCDelegate` (Add/Remove/Clear/Call/Assign) → propriété délégué ; `ComponentBoundEvent` /
`ActorBoundEvent` → propriété délégué ; `UK2Node_Event` hors `CustomEvent` → fonction (`evenement`) ;
`UK2Node_FunctionEntry` → fonction (`surcharge`) si sa déclaration d'origine est native.
- Lecture seule : aucun `MarkPackageDirty`, `Modify`, `SavePackage`, `CompileBlueprint` dans le code (vérifiable par
`grep`). La résolution `FMemberReference` peut corriger un redirecteur **en mémoire** (`MemberReference.cpp:384-391`),
sans marquer le paquet (aucun `MarkPackageDirty` dans `MemberReference.cpp`, `grep` vide).
- Sorties : `calls.json` (`membres[]` : `type` fonction|propriete|noeud, `classe`, `classe_cpp`, `module`, `entete`,
`nom`, `usages`, `assets`, `premiers_assets` ≤ 20, `contextes`, `deprecie`, `depreciation[]`, `message`,
`non_resolus`, + `references_depreciees` pour les nœuds), tri type/module/classe/nom ; `node_classes.json` ;
`per_asset.csv` (`asset,classe,etat,graphes,noeuds,appels_natifs,references_natives,references_bp,non_resolus`) ;
`summary.txt` (totaux, classes d'assets, membres dépréciés utilisés, usages par module, échecs, 500 premières
références non résolues, code de retour).
- Code : 0 si tout est chargé et écrit ; 1 si un échec de chargement, aucune racine, aucun Blueprint ou une écriture
impossible. `UseCommandletResultAsExitCode = true` pour que le code du processus soit celui de `Main` (§ 4).
## 4. Choix d'API (sources 5.5.4 `D:\Game\Launcher\Engine\UE_5.5\Engine\Source`, recoupées en 5.8.3)
| API | 5.5 (établi) | 5.8 (établi) |
|---|---|---|
| `UBlueprint::GetAllGraphs` | `Runtime/Engine/Classes/Engine/Blueprint.h:1123`, impl. `Private/Blueprint.cpp:1855-1925` | `Blueprint.h:1107` |
| sous-graphes AnimGraph enregistrés dans `SubGraphs` | `Editor/AnimGraph/Private/AnimGraphNode_StateMachineBase.cpp:159`, `AnimStateNode.cpp:137`, `AnimStateTransitionNode.cpp:149` | — |
| `UEdGraph::GetAllChildrenGraphs` | `Runtime/Engine/Classes/EdGraph/EdGraph.h:205`, `Private/EdGraph/EdGraph.cpp:321` | — |
| `UEdGraphNode::GetSubGraphs / IsDeprecated / HasDeprecatedReference` | `EdGraphNode.h:687 / 853 / 856` ; `IsDeprecated` = `CLASS_Deprecated` (`EdGraphNode.cpp:616-619`), surchargé par `K2Node_SpawnActor.h:39` | `EdGraphNode.h:697 / 870 / 873` |
| `UK2Node_CallFunction::FunctionReference / GetTargetFunction` | `Editor/BlueprintGraph/Classes/K2Node_CallFunction.h:75 / 155` (impl. `.cpp:1375`) | `:71 / :150` (`UE_API`) |
| `UK2Node_Variable::VariableReference / GetPropertyForVariable` | `K2Node_Variable.h:56 / 166` | `:58 / :168` |
| `UK2Node_StructOperation : UK2Node_Variable` (Make/Break exclus) | `K2Node_StructOperation.h:29` | même ligne |
| `UK2Node_BaseMCDelegate::DelegateReference / GetProperty` | `K2Node_BaseMCDelegate.h:22 / 51` (public : macro `GENERATED_BODY_LEGACY` finit par `public:`, `Intermediate/…/K2Node_BaseMCDelegate.generated.h:41-46`) | `:22 / :51` (inline) |
| `UK2Node_ComponentBoundEvent` `DelegatePropertyName / DelegateOwnerClass / GetTargetDelegateProperty` | `K2Node_ComponentBoundEvent.h:36 / 40 / 73` | mêmes lignes |
| `UK2Node_ActorBoundEvent` idem | `K2Node_ActorBoundEvent.h:35 / 39 / 77` | mêmes lignes |
| `UK2Node_Event::EventReference / FindEventSignatureFunction` | `K2Node_Event.h:53 / 121` (impl. `.cpp:340`) | mêmes lignes |
| `UK2Node_FunctionTerminator::FunctionReference / FindSignatureFunction` | `K2Node_FunctionTerminator.h:32 / 59` (impl. `.cpp:195`) | mêmes lignes |
| `FMemberReference` `GetMemberName / GetMemberParentClass / GetMemberParentPackage / IsSelfContext / IsLocalScope` | `Runtime/Engine/Classes/Engine/MemberReference.h:203 / 221 / 226 / 240 / 246` | mêmes lignes |
| surcharge Blueprint → super-fonction = fonction surchargée | `Editor/KismetCompiler/Private/KismetCompiler.cpp:2291` ; `UFunction::GetSuperFunction` `Class.h:2030` | `Class.h:2680` |
| `FBlueprintMetadata::MD_DeprecatedFunction / MD_DeprecatedProperty / MD_DeprecationMessage` | `EdGraphSchema_K2.h:139 / 142 / 145` | `:143 / 146 / 149` |
| `CPF_Deprecated`, `CLASS_Deprecated` | `CoreUObject/Public/UObject/ObjectMacros.h:431`, `:250` | `:463`, `:269` |
| `UField::FindMetaData` (`WITH_METADATA` = `WITH_EDITORONLY_DATA`, `Core/Public/Misc/CoreMiscDefines.h:32`) | `Class.h:234-235` | `Class.h:272-273` |
| `FField::FindMetaData / GetOwnerStruct / GetOwnerUObject` | `Field.h:777-778 / 657 / 636` | `Field.h:937-938 / 811 / 790` |
| `UField::GetOwnerClass`, `UStruct::GetPrefixCPP`, `UObjectBaseUtility::GetPackage` | `Class.h:180`, `Class.h:590` (+`3234`), `UObjectBaseUtility.h:477` | `Class.h:218`, `781` (+`4330`), `UObjectBaseUtility.h:504` |
| `IAssetRegistry::GetAssetsByPaths / ScanPathsSynchronous / SearchAllAssets` | `AssetRegistry/Public/AssetRegistry/IAssetRegistry.h:238 / 655 / 666` | `:324 / 793 / 809` |
| `FAssetData::PackageName / AssetClassPath / GetObjectPathString / GetClass` | `CoreUObject/Public/AssetRegistry/AssetData.h:180 / 189 / 342 / 456` | `:190 / 203 / 352 / 466` |
| `FPackageName::MountPointExists` (racines enregistrées avec `/` final, ex. `/Game/` `PackageName.cpp:454`) | `Misc/PackageName.h:348`, impl. `PackageName.cpp:421-425` | `PackageName.h:356-358` (3 surcharges, `const FString&` exacte) |
| `CollectGarbage(RF_NoFlags)` précédé de `FAssetCompilingManager::FinishAllCompilation` | `UObjectGlobals.h:881` ; pratique : `Editor/UnrealEd/Private/Commandlets/BaseIteratePackagesCommandlet.cpp:917-928` ; `AssetCompilingManager.h:46 / 71` | `UObjectGlobals.h:952` ; `AssetCompilingManager.h:44 / 69` |
| `SearchAllAssets(true)` avant requête en commandlet | `CompileAllBlueprintsCommandlet.cpp:181` | — |
| `UseCommandletResultAsExitCode` (défaut `false` : le moteur force 1 si une erreur a été journalisée) | `Engine/Classes/Commandlets/Commandlet.h:96`, `Private/Commandlets/Commandlet.cpp:27`, `Launch/Private/LaunchEngineLoop.cpp:4256-4262` | `Commandlet.h:96`, `LaunchEngineLoop.cpp:4217-4218` |
| `LoadObject` | `UObjectGlobals.h:1990` (`const TCHAR*`) | `UObjectGlobals.h:2175` (`FStringView`, `const TCHAR*` converti) |
| `FJsonObject::Set*Field` | `Json/Public/Dom/JsonObject.h:181-182` (clés `FString`) | `JsonObject.h:142, 153-160, 199, 210-211, 226-227` (clés `FStringView` : `TEXT()` et `FString` acceptés) ; aucune itération des clés (piège R2 évité) |
| divers : `FName::LexicalLess`, `TArray::FilterByPredicate`, `FEngineVersion::Current`, `FParse::Value` | `NameTypes.h:737`, `Array.h:1208`, `EngineVersion.h:40`, `Parse.h:59 / 70` | `NameTypes.h:826`, `Array.h:1737` (`[[nodiscard]]`, résultat utilisé), `EngineVersion.h:40`, `Parse.h:60 / 71` |
**Garde de version : aucune.** Toutes les API utilisées existent avec la même forme d'appel en 5.5 et 5.8 (tableau) ;
pas de `ENGINE_MINOR_VERSION` ni `UE_VERSION_OLDER_THAN` nécessaire (estimé, à confirmer par un build 5.8 en U4).
## 5. Écarts à la SPEC (fiche § 4–5)
1. **Espace de noms nommé** `LPAuditBlueprintCallsImpl` au lieu d'anonyme : c'est le style réel des voisins
(`LPAnimCatalogImpl`, `LPAnimIdentifyImpl`) et la règle `lp-build` (collision C2374) ; `using namespace` dans `Main`
seulement.
2. **Champs en plus** : `calls.json` (`classe_cpp`, `contextes`, `depreciation[]`, `message`, `non_resolus`,
`references_depreciees`), `per_asset.csv` (`classe`, `etat`, `references_natives`, `references_bp`, `non_resolus`),
`summary.txt` (membres dépréciés utilisés, usages par module, 500 premières références non résolues, classes
d'assets non chargées). Les champs demandés sont tous présents.
3. **Code 1 aussi** si aucune racine montée, aucun Blueprint trouvé, ou écriture impossible (zéro résultat = échec,
`sk-protocol`) ; `UseCommandletResultAsExitCode = true` (sans quoi une erreur de compilation au chargement d'un
Blueprint du jeu forcerait 1 même si tout est chargé).
4. `-Root` accepte `,` ou `+` comme séparateur (PowerShell coupe à la virgule sans guillemets).
5. Événements et fonctions surchargées dont la déclaration d'origine **n'est pas native** : non comptés comme
« références BP » (ce sont des définitions du jeu) ; `CustomEvent` ignoré. Les références BP comptées sont celles des
appels, variables et délégués.
6. **Non couvert (limites, à décider)** : Blueprints de niveau (`ULevelScriptBlueprint` dans les `.umap` : pas un asset
de premier niveau, il faudrait charger les cartes) ; types portés par les broches, cible de `DynamicCast`, structure
des `Make/Break`, fabriques des nœuds asynchrones (`UK2Node_BaseAsyncTask`), `CreateDelegate`, nœuds Property
Access, liaisons de propriétés UMG et d'AnimGraph : **classe du nœud seulement**. Contenu des macros moteur
(`StandardMacros`, hors racines) non parcouru.
7. Compilation au chargement **laissée au moteur** (chargement par défaut, comme l'éditeur) : `LOAD_DisableCompileOnLoad`
écarté car non récursif (`ObjectMacros.h:80` : « dependencies will still compile on load »), état mixte.
8. `FinishAllCompilation()` appelé sans condition avant chaque GC (le moteur le conditionne à `FApp::CanEverRender()`,
`BaseIteratePackagesCommandlet.cpp:917`) : estimé sans effet de bord, plus sûr pour le GC.
## 6. Points incertains à vérifier (compilation N0, exécution)
- **Compilation** (incertain) : `SetObjectField(…, TSharedRef)` et `MakeShared<FJsonValueObject>(TSharedRef)` comme
les voisins (compilent en 5.5 aujourd'hui) ; initialisation `TArray<FString>{ TEXT(...) }` ; conversion implicite
`TObjectPtr → const UEdGraphNode*` dans les boucles (`ObjectPtr.h:661` 5.5) ; avertissements de masquage (C4456-4458)
relus à la main, non prouvés. Attendu : `LPAuditBlueprintCallsCommandlet.cpp` + `.gen.cpp` compilés, lien de
`UnrealEditor-LPModTools.dll`, aucun avertissement nouveau.
- **Racines** : forme de `MountPointExists` (testée avec et sans `/` final) ; la ligne de journal
`racines : /Game, /ModdingExtra ; non montees (ignorees) : /LPAnimCore` doit apparaître. `/Game` non monté = défaut.
- **Classes d'assets** : `GetClass()` sans résolution ; les classes non chargées (souvent des classes Blueprint
d'instances) sont comptées à part dans `summary.txt` — vérifier qu'aucune n'est une famille de Blueprint (plugin non
chargé).
- **Durée et mémoire** : 9 068 `.uasset` sous `Content` (`find Content -name "*.uasset" | wc -l`) ; nombre de
Blueprints inconnu ; chaque Blueprint charge ses dépendances dures. Commencer par `-Limit=20`.
- **Sémantique** : `appels_natifs` = nœuds d'appel vers une fonction native ; une référence non résolue dont le parent
est natif apparaît dans `calls.json` avec `non_resolus` > 0 (clé = classe du parent, pas la classe déclarante).
- **Lecture seule** : le moteur peut écrire hors dépôts (DDC `D:/DDC`, `Saved/`, `Intermediate/` ignorés) ; à
contrôler par `git status` avant / après (3 dépôts).
## 7. Commandes pour la fiche suivante (N0, éditeur fermé, une seule compilation)
Avant : éditeur Unreal fermé ; `Makefile.bin` à déplacer seulement si un test sans addon a eu lieu depuis le dernier
build (`lp-build`) ; noter les dates de `Binaries\Win64\UnrealEditor-LPModTools.dll` (jeu) et de
`D:\Game\LifePlay-Sandbox\Plugins\LPSandbox\Binaries\Win64` ; relever les 3 `git status`.
```powershell
cd 'D:\Game\LifePlay-master 5.5'
git status --porcelain > "$env:TEMP\U1T4a_jeu_avant.txt"
git -C 'Content\Modules' status --porcelain > "$env:TEMP\U1T4a_modules_avant.txt"
git -C 'D:\Game\LifePlay-Sandbox' status --porcelain > "$env:TEMP\U1T4a_addon_avant.txt"
$UE='D:\Game\Launcher\Engine\UE_5.5\Engine'; $Proj='D:\Game\LifePlay-master 5.5\LifePlay.uproject'
& "$UE\Build\BatchFiles\Build.bat" LifePlayEditor Win64 Development -Project="$Proj" -WaitMutex *> 'Saved\Logs\portage\U1-T4a_build.log'; "code=$LASTEXITCODE"
# preuves : code 0, ligne « Using Visual Studio … 14.38 », Compile LPAuditBlueprintCallsCommandlet.cpp, lien UnrealEditor-LPModTools.dll, 0 avertissement nouveau
.\Tools\RunCommandlet.ps1 -Lot U1 -Commandlet LPAuditBlueprintCalls -Args '-Limit=20 -Out=Saved/Audit/BlueprintCalls_essai'
.\Tools\RunCommandlet.ps1 -Lot U1 -Commandlet LPAuditBlueprintCalls
# preuve de chargement du nouveau code : lignes LogLPAuditBlueprintCalls « racines : … » et « AUDIT blueprints … -> <dossier> »
# sorties : Saved\Audit\BlueprintCalls\{calls.json,node_classes.json,per_asset.csv,summary.txt}
git status --porcelain | Compare-Object (Get-Content "$env:TEMP\U1T4a_jeu_avant.txt")
git -C 'Content\Modules' status --porcelain | Compare-Object (Get-Content "$env:TEMP\U1T4a_modules_avant.txt")
git -C 'D:\Game\LifePlay-Sandbox' status --porcelain | Compare-Object (Get-Content "$env:TEMP\U1T4a_addon_avant.txt")
```
Contrôles de cohérence suggérés (`sk-recount`) : lignes de `per_asset.csv` − 1 = « traites » de `summary.txt` ;
somme `noeuds` du CSV = « noeuds » du résumé = somme `noeuds` de `node_classes.json` ; `etat=echec` = échecs listés.
## 8. Handoff
Suite : lp-builder (N0) doit compiler `LifePlayEditor` 5.5 éditeur fermé puis lancer `-Limit=20` puis tout `/Game`
(commandes § 7), état : code écrit dans l'addon (3 fichiers, non commités), jamais compilé ni exécuté.