184 lines
13 KiB
Markdown
184 lines
13 KiB
Markdown
|
|
# 01 — Architecture initiale de LifePlay (référence 4.27, écarts 5.5)
|
||
|
|
|
||
|
|
> Document de référence de la reprise de migration (2026-09-29).
|
||
|
|
> Source : étude en lecture seule de `D:\Game\LifePlay-master 4.27` (tables de noms, d'imports et
|
||
|
|
> d'exports des `.uasset`, graphes Blueprint, code C++, journal d'exécution 4.27 Development).
|
||
|
|
> Complément : `Docs/Architecture/VictoryPlugin_Architecture.md` (C++ et plugins) et
|
||
|
|
> `Docs/Architecture/Rapport_Session_2026-09-28.md` (bug ouvert).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Vue d'ensemble
|
||
|
|
|
||
|
|
LifePlay est un **moteur de script piloté par des données texte**, écrit presque entièrement en
|
||
|
|
Blueprint. Il n'y a **ni DataTable, ni JSON, ni XML, ni clé de gameplay dans les `.ini`**.
|
||
|
|
|
||
|
|
```
|
||
|
|
Content/Modules/** (fichiers texte : .lpmod .lpstat .lpaction .lpscene .lpai .lpquest
|
||
|
|
│ .lptalk .lpdesc .lpcharacter .lpworld, tables *.txt)
|
||
|
|
│ lus à l'exécution, sur disque, hors paquet
|
||
|
|
▼
|
||
|
|
Plugins/ModdingExtra (C++) LoadTxt · SaveTxt · GetAllFilesFromFolder
|
||
|
|
│ FFileHelper / IFileManager sur FPaths::ProjectContentDir()
|
||
|
|
▼
|
||
|
|
Content/BPs/GI.uasset (GameInstance, 606 fonctions, 618 variables, 50 Mo)
|
||
|
|
│ analyse, tableaux Raws_*, structures, interpréteur du DSL
|
||
|
|
├──► ÉVÉNEMENTS CheckForScenes → PlayScene → ReadSceneLine → CallFunction (219 commandes)
|
||
|
|
├──► PERSONNAGES GeneratePerson → LoadPreset / Person.RandomizeAll
|
||
|
|
└──► SAUVEGARDE Save_C, GameSettings_C, CityExpansion_C (USaveGame) + .lpcharacter
|
||
|
|
▼
|
||
|
|
Content/BPs/Person.uasset (386 fonctions : morphs, peau, cheveux, stats) UI/* (≈100 widgets)
|
||
|
|
Plugins/StreetMap (280 villes) Source/LifePlay (helpers AssetRegistry, compat Victory)
|
||
|
|
```
|
||
|
|
|
||
|
|
Contrainte de packaging **vitale** : `Config/DefaultGame.ini`
|
||
|
|
`+DirectoriesToAlwaysStageAsNonUFS=(Path="Modules")`. `Modules` doit rester en fichiers nus à côté
|
||
|
|
de l'exécutable : il est lu par `FFileHelper`, pas par le système de paquets. Les mods de la
|
||
|
|
communauté reposent sur ce point.
|
||
|
|
|
||
|
|
## 2. Configuration de démarrage
|
||
|
|
|
||
|
|
| Fichier | Clé | Valeur |
|
||
|
|
|---|---|---|
|
||
|
|
| `DefaultEngine.ini` | `GameInstanceClass` | `/Game/BPs/GI.GI_C` |
|
||
|
|
| `DefaultEngine.ini` | `GlobalDefaultGameMode` | `/Game/BPs/GM.GM_C` |
|
||
|
|
| `DefaultEngine.ini` | `GameDefaultMap` | `/Game/Scenes/CentralLondon.CentralLondon` |
|
||
|
|
| `DefaultGame.ini` | `DirectoriesToAlwaysStageAsNonUFS` | `Modules` |
|
||
|
|
| `DefaultGame.ini` | `UsePakFile` | `False` |
|
||
|
|
| `DefaultInput.ini` | 55 `ActionMappings` (34 actions), 13 `AxisMappings` (6 axes) | consommés par `BPs/PC` uniquement |
|
||
|
|
|
||
|
|
Aucun `GConfig` dans le C++. Les réglages joueur sont dans `Saved/SaveGames/GameSettings.sav`.
|
||
|
|
|
||
|
|
## 3. Couches logicielles
|
||
|
|
|
||
|
|
### 3.1 C++ du projet
|
||
|
|
| Module | Type | Contenu utile |
|
||
|
|
|---|---|---|
|
||
|
|
| `Source/LifePlay` | Runtime | `ULPAssetRegistryHelpers::GetAssetByObjectPath` (nœud pur, utilisé par `GI`, `Person`, `Room`, `UI/VisualMorph`) ; en 5.5 aussi `LPVictoryCompat`, `LPNavigationHelpers` |
|
||
|
|
| `Source/LifePlayEditorTools` | Editor | commandlets d'analyse et de correction de graphes (`LPDumpFunction`, `LPCheckMeshAssignment`, `LPFix*`, `LPCheckStreetMap`) |
|
||
|
|
|
||
|
|
`ALifePlayGameModeBase` est vide : le vrai mode de jeu est `/Game/BPs/GM`.
|
||
|
|
|
||
|
|
### 3.2 Plugins
|
||
|
|
| Plugin | Rôle | Fonctions consommées par le contenu |
|
||
|
|
|---|---|---|
|
||
|
|
| `ModdingExtra` (Vinfamy, Runtime, `PreLoadingScreen`) | **toute l'entrée/sortie de données** | `LoadTxt` (9 assets), `GetAllFilesFromFolder` (6), `SaveTxt` (4) |
|
||
|
|
| `StreetMap` (fork Vinfamy) | villes OSM : routes, bâtiments, `SearchByBuildingName` | 292 assets |
|
||
|
|
| `VictoryBPLibrary` (4.27 seulement) | 2 nœuds : `Victory_LoadTexture2D_FromFile`, `Victory_SaveStringToOSClipboard` | remplacé en 5.5 par `LPVictoryCompat` + `[CoreRedirects]` |
|
||
|
|
|
||
|
|
## 4. Formats de données
|
||
|
|
|
||
|
|
| Motif | Format | Champs | Consommateur (`GI`) |
|
||
|
|
|---|---|---|---|
|
||
|
|
| `Modules/<id>/<id>.lpmod` | `CLÉ: valeur` | `MODULE_UNIQUEID/NAME/AUTHOR/LINK/DESCRIPTION/REQUIREMENTS` | `removeDeletedMods`, `UI/ModManager` |
|
||
|
|
| `Modules/ModLauncher.config` | ligne 1 `UseConfigIgnoreAppData:true/false`, puis `UniqueID:IsEnabled` (déduit) | — | `ReadModLauncher` → `ParseConfig` → `ModEnableds`. **Absent du disque dans les deux versions** |
|
||
|
|
| `*.lpstat` | `CLÉ: valeur` | `STAT_ID, STAT_NAME, PLAYER_ONLY, NPC_ONLY, HIGHER_BETTER, STAT_MIN, STAT_MAX, DAILY_CHANGE, DEFAULT_VALUE` | `PopulateStats` → `StatValue[]` |
|
||
|
|
| `*.lpaction` | `CLÉ: valeur` | `ACTION_UNIQUEID/NAME, WHERE, WHEN, MINUTES, TIMEOUT_MINUTES, ALSO_TIMEOUT, EFFECTS, CONDITIONS, MOVE_FIRST, SCENE_ALWAYS, ANIMATION` | `PopulateActions` → `ActionDetail[]`, `AmenityAction[]` |
|
||
|
|
| `*.lpscene` | en-tête `WHAT/WHERE/WHEN/WHO/OTHER`, puis corps DSL | — | `PopulateScenes` → `Scene[]` ; corps relu par `PlayScene` |
|
||
|
|
| `*.lpai` | corps DSL (5 premières lignes ignorées) | — | `LPAI`, `AI_High/Med`, `UpdateAI` |
|
||
|
|
| `*.lpquest` | `CLÉ: valeur` | `ID, NAME, DESC, ONCE, CONDITIONS, START` | `PopulateQuests` → `Quest[]` |
|
||
|
|
| `*.lptalk`, `*.lpdesc` | condition + textes, séparateur `##`, préfixes `*START*`/`*END*` | — | `PopulateTalksAndDescs` |
|
||
|
|
| `*.lpcharacter` | `CATÉGORIE Param: p% v1, p% v2…` ; plage `lo=>hi` | catégories `INFO, HAIR, SKIN, MORPH, STAT, SCALE, PENIS` | `LoadPreset` → `ReadLine` → `ChanceMinMax` → `GenerateAndApply{Floats,Strings,Bools}` |
|
||
|
|
| `*.lpworld` | taille de pièce, blocs `*****` (maillage `///` matériaux `///` transformation) | — | `PopulateWorldPresets`, `Room` |
|
||
|
|
| `Modules/names_{F,M}.txt` | un prénom par ligne | — | `FillNamePool` |
|
||
|
|
| `Modules/outfits_{M,F}[_work/_sports/_swim].txt` | `;` entre tenues, `,` entre pièces | — | `ReadOutfits` |
|
||
|
|
| `Modules/uniforms.txt` | lieux, puis listes F et M | — | `readUniforms` |
|
||
|
|
| `Modules/Clothes4.txt`, `SimplifyMorphs.txt`, `donors.txt` | `Nom: Daz?: Slots: Tag,Nombre` | — | `populateClothes4`, `SimplifyMorphs` |
|
||
|
|
| `Modules/MorphTags/*.txt` | un morph par ligne, `: tag` optionnel | — | `PopulateAllMorphTags` |
|
||
|
|
| `Modules/beauty_standards_default.txt` | `tag: poidsA: poidsB` | — | `PopulateBeautyStandardsDefault`, `getRandomEthnicity`, `getRandomAge` |
|
||
|
|
| `Modules/Pregnancy_Morphs.txt` | `Morph:valeur` | — | `FillPregnancyMorphs` |
|
||
|
|
| `Saved/SaveGames/GameSettings.sav` | `GameSettings_C` (63 variables) | `PercentMale/Female/IntSame/IntOpp/IntTrans`, `Fantasy*`, `BodyShapeDistribution`, `BeautyStandards_Custom`, `ModEnableds`, volumes… | `LoadSettings` / `SaveSettings` |
|
||
|
|
| `Saved/SaveGames/<slot>.sav` | `Save_C` (137 variables) | jour, heure, `GeneratedIndex`, relations, `ActorVars`, `GlobalVariables`, grossesses, IA… | `SaveGame` / `LoadGame` / `NewGame` |
|
||
|
|
| `Content/Saves/<slot>/Characters/N.lpcharacter` | format `.lpcharacter` | personnages générés | `SavePreset`, `DuplicateCharacters` |
|
||
|
|
|
||
|
|
Volumétrie 5.5 (identique à 4.27, 2 051 fichiers) : `vin_Base` 1 394 fichiers dont 752 `.lpscene`,
|
||
|
|
286 `.lpaction`, 128 `.lpcharacter`, 110 `.lpworld`, 69 `.lpstat` ; 15 autres modules `vin_*`.
|
||
|
|
36 fichiers de données sont **vides en amont** (34 `.lpscene` de `vin_base/scenes/corruption`,
|
||
|
|
`strt_white_m.lpcharacter`, `boss_asks_impregnate)cms.lpscene`) : ce n'est pas un défaut du portage.
|
||
|
|
|
||
|
|
Structures Blueprint utilisées par les pipelines (`Content/Structs`, 57 au total) : `Variable`,
|
||
|
|
`ActorVars`, `ChanceMinMax`, `SMBool`, `ActionDetail`, `Scene`, `Quest`, `StatValue`, `ModEnabled`,
|
||
|
|
`StringArray`, `FloatArray`, `IntArray`, `PersonData`, `MorphSlider`, `NameFloat`, `Cloth`, `Inventory`.
|
||
|
|
|
||
|
|
## 5. Pipelines
|
||
|
|
|
||
|
|
### 5.1 Démarrage et injection des données
|
||
|
|
```
|
||
|
|
GI.ReceiveInit → UpdateFullScreenMode, AssetReg, minuterie 2 s → DelayedStart
|
||
|
|
DelayedStart → PC.BeginPlay, StreetMap_Static.BeginPlay, LoadSettings, Make10k
|
||
|
|
LoadSettings : GameSettings.sav → ~60 variables de GI
|
||
|
|
→ ReadModLauncher (LoadTxt ModLauncher.config) → ParseConfig → ModEnableds
|
||
|
|
→ removeDeletedMods (GetAllFilesFromFolder "Modules" *.lpmod)
|
||
|
|
→ DefaultDistributionIfNeeded (presets male/female → BodyShapeDistribution)
|
||
|
|
→ PopulateRaws
|
||
|
|
PopulateRaws (pour chaque module activé)
|
||
|
|
FillNamePool, readUniforms, PopulateAllMorphTags, PopulateBeautyStandardsDefault, FillPregnancyMorphs
|
||
|
|
GetAllFilesFromFolder("Modules/<id>", *.lpstat|lpaction|lpscene|lptalk|lpdesc|lpquest|lpai)
|
||
|
|
→ LoadTxt → Raws_* (tableaux de chaînes)
|
||
|
|
→ PopulateStats → PopulateActions → PopulateScenes → PopulateQuests → PopulateTalksAndDescs
|
||
|
|
→ PopulateWorldPresets → RemoveNPCOnly → CleanRaws
|
||
|
|
```
|
||
|
|
Également au démarrage, appelant non identifié (voir §7) : `donors`, `Clothes4`, `SimplifyMorphs`,
|
||
|
|
`outfits_*`.
|
||
|
|
|
||
|
|
### 5.2 Événements (scènes)
|
||
|
|
```
|
||
|
|
Action du joueur : TakeActionWithBuilding / TakeModActionWithBuilding → CheckForScenes
|
||
|
|
→ LoopCheckForScenes → UpdateCheckForScenes (pour chaque Scene) :
|
||
|
|
CheckSceneForTimeout → CheckConditionsWhen → CheckConditionsWho → CheckConditionsOther → PlayScene
|
||
|
|
Autres déclencheurs : UpdateAI (.lpai), actions SCENE_ALWAYS, quêtes (StartQuest → TestScene)
|
||
|
|
PlayScene : LoadTxt(fichier) → GetValidLines → boucle ReadSceneLine
|
||
|
|
If/Elseif/Else/Endif/While/Random/Sex( traités en ligne ; variables : GI.Variables (Array<Variable>)
|
||
|
|
ReadSceneLine → CallFunction (219 commandes) / CallFunctionReturnBool (84 conditions)
|
||
|
|
fin : DefaultDistribution, destroyAllDummies, clearScenePersons, SceneEnd, Timeout
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5.3 Personnages
|
||
|
|
```
|
||
|
|
DSL generatePerson(p1..pn) → GI.GeneratePerson(Presets, Temporary, Relative, MatchRace, VariableToClear) → Person_C
|
||
|
|
SpawnDummy (réserve de Person_C pré-instanciés, MakeDummyPersons) → BackupCbe → PopulateEachPerson → RandomizeStats
|
||
|
|
A) presets fournis : pour chaque .lpcharacter dont le nom se termine par le preset → LoadPreset
|
||
|
|
B) aucun preset : determinePersonVars (Percent*, Fantasy*, MajorityRace, getRandomEthnicity/Age)
|
||
|
|
→ IsMale, Race, Genital, UpdatePlayerMesh, randomizeName, Person.RandomizeAll
|
||
|
|
→ ChooseNPCBodyShape(BodyShapeDistribution) → LoadPreset(corps) → MorphRace
|
||
|
|
→ SavePreset → SaveTxt("Saves/_session/Characters/<GeneratedIndex>.lpcharacter") → AddVariable
|
||
|
|
LoadPreset : LoadTxt → ReadLine → tirage → GenerateAndApplyFloats (morphs, matériaux)
|
||
|
|
/ GenerateAndApplyStrings (maillages, cheveux, textures via GetAssetByObjectPath + GetAsset)
|
||
|
|
/ GenerateAndApplyBools → ResolveConflictingMorphs, Unfat, ShowAppropriateGenital, UpdateProxyMorphs
|
||
|
|
```
|
||
|
|
Tout le hasard passe par `KismetMathLibrary` (`RandomFloat`, `RandomBool`, `RandomInteger`…,
|
||
|
|
`Array_Shuffle`) : pas de graine, pas de `RandomStream`.
|
||
|
|
|
||
|
|
### 5.4 Sauvegarde
|
||
|
|
`SaveGame(Name, Index)` : `SaveSettings` + `CreateSaveGameObject(Save_C)` + ~100 variables +
|
||
|
|
`SaveGameToSlot`. Personnages : `DuplicateCharacters` copie `Saves/_session/Characters` ↔
|
||
|
|
`Saves/<slot>/Characters` (`LoadTxt`/`SaveTxt`).
|
||
|
|
|
||
|
|
## 6. Dépendances moteur des pipelines (points sensibles au portage)
|
||
|
|
|
||
|
|
| Dépendance | Où | Risque 5.5 |
|
||
|
|
|---|---|---|
|
||
|
|
| Structures utilisateur avec tableaux (`Variable`) | conteneur de variables du DSL | `Variable.uasset` porte un `DoubleProperty` en 5.5 (conversion LWC) — piste principale du bug ouvert |
|
||
|
|
| `TMap` dans les `USaveGame` | `Save_C`, `GameSettings_C` | compatibilité des `.sav` existants |
|
||
|
|
| `GetAssetByObjectPath` + `GetAsset` | chargement de maillages et textures par chemin | API passée à `FSoftObjectPath` ; broches orphelines au portage |
|
||
|
|
| `SetSkeletalMesh`, `SetMasterPoseComponent`, propriété `SkeletalMesh` | `Person`, `GI`, UI | renommés/dépréciés en 5.1 |
|
||
|
|
| Composants proxy ajoutés à l'exécution (`AddComponent`) | `Person::NewProxy`, `MorphProxy` | type réel `USkinnedMeshComponent` ≠ `USkeletalMeshComponent` (cause de l'échec de R-03) |
|
||
|
|
| `FFileHelper`, `IFileManager` sur `ProjectContentDir` | `ModdingExtra` | stable ; exige `Modules` hors paquet |
|
||
|
|
| `GameplayStatics` SaveGame | `GI` | stable |
|
||
|
|
|
||
|
|
## 7. Inconnues à lever (lot L5)
|
||
|
|
|
||
|
|
1. Appelants de `ReadOutfits`, `populateClothes4`, `PopulateCharGenPage`, `MakeDummyPersons` (probablement `PC`, `MainMenu` ou une minuterie).
|
||
|
|
2. Format exact de `ModLauncher.config` (déduit, jamais observé sur disque).
|
||
|
|
3. Types de valeur de `PerksUnlocked`, `VoiceTypes`, `ActionCount` (`Map<string,?>`).
|
||
|
|
4. Fin de `GeneratePerson` après `fertility_npc` (conditions de branche vers `ChooseNPCBodyShape`).
|
||
|
|
5. Fichiers sans chargeur confirmé : `step4_morphs.txt`, `test_output.txt`, `FAQ.txt`, `AllMorphTags.txt`.
|
||
|
|
6. Contenu binaire de `Default.sav` (un `BodyShapeDistribution` périmé est possible).
|
||
|
|
|
||
|
|
## 8. Écarts 5.5 déjà en place (hérités de la campagne du 2026-09-08)
|
||
|
|
|
||
|
|
VictoryPlugin retiré et remplacé par `LPVictoryCompat` (+ `[CoreRedirects]`) ; `StreetMap` porté
|
||
|
|
(LWC, R-01, R-02) ; `ModdingExtra` porté ; `Target.cs` en `BuildSettingsVersion.V5` /
|
||
|
|
`Unreal5_5` ; 8 562 packages resauvegardés en UE5 ; commandlets de correction R-03 à R-06.
|
||
|
|
État détaillé et défauts : `02_Audit_Logiciel.md`.
|