21 KiB
Fiche REL-SAV-T1 — Niveau N3− — Modèle prévu opus (lp-diag, effort medium) | utilisé claude-opus-5-5 (session REL, sans sous-agent) — Agent session REL — Skills lp-lot, lp-paths
REL-SAV-DIAG : renommer le dossier de sauvegarde LifePlay en LifePlay-Revival (2026-10-13)
Lecture seule : aucun jeton UE, rien écrit hors ce dossier etat\REL\SAV\. Moteur lu : D:\Game\Launcher\Engine\UE_5.8\Engine (abrégé E\), moteur installé (E\Build\InstalledBuild.txt présent).
Niveaux de preuve : établi (lu dans la source ou mesuré), estimé (déduit, non rejoué), incertain.
Verdict
L'hypothèse est confirmée : sous Windows, le jeu Shipping écrit dans %LOCALAPPDATA%\<FApp::GetProjectName()>\Saved. Le nom de projet LifePlay est figé dans l'exe monolithique et sert aussi au chemin du contenu : on ne le change pas. Le moteur prévoit deux leviers :
- un argument de lancement
-UserDir=<chemin absolu>, déjà utilisé par les.batd'essai du projet ; - une macro de compilation
UE_SAVED_DIR_OVERRIDE, sans effet avec le moteur Launcher, car Core y est précompilé.
Recommandation : option B (lanceur officiel qui passe -UserDir="%LOCALAPPDATA%\LifePlay-Revival"), complétée par la garde B+ si l'on veut couvrir le double-clic sur LifePlay.exe. Les deux sont réversibles, sans changement du contrat des mods ni de l'éditeur. B seule ne touche ni Source\ ni Config\ ni Content\ ; B+ ajoute du C++ dans le module LifePlay.
1. Calcul du dossier utilisateur et de Saved (UE 5.8, Windows, jeu empaqueté)
| Étape | Source | Niveau |
|---|---|---|
ProjectSavedDir() = ProjectUserDir() + Saved (+ _<suffixe> si -saveddirsuffix=), mis en cache au premier appel |
E\Source\Runtime\Core\Private\Misc\Paths.cpp:86-115, 485-494 |
établi |
ProjectUserDir() : 1) -UserDir= s'il est donné ; 2) sinon, si ShouldSaveToUserDir() : UserSettingsDir()\UE_SAVED_DIR_OVERRIDE si la macro est définie, sinon UserSettingsDir()\<FApp::GetProjectName()> ; 3) sinon ProjectDir() (dossier du jeu) |
Paths.cpp:451-471 |
établi |
ShouldSaveToUserDir() = FApp::IsInstalled() ou -SaveToUserDir ou FPlatformProcess::ShouldSaveToUserDir() (faux par défaut) ou -UserDir non vide |
Paths.cpp:183-192 ; E\Source\Runtime\Core\Private\GenericPlatform\GenericPlatformProcess.cpp:98-102 |
établi |
FApp::IsInstalled() est vrai par défaut en Shipping desktop ; il l'est aussi si Engine\Build\InstalledProjectBuild.txt existe, ou avec -Installed. -NotInstalled l'annule |
E\Source\Runtime\Core\Private\Misc\App.cpp:212-242 (l. 218-219, 225-227, 231-237) |
établi |
UserSettingsDir() = dossier connu LocalAppData (LocalAppDataLow en intégrité basse) |
E\Source\Runtime\Core\Private\Windows\WindowsPlatformProcess.cpp:1459-1467 |
établi |
-UserDir= est lu par FParse::Value(…, "UserDir="). Un chemin relatif est rattaché à ProjectDir() ; aucune variable d'environnement n'est développée par le moteur (0 occurrence de « environment » dans CommandLine.cpp) : il faut un chemin absolu déjà développé |
Paths.cpp:1940-1960 ; E\Source\Runtime\Core\Private\Misc\CommandLine.cpp |
établi |
Journaux : ProjectLogDir() = ProjectSavedDir()\Logs sous Windows (SUPPORTS_LOGS_IN_USERDIR = 0) |
Paths.cpp:36-38, 574-595 |
établi |
Nom du projet dans un exe monolithique : GInternalProjectName = UE_PROJECT_NAME, défini par UBT à partir du nom du .uproject. Le même nom sert au chemin ..\..\..\<Nom>\<Nom>.uproject |
E\Source\Runtime\Core\Public\Modules\ModuleManager.h:1102, 1116 ; E\Source\Programs\UnrealBuildTool\Configuration\UEBuildModuleCPP.cs:2792-2797 ; E\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp:666-716 |
établi |
Aucun réglage .ini ne change ce dossier : seuls la ligne de commande et la macro interviennent dans Paths.cpp |
Paths.cpp:451-471 (aucune lecture de GConfig) |
établi |
Constat sur les builds du projet (établi) : les 20 builds LifePlay_Build_5.8_*_Development lancés ont un Windows\LifePlay\Saved à côté de l'exe (Development non « installé »). Le Shipping, lui, écrit dans %LOCALAPPDATA%\LifePlay\Saved. Ce dossier existe sur le poste et contient :
| Sous-dossier | Taille | Fichiers |
|---|---|---|
Config |
53 K | 29 (Windows\GameUserSettings.ini, LPColorGrade.ini, LPKeyboard.ini ; restes WindowsNoEditor\ et CrashReportClient\ des versions UE4) |
SaveGames |
11 M | 22 |
LPDataCache |
7,9 M | 13 |
Logs |
0 | 0 |
Crashes |
4 K | 0 |
Conséquence : seul le Shipping (build de release) est concerné. L'éditeur et les builds Development de test n'utilisent pas ce dossier aujourd'hui.
2. Options pour obtenir LifePlay-Revival sans renommer le projet ni le module
| Option | Moyen | Effort | Risque | Réversibilité | Niveau |
|---|---|---|---|---|---|
A. Macro UE_SAVED_DIR_OVERRIDE |
GlobalDefinitions.Add("UE_SAVED_DIR_OVERRIDE=LifePlay-Revival") dans LifePlay.Target.cs (UE_STRINGIZE garde le tiret : PreprocessorHelpers.h:6-7) |
impossible avec le moteur Launcher. Une définition globale exige BuildEnvironment = Unique, refusé sur moteur installé (RulesAssembly.cs:708-712 ; UEBuildTarget.cs:1508-1516). Même forcée par bOverrideBuildEnvironment, elle ne recompile pas Core : les modules du moteur installé sont précompilés (RulesAssembly.cs:572-573, bUsePrecompiled = bReadOnly), et LifePlay-Win64-Shipping.exe.rsp relie 43 objets Module.Core.* pris dans l'Intermediate du moteur. Il faudrait un moteur 5.8 compilé depuis les sources : très lourd. |
élevé (changement de chaîne de build juste avant la release) | oui (retirer la ligne), mais le moteur source reste à maintenir | établi (refus, liaison) ; estimé (sans effet silencieux avec bOverrideBuildEnvironment) |
B. Lanceur officiel avec -UserDir |
Un lanceur à la racine du paquet (.bat, raccourci ou petit exe) qui lance LifePlay.exe -UserDir="%LOCALAPPDATA%\LifePlay-Revival". Le moteur crée alors …\LifePlay-Revival\Saved\… (Paths.cpp:453-457 puis :86-115) |
faible : un fichier ajouté au paquet par l'étape d'empaquetage, plus README. Méthode déjà prouvée en Shipping par les .bat d'essai (LifePlay_Build_5.8_Shipping_U8r2_essai\Windows\Lancer_U8r2_essai.bat, lp-validate l. 96-100) |
moyen : un joueur qui lance LifePlay.exe directement (habitude, raccourci existant) retombe sur %LOCALAPPDATA%\LifePlay. Les deux dossiers coexistent alors sans erreur, mais avec des sauvegardes séparées |
totale : retirer le lanceur | établi (mécanisme) ; estimé (comportement des joueurs) |
| B+. B + garde dans le jeu | Au démarrage du module LifePlay, en Shipping : si FPaths::CustomUserDirArgument() est vide, relancer l'exe avec -UserDir=… puis sortir aussitôt (RequestExit(true), sans écrire la config) |
moyen : environ 30 lignes C++, une build, un essai en jeu | moyen : à ce moment, le moteur a déjà ouvert un journal et lu la config dans l'ancien dossier (pré-initialisation avant les modules du jeu). Il faut prouver que rien n'y est réécrit. Une double fenêtre ou un écran de démarrage est possible | totale (retirer le code) | estimé (non rejoué) |
C. Renommer le projet (.uproject, ProjectName) pour le seul paquet |
— | élevé | rédhibitoire : UE_PROJECT_NAME et le chemin <Nom>\Content changent (LaunchEngineLoop.cpp:708-713), ce qui casse la structure du paquet, les points de montage et le contrat des mods (figé). Les noms de projet UE n'acceptent pas le tiret (incertain, non vérifié) |
difficile | établi (lien nom ↔ chemins) |
D. Arguments intégrés à LifePlay.exe (bootstrap) |
UAT écrit dans la ressource 202 de l'exe de démarrage les seuls arguments ..\..\..\LifePlay\LifePlay.uproject (E\Source\Programs\AutomationTool\Win\WinPlatform.Automation.cs:167-176, 330-331) |
moyen à élevé : retoucher la ressource après empaquetage | moyen. Surtout, sans développement des variables, il faudrait un chemin absolu propre à chaque poste : inapplicable | oui | établi |
E. Jonction Windows LifePlay → LifePlay-Revival |
— | faible | le dossier LifePlay reste visible : ne répond pas à la demande |
oui | estimé |
3. Effets de bord (option B ou B+)
| Domaine | Effet | Preuve |
|---|---|---|
| Code du jeu et de l'addon | Aucun chemin en dur : tout passe par ProjectSavedDir() et suit le nouveau dossier (jeu : LPColorGradeSubsystem.cpp:27, LPKeyboardSubsystem.cpp:37, LPVideoQualitySubsystem.cpp:71, LPDebugSubsystem.cpp:78, 101, Plugins\LPAnimCore\…\LPAnimRedirect.cpp:10, Plugins\ModdingExtra\…\LPDataCache.cpp:105 ; addon LPSandbox* : 10 fichiers, absent du paquet de release) |
établi (grep) |
| Mods et contrat des mods | Les mods vivent dans Content\Modules du dossier du jeu (ProjectContentDir() : LPModInfoSubsystem.cpp:129, LPDataCache.cpp:102-104). Aucun mod ne lit Saved. LPDataCache est un cache reconstruit à partir des dates et tailles des modules (LPDataCache.cpp:107-125) : il est simplement recréé au premier lancement (plus lent une fois). Le contrat des mods n'est pas touché. Le choix des mods (GI.ModEnableds, README l. 97) est enregistré dans une sauvegarde : il suit SaveGames si l'on reprend ce dossier |
établi (mods, cache) ; estimé (lieu du choix des mods : GameSettings.sav, doc 21 l. 225) |
Sauvegardes dans Content\Saves |
Une partie de la sauvegarde (Player.lpcharacter, doc 21 l. 213) est dans Content\Saves, dans le dossier d'installation. Le renommage ne la touche pas ; le défaut existant (SAV1 / ERR-042) reste ouvert |
établi |
| Éditeur | Non concerné : non « installé », il écrit dans <copie>\Saved. Le lanceur n'est livré qu'avec le paquet |
établi (App.cpp:218-221, Paths.cpp:467-470) |
| Builds Development de test | Non concernés, sauf s'ils sont lancés par le lanceur : -UserDir force alors le dossier utilisateur (Paths.cpp:189) |
établi |
Lanceurs d'essai (Lancer_*_essai.bat) |
Ils passent leur propre -UserDir : inchangés |
établi |
| Outils | Tools\TracesRacines.ps1:90 liste %LOCALAPPDATA%\LifePlay comme racine de traces : ajouter LifePlay-Revival. CollectDebugArtifacts.ps1:18-20, debug\LifePlay_debug_*.bat et .ps1, LogStats.ps1:22 visent le Saved d'un build Development : inchangés. CheckPackage.ps1 : aucune mention de Saved ni d'AppData. Étape d'empaquetage (lp-builder / BuildDebug) : y ajouter le lanceur |
établi (grep) |
| Skills | lp-build l. 71-72 et lp-validate l. 96-100 (copie 5.8 et addon 5.8) citent %LOCALAPPDATA%\LifePlay\Saved : à mettre à jour |
établi (grep) |
| README | l. 82-83 (« saves and settings … %LOCALAPPDATA%\LifePlay\Saved ») et l. 140 : à réécrire (nouveau dossier, lanceur, reprise) |
établi |
| Moteur hors projet | EngineUserDir (%LOCALAPPDATA%\UnrealEngine\5.8) ne dépend pas de -UserDir (Paths.cpp:204-210) : inchangé |
établi |
4. Reprise des anciennes sauvegardes (option seulement, à décider par l'utilisateur)
| Variante | Quoi | Coût | Risque |
|---|---|---|---|
| R0. Rien | Le joueur copie lui-même ; seul le README l'explique | nul | perte apparente des parties (signalements) |
| R1. Copie par le lanceur (B) | Au lancement : si %LOCALAPPDATA%\LifePlay-Revival\Saved\SaveGames est absent et que %LOCALAPPDATA%\LifePlay\Saved\SaveGames existe, copier SaveGames (11 M, 22 fichiers sur ce poste). La copie se fait avant le démarrage du moteur, donc sans conflit de fichiers ouverts. Sans déplacement ni suppression : l'ancien dossier reste une sauvegarde |
faible : quelques lignes dans le lanceur ; essai avec dossier présent, absent, déjà migré | faible ; à essayer avec un profil dont le chemin contient une espace ou des accents |
R1c. + Config\Windows |
GameUserSettings.ini, LPKeyboard.ini, LPColorGrade.ini, LPVideoQuality.ini |
faible | moyen : réglages d'une version antérieure réinjectés (incident U8 : .ini réécrits). À éviter, ou à limiter à LPKeyboard.ini (touches du joueur). WindowsNoEditor\, CrashReportClient\, LPDataCache, Logs, Crashes ne sont jamais à reprendre |
| R2. Copie dans le jeu (C++) | Même règle, faite au démarrage du module LifePlay |
moyen (C++ + build) | moyen : GameUserSettings est déjà lu quand le module démarre, donc une copie de Config arriverait trop tard ; SaveGames seul reste possible si la copie précède la première lecture des sauvegardes par le GI (à prouver) |
5. Recommandation
- B + R1 (SaveGames seul). Un lanceur
LifePlay-Revivalest ajouté au paquet par l'étape d'empaquetage. Il copieSaveGamess'il manque, puis lanceLifePlay.exe -UserDir="%LOCALAPPDATA%\LifePlay-Revival". Le README désigne ce lanceur comme point d'entrée. Rien n'est écrit dansSource\,Config\niContent\: risque faible, faisable avant l'alpha. - B+ seulement si l'utilisateur veut couvrir le lancement direct de
LifePlay.exe. C'est du C++ avec un risque moyen, à n'engager qu'après une preuve en jeu que l'ancien dossier n'est pas réécrit. Sinon, l'écarter jusqu'après l'alpha. - Rejeter A (moteur source), C (renommage du projet) et D.
Questions pour l'utilisateur (posées par Big Boss) : forme du lanceur (.bat avec fenêtre de console brève, raccourci .lnk, ou petit exe) ; reprise R0 / R1 / R1c ; B+ oui ou non. Chantiers suivants si GO : SPEC du lanceur, IMPL dans l'outil d'empaquetage, BUILD Shipping, essai en jeu (dossier absent, présent, déjà migré ; Continuer ; mods), puis DOC (README, TracesRacines.ps1, lp-build, lp-validate, doc 29 l. 37).
6. Proposition de l'utilisateur (2026-10-13) : dossier choisi dans les réglages du jeu, LifePlay-Revival par défaut
Demande : enregistrer le dossier de sauvegarde dans un fichier .ini des réglages du jeu, pour que le joueur puisse le choisir, avec %LOCALAPPDATA%\LifePlay-Revival par défaut.
Faisable, en prolongement de l'option B, sous deux contraintes établies au § 1 :
- Le chemin doit être connu avant le démarrage du moteur.
ProjectSavedDir()est calculé une fois, puis mis en cache (Paths.cpp:485-494), à partir de la seule ligne de commande (Paths.cpp:451-471). Le jeu ne peut donc pas changer de dossier en cours de partie. C'est le lanceur qui lit le.iniet passe-UserDir. Un choix fait dans le menu prend effet au lancement suivant. - Le
.inine peut pas être dansSaved.GameUserSettings.iniest dansSaved\Config\Windows: le lanceur ne le trouverait qu'en connaissant déjà le dossier (référence circulaire). Précision de l'utilisateur (2026-10-13) : le fichier va dans le dossierLifePlaydu jeu installé, avec d'autres réglages, par exemple<installation>\Windows\LifePlay\SaveLocation.ini, cléSaveDir=(nom et place exacts fixés par la SPEC). L'emplacement est fixe par rapport à l'exe : le lanceur et le jeu le trouvent tous deux sans connaîtreSaved(le jeu parFPaths::ProjectDir()). Si le fichier ou la clé manque, le lanceur prend%LOCALAPPDATA%\LifePlay-Revival. Le paquet V2.0 n'a aujourd'hui aucun fichier de réglages dans ce dossier (Binaries,Content\Modules,Movies,Paksseulement). Les fichiers de réglages existants (LPKeyboard.ini,LPVideoQuality.ini,LPColorGrade.ini,GameUserSettings.ini) ne peuvent pas recevoir cette clé. Ils sont écrits dansProjectSavedDir()\Config\Windows, donc dans le dossier de sauvegarde lui-même (§ 3). En Development, ce dossier se trouve sous<build>\Windows\LifePlay\Saved\Config\Windows(relevé :LifePlay_Build_5.8_STE-J6_Development). En Shipping, il se trouve sous%LOCALAPPDATA%\LifePlay\Saved\Config\Windows(relevé sur ce poste), et il suivra le dossier choisi. On retient donc un fichier séparé au même format,LPSaveLocation.ini, placé hors deSaved. Conséquences de cet emplacement :- Une nouvelle installation, par exemple une nouvelle version décompressée ailleurs, repart sans ce fichier, donc au dossier par défaut. Les parties ne sont pas perdues : elles restent dans le dossier choisi, qu'il faudra choisir de nouveau, ou recopier le
.ini(à écrire au README). - Droits d'écriture : hors périmètre (utilisateur, 2026-10-13). Le jeu n'a pas d'installateur : on le décompresse où l'on veut, et les permissions sont à la charge du joueur. Aucun repli spécial n'est prévu. Seule une écriture refusée est signalée au journal, sans plantage (garde minimale de la SPEC).
- L'emplacement est cohérent avec
Content\Saves, déjà dans le dossier d'installation (§ 3).
- Une nouvelle installation, par exemple une nouvelle version décompressée ailleurs, repart sans ce fichier, donc au dossier par défaut. Les parties ne sont pas perdues : elles restent dans le dossier choisi, qu'il faudra choisir de nouveau, ou recopier le
Détails :
- Le moteur ajoute
Saved\au dossier choisi (Paths.cpp:86-115). Si le joueur choisitD:\MesParties, il obtientD:\MesParties\Saved\SaveGames. Cela convient, à condition de l'indiquer dans le menu. - Le lanceur vérifie que le dossier est accessible en écriture. Sinon, il revient au dossier par défaut.
- Au changement de dossier, il faut décider : copier les sauvegardes existantes vers le nouveau dossier (même règle que R1), ou partir d'un dossier vide.
| Volet | Effort | Risque | Touche |
|---|---|---|---|
Lanceur qui lit SaveLocation.ini (B + R1, plus une lecture de clé) |
faible | faible | outil d'empaquetage seulement |
Option dans le menu des réglages (choix du dossier, écriture du .ini, message « effectif au prochain lancement ») |
moyen à élevé : widget Blueprint (Content, par MCP) et fonction C++ d'écriture et de sélecteur de dossier |
moyen | Source\, Content\ (GO de Big Boss) |
Proposition de phasage :
- Avant l'alpha : le lanceur avec
SaveLocation.ini. Le joueur peut déjà changer le dossier en modifiant le fichier (README). - Ensuite : l'option dans le menu des réglages, comme lot distinct (SPEC, IMPL, BUILD, essai en jeu).
7. Ligne « dossier de sauvegarde » dans les réglages du jeu (demande de l'utilisateur, 2026-10-13 : onglet Misc ou General)
Faisable en C++ seul, sans modifier de Blueprint ni rien dans Content\, sur le modèle d'un précédent du projet (établi, lecture du code) :
LPSettingsSubsystem.cpp:35-45: les six ongletsGeneral,Audio,Video,Keyboard,Lewd,Misc.CategoryOf(l. 145-207) range chaque ligne d'après le nom de son widget, puis d'après son libellé.LPModInfoSubsystem.cpp:42-46, 240-313: le lot U7 ajoute déjà en C++ trois lignes àSettingsScrollBox, avec des libellés suffixés « (restart) » et l'infobulle « Takes effect at next launch ». Les widgets nommésLPModCheck*sont envoyés dansMisc(LPSettingsSubsystem.cpp:178-181).
Proposition (pour la SPEC) :
- Un sous-système, ou une extension de
LPSettingsSubsystem, ajoute une ligne nomméeLPSaveDir…, rangée dans Misc : c'est l'onglet qui porte déjà les réglages « (restart) ». General reste possible en une ligne deCategoryOf, au choix de l'utilisateur. - Contenu de la ligne :
- libellé « Save folder (restart) » et chemin actuel (
FPaths::ProjectUserDir()) ; - bouton « Browse… » ;
- bouton « Default » (
%LOCALAPPDATA%\LifePlay-Revival) ; - infobulle : « Takes effect at next launch. Existing saves are copied if the new folder has none » (selon la décision R0 / R1).
- libellé « Save folder (restart) » et chemin actuel (
- Écriture de
ProjectDir()\LPSaveLocation.ini, cléSaveDir=. En cas d'échec, une ligne au journal (décision U3). - Sélecteur de dossier :
- le module
DesktopPlatformsert à l'éditeur et n'est pas livré en Shipping (estimé) ; - il faudrait donc le dialogue natif Windows (
IFileOpenDialog,FOS_PICKFOLDERS, sous#if PLATFORM_WINDOWS), estimé à une soixantaine de lignes ; - repli plus simple : un champ texte où l'on colle le chemin, plus le bouton « Default ».
- le module
Dans tous les cas, cette ligne ne fait qu'écrire le choix. Pour qu'il soit appliqué au lancement suivant, il faut encore :
- soit le lanceur (B), qui lit
LPSaveLocation.iniet passe-UserDir; - soit la garde B+ : au démarrage, le jeu lit
LPSaveLocation.iniet, si-UserDirest absent ou différent, se relance avec le bon-UserDir, puis se ferme. Avec un réglage dans le jeu, B+ dispense du lanceur et couvre le double-clic surLifePlay.exe, mais il reste à prouver en jeu que l'ancien dossier n'est pas réécrit (§ 2).
Effort : moyen. Le C++ se trouve dans Source\LifePlay seulement ; il faut une compilation, un paquet Shipping et un essai en jeu (choisir, relancer, Continuer, revenir au dossier par défaut). Risque : moyen. GO de Big Boss requis.
Fichiers à commiter
Docs/Migration/etat/REL/SAV/REL-SAV-DIAG.md, Docs/Migration/etat/REL/SAV/REL-SAV-TACHES.md, Docs/Migration/etat/REL/SAV/fiches/REL-SAV-T1.md (ticket au gardien par Big Boss).
Tours : ≈ 30 — aucune écriture hors etat\REL\SAV\ — aucun jeton UE pris.