DOC-MOD-3 : cycle de vie d'un mod, § 2.6 et 7 schémas Mermaid
Phase DOC-MOD-3 (CHG-227). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
18abdee4fc
commit
f7f1775bae
2 changed files with 183 additions and 0 deletions
|
|
@ -132,6 +132,188 @@ Aucune clé `.lpmod` ne permet de verrouiller un autre module.
|
|||
Convention des clés d'animation : `<préfixe du pack>_<clip>` en minuscules (`qua_dance_loop`, `fap_as_talk`), assets
|
||||
`<clé>_F` et `<clé>_M`. Une clé inconnue ne joue rien (journal `PlayDaily(<clé>) -> cle inconnue` hors Shipping).
|
||||
|
||||
### 2.6 Schémas du cycle de vie
|
||||
|
||||
Schémas tirés des relevés `LPDumpFunction` de `GI` (graphe principal, 6 199 nœuds) et de `UI/ModuleTick`, du code C++
|
||||
du jeu et du moteur (`GameInstance.cpp`, `PluginManager.cpp`). Les noms entre parenthèses sont les paramètres des
|
||||
fonctions ou des événements. `GI.X` désigne un événement ou une fonction du Blueprint `GI` ; `ULP…` une classe C++ du jeu.
|
||||
|
||||
#### 2.6.1 États d'un module
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Installe : extraction de l'archive
|
||||
Installe : Installé (fichiers sur disque)
|
||||
Installe --> Monte : démarrage, FPluginManager (Mods/id)
|
||||
Monte : Plugin monté (assets /id/ visibles)
|
||||
Monte --> Liste : GI.LoadSettings, ULPModInfoSubsystem
|
||||
Liste : Listé (.lpmod lu)
|
||||
Liste --> Inscrit : ReadModLauncher ou GameSettings.sav, MODULE_DEFAULT_ENABLED
|
||||
Inscrit : Inscrit dans GI.ModEnableds
|
||||
Inscrit --> Actif : IsEnabled = true
|
||||
Inscrit --> Inactif : IsEnabled = false
|
||||
Actif --> Inactif : GI.ToggleMod(Mod, false)
|
||||
Inactif --> Actif : GI.ToggleMod(Mod, true)
|
||||
Actif : Actif (textes lus par GI.PopulateRaws)
|
||||
Inactif : Inactif (textes ignorés, plugin toujours monté)
|
||||
Liste --> Retire : dossier Modules/id supprimé
|
||||
Retire : Retiré de ModEnableds (GI.removeDeletedMods)
|
||||
Retire --> [*]
|
||||
Actif --> Decharge : fermeture du jeu
|
||||
Inactif --> Decharge : fermeture du jeu
|
||||
Decharge : Déchargé (sous-systèmes Deinitialize, conteneurs démontés)
|
||||
Decharge --> [*]
|
||||
```
|
||||
|
||||
`vin_Base` ne peut pas passer à l'état Inactif : la case de `UI/ModuleTick` n'appelle `GI.ToggleMod` que si
|
||||
`UniqueID != 'vin_Base'`.
|
||||
|
||||
#### 2.6.2 Démarrage : séquence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant M as Moteur (FPluginManager)
|
||||
participant R as Registre d'assets
|
||||
participant GI as GI (Blueprint)
|
||||
participant S as Sous-systèmes C++
|
||||
participant D as Disque Modules/
|
||||
M->>M: ReadAllPlugins : Mods/id/id.uplugin devient un plugin de type Mod
|
||||
M->>M: ConfigureEnabledPlugins (dépendances Plugins, obligatoire absente = arrêt)
|
||||
M->>R: CanContainContent : montage de /id/, MountPak(pak, 0)
|
||||
R->>R: AssetRegistry.bin du mod ajouté
|
||||
M->>GI: UGameInstance::Init puis ReceiveInit (minuterie 2 s)
|
||||
M->>S: SubsystemCollection.Initialize
|
||||
S->>D: ULPModInfoSubsystem lit Modules/*/id.lpmod
|
||||
S->>R: ULPModDailiesSubsystem relève les UAnimSequence sous /id/Anims
|
||||
GI->>GI: DelayedStart puis LoadSettings(LoadLastSave)
|
||||
GI->>D: ReadModLauncher, ParseConfig(Content), ModEnableds si UseConfig
|
||||
GI->>D: GameSettings.sav donne ModEnableds, puis removeDeletedMods
|
||||
S->>GI: ULPHairstyleSubsystem ajoute les modules MODULE_DEFAULT_ENABLED
|
||||
GI->>D: PopulateRaws lit les textes des modules cochés (LoadTxt, LPDataCache)
|
||||
S->>GI: ULPModDailiesSubsystem::Tick ajoute les clips à Room.Dailies
|
||||
S->>GI: ULPModInfoSubsystem::Tick (2 s) : avertissement MODULE_GAME_VERSION
|
||||
```
|
||||
|
||||
#### 2.6.3 Arbre logique de `GI.LoadSettings(LoadLastSave)`
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["GI.LoadSettings(LoadLastSave)"] --> B["ThemeSong.SetActive(false), r.Streaming.PoolSize 1500, EnableDynamicResolution"]
|
||||
B --> C{"DoesSaveGameExist('GameSettings', 0)"}
|
||||
C -- oui --> D["LoadGameFromSlot('GameSettings', 0), cast GameSettings"]
|
||||
D --> E["ModEnableds = GameSettings.ModEnableds"]
|
||||
E --> F["GI.ReadModLauncher()"]
|
||||
F --> G["GI.removeDeletedMods()"]
|
||||
G --> H["environ 60 réglages copiés (DifficultyPlayerInput, SceneFrequency, MarkerSize...)"]
|
||||
H --> I["loadAverageAttractiveness()"]
|
||||
I --> J["DefaultDistributionIfNeeded()"]
|
||||
J --> K["GI.PopulateRaws()"]
|
||||
C -- non --> F2["GI.ReadModLauncher()"]
|
||||
F2 --> K
|
||||
K --> L{"LoadLastSave et réglages existants"}
|
||||
L -- oui --> M["LoadThis = LastSaveGame"]
|
||||
F -.-> F1["ParseConfig(Content = ModLauncher.config) : UseConfig, ModEnableds"]
|
||||
F1 -.-> F1b{"UseConfig"}
|
||||
F1b -. oui .-> F1c["ModEnableds = liste du fichier"]
|
||||
```
|
||||
|
||||
`Modules/ModLauncher.config` est absent en pratique : `UseConfig` est faux et `ModEnableds` vient de
|
||||
`GameSettings.sav` (ou de la valeur par défaut du Blueprint au premier lancement).
|
||||
|
||||
#### 2.6.4 Arbre logique de `GI.PopulateRaws()`
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
P["GI.PopulateRaws()"] --> P1["FillNamePool, readUniforms, PopulateAllMorphTags, PopulateBeautyStandardsDefault, FillPregnancyMorphs"]
|
||||
P1 --> P2["FilenamesUsed.Clear()"]
|
||||
P2 --> L{"Pour chaque ModEnabled (UniqueID, IsEnabled) de ModEnableds, dans l'ordre"}
|
||||
L -- "IsEnabled faux" --> L
|
||||
L -- "IsEnabled vrai" --> T["Pour chaque type : lpstat, lpaction, lpscene, lptalk, lpdesc, lpquest, lpai"]
|
||||
T --> F["GetAllFilesFromFolder('Modules/' + UniqueID, Ext)"]
|
||||
F --> N{"nom de fichier (après le dernier '/') déjà dans FilenamesUsed ?"}
|
||||
N -- oui --> X["ignoré : le module lu avant l'emporte"]
|
||||
N -- non --> Y["LoadTxt vers Raws_Stat, Raws_Action, Raws_Scene, Raws_Talks, Raws_Descs, Raws_Quests, AI_High, AI_Med ; FilenamesUsed.Add(nom)"]
|
||||
L -- fin --> Q["PopulateStats, PopulateActions, PopulateScenes, PopulateQuests, PopulateTalksAndDescs, PopulateWorldPresets, RemoveNPCOnly, CleanRaws"]
|
||||
Q --> R["IsModEnabled(...) : options liées à un module (Datings...)"]
|
||||
```
|
||||
|
||||
Le premier fichier lu l'emporte. Comme l'affichage du gestionnaire est inversé (§ 2.4), c'est le module le plus bas
|
||||
de la liste affichée. Les `.lpscene` passent en plus deux conditions sur leur contenu avant d'être ajoutées.
|
||||
|
||||
#### 2.6.5 Gestionnaire de mods : ouverture, actions, fermeture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
O["Menu en partie : HideUI() puis GI.CreateModManagerWidget(GameStart)"] --> O2["CreateWidget ModManager, GameStart mémorisé, AddToViewport(0)"]
|
||||
O1["Écran titre (UI15) : GI.CreateModManagerWidget(GameStart = false), ModManager.TitleMenu = menu"] --> O2
|
||||
O2 --> O3["TempModuleTicks.Clear(), TempModules.Clear()"]
|
||||
O3 --> O4["LPMods = GetAllFilesFromFolder('Modules', 'lpmod')"]
|
||||
O4 --> O5{"Pour chaque .lpmod : UniqueID déjà dans TempModules ?"}
|
||||
O5 -- non --> O6["TempModules.Add(UniqueID) ; CreateWidget ModuleTick (FullString = fichier entier, UniqueID)"]
|
||||
O6 --> O7["CheckIfModAlreadyFound(UniqueID, ModuleTick) : AlreadyExisted"]
|
||||
O7 --> O8["NameText, AuthorText depuis MODULE_NAME, MODULE_AUTHOR ; TempModuleTicks.Add"]
|
||||
O5 -- fin --> O9["removeDeletedMods(), AddTempModuleTicks(), SetInputMode_UIOnly(ModManager)"]
|
||||
O9 --> U{"Action du joueur dans UI/ModuleTick"}
|
||||
U -- "case cochée ou décochée" --> T1{"UniqueID différent de 'vin_Base'"}
|
||||
T1 -- oui --> T2["GI.ToggleMod(Mod = UniqueID, IsEnabled) : remplace l'élément de ModEnableds"]
|
||||
T1 -- non --> T3["sans effet"]
|
||||
U -- "monter ou descendre" --> S1["GI.SortLoadOrder(ForUp = 1 ou -1, ModuleIndex = position affichée)"]
|
||||
S1 --> S2{"ModuleIndex = 1 et ForUp = 1, ou hors bornes ?"}
|
||||
S2 -- non --> S3["Array_Swap(ModEnableds, L-1-ModuleIndex, L-1-ModuleIndex+ForUp), ClearChildren, AddTempModuleTicks"]
|
||||
S2 -- oui --> S4["refusé"]
|
||||
U -- "fermer, en partie" --> C1["GI.CloseModManager(GameStart) : ShowUI, ClearModManagerWidget, PopulateRaws, ModManagerOn = false"]
|
||||
C1 --> C2{"GameStart"}
|
||||
C2 -- oui --> C3["CharGenInput(GameStart = true)"]
|
||||
C2 -- non --> C4["DelayThenFollowUp()"]
|
||||
U -- "fermer, écran titre (UI15)" --> C5["menu titre réaffiché, ClearModManagerWidget, PopulateRaws, ULPModSettingsLibrary::SaveModSelection"]
|
||||
```
|
||||
|
||||
#### 2.6.6 Appel d'une animation de mod
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Sc as Scène ou action
|
||||
participant GI as GI.CallFunction
|
||||
participant P as Person (Blueprint patché)
|
||||
participant L as ULPModDailiesLibrary
|
||||
participant Ro as Room.Dailies
|
||||
Sc->>GI: Actor.animate(clé) ou ANIMATION: clé
|
||||
GI->>P: PlayDaily(clé), cas 'animate'
|
||||
P->>P: SwitchString des clés du jeu (dance...)
|
||||
P->>L: cas Default : IsModDaily(clé)
|
||||
alt clé de mod
|
||||
L-->>P: vrai (journal « cle de mod » hors Shipping)
|
||||
P->>Ro: PlayDailyAnim parcourt Room.Dailies, suffixe _F ou _M selon IsMale
|
||||
Ro-->>P: UAnimSequence /id/Anims/.../clé_F ou clé_M
|
||||
P->>P: currentDaily joué par l'AnimBP Daily ou Daily_F
|
||||
else clé inconnue
|
||||
L-->>P: faux (journal « cle inconnue ») : rien n'est joué
|
||||
end
|
||||
```
|
||||
|
||||
La case du gestionnaire n'intervient pas dans cet arbre (§ 6, E1).
|
||||
|
||||
#### 2.6.7 Désactivation, désinstallation et déchargement
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Module décoché : GI.ToggleMod(Mod, false)"] --> B["fermeture du gestionnaire : GI.PopulateRaws()"]
|
||||
B --> B1["textes du module non relus : actions, scènes, stats absentes"]
|
||||
A --> C["ULPHairstyleSubsystem::IsModuleEnabled : coiffures filtrées à la demande"]
|
||||
A --> D["ULPModInfoSubsystem : plus d'avertissement de version"]
|
||||
A --> E["ULPModDailiesSubsystem : clips toujours dans Room.Dailies (E1)"]
|
||||
A --> F["plugin /id/ toujours monté jusqu'à la fermeture"]
|
||||
G["Dossier Modules/id supprimé"] --> H["démarrage suivant : GI.removeDeletedMods() retire l'entrée de ModEnableds"]
|
||||
I["Dossier Mods/id supprimé"] --> J["démarrage suivant : plugin absent, clips et coiffures du mod introuvables"]
|
||||
K["Fermeture du jeu"] --> K1["UGameInstance::Shutdown, ReceiveShutdown"]
|
||||
K1 --> K2["SubsystemCollection.Deinitialize : LPModDailies retire son ticker et vide les clés ; LPModInfo retire son ticker et ferme l'avertissement"]
|
||||
K2 --> K3["moteur : modules et conteneurs démontés à la sortie"]
|
||||
```
|
||||
|
||||
Il n'existe pas de déchargement à chaud : un plugin de mod reste monté du démarrage à la fermeture, quel que soit
|
||||
l'état de sa case.
|
||||
|
||||
## 3. Propriétés réellement lues
|
||||
|
||||
### 3.1 `<id>.uplugin` (moteur)
|
||||
|
|
|
|||
|
|
@ -1131,6 +1131,7 @@ Validation L7c/L7d (2026-10-02, parc, même cadrage) : la nuit reste claire (sol
|
|||
| CHG-155 | 2026-10-05 | ShowCouple | Un lit est reconnu par son nom. Il ne bloque un déplacement que vers le bas, pour se poser ; le retour horizontal n'est plus arrêté et le contact ne renvoie plus la boîte | après avoir quitté le lit, la boîte ne pouvait plus y revenir | revenir au test `DoesPackageExist` et au filtre du flanc seul |
|
||||
| CHG-156 | 2026-10-05 | Clavier | `LPKeyboardSubsystem` : bouton « Clavier » ajouté à l'exécution dans `MainMenu.SettingsScrollBox` ; panneau pour changer, ajouter ou retirer une touche (actions et axes clavier). Écrit dans `Saved/Config/Windows`, pas dans `GameSettings.sav` | pouvoir réaffecter les touches, dont Q, sans modifier les Blueprints | retirer `LPKeyboardSubsystem.h/.cpp` et la dépendance `UMG` |
|
||||
| CHG-158 | 2026-10-05 | Réglages | `LPSettingsSubsystem` : onglets Audio, Video, Lewd, General, Keyboard, Misc au-dessus de `SettingsScrollBox`. Les lignes du Blueprint restent en place et sont montrées selon leur texte ; le reste va dans Misc. Keyboard affiche la liste des touches | la liste unique ne montrait pas le clavier | retirer `LPSettingsSubsystem.h/.cpp` |
|
||||
| CHG-227 | 2026-10-07 | DOC-MOD-3 | `Docs/Migration/23_Cycle_De_Vie_Mod.md` (§ 2.6 nouveau, 7 schémas Mermaid) | schémas du cycle de vie d'un module demandés par l'utilisateur : états (installé, monté, listé, inscrit, actif / inactif, retiré, déchargé), séquence de démarrage (moteur, registre, `GI`, sous-systèmes C++), arbres logiques de `GI.LoadSettings(LoadLastSave)`, `GI.PopulateRaws()`, du gestionnaire (`CreateModManagerWidget(GameStart)`, `ToggleMod(Mod, IsEnabled)`, `SortLoadOrder(ForUp, ModuleIndex)`, `CloseModManager(GameStart)`), appel d'une animation de mod, désactivation et déchargement ; graphes reconstitués depuis le relevé `LPDumpFunction -BP=GI -Fn=EventGraph -Pins -Exec` et l'ordre d'initialisation de `UGameInstance` (moteur) ; 7 schémas rendus sans erreur par Mermaid 11 | aucun changement de code ni de configuration | `.\Tools\Restore.ps1 -Lot DOC-MOD-3` |
|
||||
| CHG-226 | 2026-10-07 | DOC-MOD-2 | `Docs/Migration/23_Cycle_De_Vie_Mod.md` (§ 2.4, 3.1, 3.2, 3.3 et 3.4 nouveaux, 5, 6) ; `Docs/Migration/Journal_Modifications.md` | complément de la documentation du cycle de vie d'un mod, constats vérifiés dans les Blueprints (`GI`, `UI/ModuleTick`, relevés `LPDumpFunction`) et le moteur UE 5.5 : l'ordre de chargement existe (`GI.SortLoadOrder`, `PopulateRaws` : le premier fichier lu par nom gagne, le module le plus bas l'emporte, fichiers texte seulement) ; `vin_Base` verrouillé en dur dans `UI/ModuleTick` ; dépendance `.uplugin` obligatoire absente = le jeu ne démarre pas, donc aucune dépendance entre mods dans le `.uplugin` ; doublons entre `.uplugin`, `.lpmod` et `pack.json`, divergences dues à `New-IfMissing` de `DeliverAnims.ps1` ; évolutions E12 corrigée, E13 à E15 ajoutées | aucun changement de code ni de configuration | `.\Tools\Restore.ps1 -Lot DOC-MOD-2` |
|
||||
| CHG-225 | 2026-10-07 | DOC-MOD | `Docs/Migration/23_Cycle_De_Vie_Mod.md` (nouveau) ; `Docs/Migration/README.md` (ligne d'index) | documentation demandée par l'utilisateur : cycle de vie d'un mod, propriétés réellement lues par le moteur (`.uplugin`) et par le jeu (`.lpmod`), classes, architecture, capacités, évolutions possibles. Constat consigné : `LPModDailies` ne consulte pas la case du gestionnaire de mods (un pack d'animations décoché fournit encore ses clés, évolution E1) ; `MODULE_REQUIREMENTS` n'est pas vérifié | aucun changement de code ni de configuration | supprimer `23_Cycle_De_Vie_Mod.md` et cette entrée ; `.\Tools\Restore.ps1 -Lot DOC-MOD` |
|
||||
| CHG-224 | 2026-10-07 | AP7 | Cuisson DLC et essai en jeu empaqueté. `Config/DefaultGame.ini` : `ProjectVersion=2026.10.1.6` (version de référence d'essai, non publiée) ; `+DirectoriesToNeverCook` pour `/Game/Quaternius`, `/Game/FreeAnimationsPack`, `/Game/AnimPacks`, `/Game/Retarget_ue5` (sources de travail, jamais dans le jeu). `Tools/anim/DeliverAnims.py` : à la copie dans le mod, les réglages de compression qui pointent sur `/Engine/` sont remis à vide (les clips d'un pack UE5 référençaient `/Engine/Animation/DefaultAnim*CompressionSettings` : cuisson DLC refusée) ; la compression par défaut du projet s'applique, comme pour Quaternius | lot AP7, étape 7. Empaquetage Shipping `2026.10.1.6` (`D:\Game\LifePlay_Build_5.5_Shipping_AP7\Windows`, `Releases/2026.10.1.6`) ; mods cuits contre cette version : `lpr_anim_quaternius` (84 paquets, zip 15 798 332 o), `lpr_anim_freeanims` (20 paquets, 0 référence moteur, zip 4 416 299 o) dans `D:\Game\LifePlay_Publication\Mods\` ; module d'essai `lpr_anim_essai` copié dans le seul jeu d'essai (hors du projet : `LifePlay_Backup_5.5/AP7/hors_build`). **Essai utilisateur en jeu empaqueté : animations jouées** (`qua_*`, `fap_*`, témoin `dance`) | `.\Tools\Restore.ps1 -Lot AP7` ; supprimer `D:\Game\LifePlay_Build_5.5_Shipping_AP7` et `Releases/2026.10.1.6` ; rien n'est commité dans le dépôt du jeu |
|
||||
|
|
|
|||
Loading…
Reference in a new issue