# 07 — Architecture de LifePlay en UE 5.5 (état final de la migration) > Complète `01_Architecture_Initiale.md`, qui décrit le fonctionnement hérité de 4.27 (données texte, > `ModdingExtra`, interpréteur du DSL dans `GI`). Ce document décrit ce que la migration a ajouté ou > appris : la couche de compatibilité C++, les sous-systèmes, les différences de comportement du > moteur et le fonctionnement de la scène (studio, pièces, écran d'appel), mesurés en jeu. > État au 2026-10-02 : V1.1 publiée, lots L7a à L7l validés. --- ## 1. Vue d'ensemble ``` Content/Modules/** (texte, hors paquet) inchangé depuis 4.27 (2 051 fichiers, MD5 identiques) │ Plugins/ModdingExtra LoadTxt / SaveTxt / GetAllFilesFromFolder (porté UE5, trace en Verbose) │ Content/BPs/GI ── interpréteur du DSL, événements, personnages, sauvegarde (Blueprints 4.27, │ Person, Room, AI, UI/* resauvegardés UE5) │ │ appels Blueprint redirigés vers la couche de compatibilité (nœuds rebranchés par commandlet) ▼ Source/LifePlay ── bibliothèques de compatibilité (comportement 4.27 garanti) │ LPStringCompat · LPMeshCompat · LPNavigationHelpers │ LPAssetRegistryHelpers · LPVictoryCompat │ └── sous-systèmes d'instance de jeu (aucun Blueprint modifié) LPSessionLog (journal, diagnostic) · LPSecondScreen (caméra d'appel) LPOutdoorRoom (plafond des lieux extérieurs) Source/LifePlayEditorTools ── commandlets d'analyse et de correction (éditeur uniquement) Plugins/StreetMap (280 villes, porté LWC) Plugins/McpAutomationBridge (éditeur uniquement) ``` Principe directeur : **les Blueprints de gameplay restent ceux de 4.27**. Chaque écart de comportement du moteur est corrigé soit en rebranchant des nœuds vers une fonction C++ qui reproduit le comportement 4.27 (corrections « CX-B »), soit par un sous-système C++ qui agit à l'exécution sans toucher aux assets. ## 2. Modules C++ ### 2.1 `Source/LifePlay` (runtime, livré avec le jeu) | Classe | Type | Rôle | Introduit par | |---|---|---|---| | `ULPAssetRegistryHelpers` | bibliothèque Blueprint | `GetAssetByObjectPath` en nœud **pur** (le moteur l'a rendu impur) ; `GetAssetsByClassName`, `GetAssetObjectPath` (paramètre `FName` → `FTopLevelAssetPath`) | portage 4.27 ; CX-B01 | | `ULPVictoryCompat` | bibliothèque Blueprint | les 2 nœuds du Victory Plugin réellement utilisés (`LoadTexture2D_FromFile`, `SaveStringToOSClipboard`) ; `[CoreRedirects]` dans `DefaultEngine.ini` | CX-C06 | | `ULPStringCompat` | bibliothèque Blueprint | `ParseIntoArray`, `Contains`, `Split`, `FindSubstring`, `FindUE4` avec la sémantique **UE 4.27** (§4) | CX-B08, CX-B12 | | `ULPMeshCompat` | bibliothèque Blueprint | `GetSkeletalMesh(Component)` = `Cast(GetSkinnedAsset())`, valable pour tout `USkinnedMeshComponent` (les proxys de `Person` n'en sont pas des `USkeletalMeshComponent`) | CX-B10 | | `ULPNavigationHelpers` | bibliothèque Blueprint | `GetRandomLocationInNavigableRadius` en nœud **pur** (le remplaçant moteur est impur) | CX-B11 | | `ULPSessionLogSubsystem` | `UGameInstanceSubsystem` | résumé de démarrage, bilan de session dédoublonné, outils de diagnostic sur option de ligne de commande (§5) | L3, L5, L7i, L7l | | `ULPSecondScreenSubsystem` | `UGameInstanceSubsystem` | à chaque image, cadre la caméra `SecondScreen` sur le visage du contact affiché (`GI.SecondScreenPerson`) | L7j (ERR-031) | | `ULPOutdoorRoomSubsystem` | `UGameInstanceSubsystem` | masque le plafond `WallT` de la pièce quand l'échelle Z de sa racine est < 0,05 (lieux extérieurs) | L7l (ERR-036) | | `ALifePlayGameModeBase` | — | vide ; le vrai mode de jeu est `/Game/BPs/GM` | 4.27 | Dépendances (`LifePlay.Build.cs`) : publiques `Core`, `CoreUObject`, `Engine`, `InputCore`, `AssetRegistry`, `NavigationSystem` ; privées `ImageWrapper`, `ApplicationCore`, `EngineSettings`. Structure plate (pas de sous-dossier `Public/`) : `PublicIncludePaths.Add(ModuleDirectory)`. ### 2.2 `Source/LifePlayEditorTools` (éditeur uniquement) 24 commandlets, en trois familles (catalogue et usages : `08_Guide_Developpeur.md` §5) : - **analyse en lecture seule** : `LPDumpFunction`, `LPDumpAssets`, `LPDumpComponents`, `LPDumpWidgetTree`, `LPDumpCDO`, `LPDumpSave`, `LPCheckMeshAssignment`, `LPCheckStreetMap`, `LPCheckMeshes`, `LPTestStringCompat` ; - **correction de graphes** (rebranchement de nœuds, contrôle broche par broche intégré, `-DryRun`) : `LPFixAssetRegistryNodes`, `LPFixAssetRegistryPins`, `LPFixEditableTextBoxFont`, `LPFixOrphanBoundEvents`, `LPFixParseIntoArray`, `LPFixButtonPadding`, `LPFixSkeletalMeshGet`, `LPFixNavRandomPoint`, `LPFixStringSearch` ; - **correction de cartes ou de paquets** : `LPFixZeroScaleActors`, `LPConvertAtmosphericFog`, `LPFixSceneCapture`, `LPResavePackages`. `LPFixDeprecatedNodes` (R-03/R-04 d'origine) est conservé pour l'historique mais **ne doit plus être utilisé** : sa variante R-03 aggrave ERR-002 (CX-B05 rejeté), sa variante R-04 est remplacée par `LPFixNavRandomPoint`. ### 2.3 Plugins | Plugin | Cible | Remarque | |---|---|---| | `ModdingExtra` | runtime | entrée/sortie des données ; trace d'appel en catégorie `LogModdingExtra` (`Verbose`) | | `LPAnimCore` | runtime | lot DC1 : `LPAnimRedirect` (redirection des clips) et `LPCoupleSim` (géométrie du couple), rapatriés de l'addon ; module `LPAnimCore` dans `Plugins/LPAnimCore` | | `StreetMap` | runtime | porté LWC ; 280 villes vérifiées identiques à 4.27 (L7h) | | `EnhancedInput` | runtime | système d'entrée actif ; exécute les 34 actions héritées de `DefaultInput.ini` | | `McpAutomationBridge` | **éditeur uniquement** (`TargetAllowList: Editor`) | pilotage de l'éditeur par serveur MCP ; jamais publié (contient un jeton) | | `AndroidFileServer` | désactivé | réécrivait un `SecurityToken` dans `DefaultEngine.ini` (ERR-023) | ## 3. Configuration (écarts à 4.27) | Fichier | Clé | Valeur | Raison | |---|---|---|---| | `DefaultGame.ini` | `+DirectoriesToAlwaysCook=(Path="/Game")` | — | assets chargés par chemin texte : sans cela, 3 257 paquets cuits au lieu de 8 561 (ERR-026) | | `DefaultGame.ini` | `DirectoriesToAlwaysStageAsNonUFS=Modules`, `UsePakFile=False` | inchangés | `Modules` en fichiers nus, comme la version de l'auteur | | `DefaultGame.ini` | clés de nativisation | retirées | inexistantes en UE5 (L7c) | | `DefaultEngine.ini` | `r.DynamicGlobalIlluminationMethod=0`, `r.ReflectionMethod=2`, `r.Shadow.Virtual.Enable=0` | explicites | rendu identique à celui validé, indépendant des valeurs par défaut du moteur (L7c) | | `DefaultEngine.ini` | `DefaultGraphicsRHI_DX12` | explicite | idem | | `DefaultEngine.ini` | `r.AntiAliasingMethod=2` (TAA) | explicite (`r.DefaultFeature.AntiAliasing` est ignorée par UE5) | supprime le scintillement à l'approche des personnages (ERR-032, L6a) | | `DefaultEngine.ini` | `[CoreRedirects]` Victory → `LPVictoryCompat` | — | chargement de `GI`, `MainMenu`, `Inventory`… | | `DefaultEngine.ini` | 4 clés PhysX | retirées | PhysX n'existe plus (Chaos) | | `LifePlay.uproject` | `TargetPlatforms: ["Windows"]`, plugins explicites | — | L2 | ## 4. Différences de comportement du moteur découvertes (UE 4.27 → 5.5) Aucune n'est signalée par le compilateur : un graphe identique donne un résultat différent. Elles expliquent l'essentiel des défauts de la migration. | # | API | UE 4.27 | UE 5.5 | Effet dans LifePlay | Correction | |---|---|---|---|---|---| | 1 | `IAssetRegistry::GetAssetsByClass` | paramètre `FName ClassName` | `FTopLevelAssetPath` ; la valeur est **perdue** à la montée de version | aucun corps, vêtement, coiffure énumérable : personnages identiques (ERR-002) | CX-B01 | | 2 | `FString::ParseIntoArray("")` | `[]` | `[""]` ; séparateur insensible à la casse | `generatePerson()` charge les 141 presets : personnages invisibles (ERR-027) | CX-B08 | | 3 | `FString::Find("", IgnoreCase, FromStart)` | `INDEX_NONE` | `0` | `Contains(x, "")` vrai : filtres de morphs sans effet (ERR-005), erreurs en cascade (ERR-006/007) | CX-B12 | | 4 | style par défaut de `UButton` | marge 2,2,2,2 (`FCoreStyle`) | 12,1.5,12,1.5 (`FUMGCoreStyle`) | les assets 4.27 ne stockent pas la valeur par défaut : barre de temps décalée (ERR-034) | CX-B09 | | 5 | `USkinnedMeshComponent::SkeletalMesh` | propriété | dépréciée ; `GetSkeletalMeshAsset()` n'existe que sur `USkeletalMeshComponent` | un remplacement naïf renvoie `None` sur les proxys (CX-B05 rejeté) | CX-B10 | | 6 | `GetAssetByObjectPath`, `K2_GetRandomLocationInNavigableRadius` | purs | impurs | un rebranchement naïf ajoute des broches d'exécution non reliées : nœud élagué | helpers purs | | 7 | `FEditableTextBoxStyle::Font` | champ | `TextStyle.Font` | broche orpheline : cuisson en échec (ERR-021) | CX-B02 | | 8 | `AAtmosphericFog` | classe active | dépréciée, convertie en `SkyAtmosphere` au chargement | aucun changement visible | L7d (remplacement explicite) | | 9 | Shipping (`NO_LOGGING`) | — | les catégories de journal deviennent `FNoLoggingCategory` sans `GetCategoryName` | compilation Shipping en échec | `FName` constant (L7g) | Leçon générale : **une propriété sérialisée en delta prend silencieusement la nouvelle valeur par défaut du moteur** (#4), et **une fonction de chaîne peut changer de sémantique sur les cas limites** (#2, #3). Comparer les sources du moteur 4.27 et 5.5 sur ces cas avant de conclure. ## 5. Journalisation et diagnostic (`ULPSessionLogSubsystem`) Le sous-système n'altère aucun message existant (les comparaisons A/B avec 4.27 en dépendent). Il ajoute : - au démarrage : `===== LifePlay : demarrage =====` (versions, modules, fichiers par type, échecs `LoadTxt`) ; - à la fermeture ou par la commande console `LifePlay.LogSummary` : `===== LifePlay : bilan de session` (volume par catégorie, signatures d'erreurs dédoublonnées) ; - des outils activés par la ligne de commande, tous inactifs par défaut (liste dans `09_Commandes_Utiles.md` §4) : variables de `GI` au démarrage et à la fin (`-LPDumpVars`), trace des exceptions de script avec variables locales et cadres appelants (`-LPTraceScriptEx`…), relevé de chemins d'objets sur un motif du journal (`-LPDumpOnLog`) ou périodique (`-LPDumpEvery`). Un chemin de relevé part de l'instance de jeu et suit les propriétés objet ou structure : `Room.WallT.RelativeLocation`, `PlayerCharacter.CapsuleComponent.CapsuleHalfHeight`… C'est ce qui a permis de mesurer la cause réelle d'ERR-036 (le plafond), là où l'analyse statique des données désignait à tort une dalle de neige. ## 6. Scène, pièces et écran d'appel (mesurés en jeu) ### 6.1 Studio unique Tous les lieux (bâtiments, extérieurs) sont construits par **un seul acteur `Room_C_0`** placé dans un studio, en (−3 131 543 ; −14 967 213 ; −115) de `CentralLondon`. Pendant une visite, la ville (`StreetMapStatic`) est masquée. ### 6.2 Pièce et échelle `.lpworld` - La racine de `Room` (cube, matériau `FntWall`) prend l'**échelle de la première ligne du `.lpworld`**. - Les meubles sont positionnés et dimensionnés relativement à cette racine : leurs hauteurs sont donc multipliées par l'échelle Z. - Échelles Z déclarées : 81 lieux à 0,2, 5 à 0,3, 1 à 0,4, et **0,01 pour les 7 lieux extérieurs** (`beach`, `forest`, `mountain`, `park`, `pool`, `river`, `street`). - Le plafond `WallT` (Z relatif 2 040, sans collision) suit l'échelle : 4,08 m en intérieur, mais 18 à 20 cm au-dessus du sol en extérieur, où il masquait pieds et pieds de meubles (ERR-036, défaut d'origine 4.27). `ULPOutdoorRoomSubsystem` le masque en extérieur et le rend en intérieur. ### 6.3 Écran d'appel (second écran) - `GI::Show` place le contact sur son emplacement de scène décalé de −10 000 000 en Y, sur la copie de scène `SecondScreenFloor`. - La caméra `SceneCapture2D` `SecondScreen` rend vers `Render/SecondScreen`, affiché par `UI/Scene::FaceRender`. - Dans la carte 4.27 d'origine, cette caméra n'avait pas de racine et filmait le ciel (ERR-031, défaut d'origine). L7j lui a donné une racine (`LPFixSceneCapture`), et `ULPSecondScreenSubsystem` la cadre à chaque image : 80 cm devant l'os `head` du contact, champ de 30°. ### 6.4 Ciel `BP_Sky_Sphere` (matériau `M_Sky_Panning_Clouds2`), lumière directionnelle `Sun`, `SkyLight` à cubemap, `SkyAtmosphere` (ex-`AtmosphericFog`, Z −100 000, `PlanetTopAtComponentTransform`). Le soleil ne suit pas l'heure : la nuit reste claire en extérieur, **comme en 4.27**. Un grand disque blanc à l'horizon existe déjà avant L7d (origine non étudiée). ### 6.5 Variables du DSL `GI::GetVariable` traite à part les noms spéciaux (`Player`, `Ptr`, `Interacting`, `CurrentCompanion`, `A1` à `A5`) par un `SwitchString`. La variable `AI` est un `AIDummy`. Les variables `Person` vides signalées en jeu (ERR-003) existent au même taux en 4.27. ## 7. Ce qui reste hérité tel quel Effets Cascade (4 systèmes, pris en charge par UE 5.5), entrées héritées exécutées par Enhanced Input, éclairage dynamique sans précalcul. Défauts d'origine 4.27 conservés : ERR-030 (habillage), ERR-037 (Quick dress), nuit claire, disque blanc. Voir `Registre_Erreurs.md`.