From 1fc32f55d6d33b2a433ef53df0a4570ba2201427 Mon Sep 17 00:00:00 2001 From: edujiro5972 <336072401+edujiro5972@users.noreply.github.com> Date: Sat, 3 Oct 2026 11:19:44 +0200 Subject: [PATCH] V1.5 (LifePlay 2026.10.1.5) : version annee.mois.majeur.mineur, modules vin_* en un seul paquet, README Co-Authored-By: Claude Opus 5.5 --- Config/DefaultGame.ini | 2 +- Docs/Migration/14_Interface_V1.4.md | 7 +++- Docs/Migration/15_Modules_Optionnels.md | 7 ++++ Docs/Migration/Journal_Modifications.md | 1 + README.md | 25 ++++++++++++- Source/LifePlay/LPVersionSubsystem.h | 2 +- Tools/BuildMod.ps1 | 9 +++++ Tools/SplitModules.ps1 | 50 +++++++++++++++++-------- Tools/modules/next.json | 14 +++++-- 9 files changed, 93 insertions(+), 24 deletions(-) diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index e5e2712..64f8ac2 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -1,7 +1,7 @@ [/Script/EngineSettings.GeneralProjectSettings] ProjectID=543F4F9E4DE525696C82F5A52303C15C ProjectName=LifePlay -ProjectVersion=2026.10.4 +ProjectVersion=2026.10.1.5 Description=Portage UE 5.5 - assets integres depuis LifePlay 5.9 Full Source [/Script/MoviePlayer.MoviePlayerSettings] diff --git a/Docs/Migration/14_Interface_V1.4.md b/Docs/Migration/14_Interface_V1.4.md index 9964bd2..602f1cd 100644 --- a/Docs/Migration/14_Interface_V1.4.md +++ b/Docs/Migration/14_Interface_V1.4.md @@ -22,8 +22,11 @@ Vinfamy comme auteur original, lien Donate vers le Patreon de LifePlay Revival, - **Version** : format du menu ramené à `LifePlay {text}` ; nouveau sous-système `Source/LifePlay/LPVersionSubsystem` qui remplit `GI.version_text` au démarrage avec `ProjectVersion` de `Config/DefaultGame.ini` (`[/Script/EngineSettings.GeneralProjectSettings]`). Format : **année.mois.publication**, le dernier nombre étant un - compteur de publications (V1.4 = 4) : `ProjectVersion=2026.10.4`. **À chaque publication**, mettre à jour cette ligne - (année et mois de la publication, compteur + 1). + compteur de publications (V1.4 = 4) : `ProjectVersion=2026.10.4`. **Depuis la V1.5 (décision du 2026-10-03)** : + **année.mois.majeur.mineur**, majeur et mineur étant ceux du numéro de version publié (V1.5 = `2026.10.1.5`, + V1.6 = `2026..1.6`, V2.0 = `2026..2.0`) ; la V1.4 publiée reste `2026.10.4`. Le jeu et les outils traitent + la version comme un texte (affichage, `Releases/`, noms d'archives, comparaison exacte de + `MODULE_GAME_VERSION`) : aucun ne la compare numériquement. **À chaque publication**, mettre à jour cette ligne. - **Menu** : nouvelle commandlet `LPEditWidget` (`Source/LifePlayEditorTools`), pilotée par une spécification versionnée `Tools/ui/MainMenu_V1.4.json` ; chaque modification indique la valeur attendue avant (sinon rien n'est écrit), le widget est compilé sans erreur puis sauvegardé. Modifications : format de version, URL Donate diff --git a/Docs/Migration/15_Modules_Optionnels.md b/Docs/Migration/15_Modules_Optionnels.md index 8401127..380d34c 100644 --- a/Docs/Migration/15_Modules_Optionnels.md +++ b/Docs/Migration/15_Modules_Optionnels.md @@ -57,3 +57,10 @@ gestionnaire de mods, où ils s'activent ou se désactivent. Pour en retirer un partie texte serait livrée sans ses paquets ; utiliser un build neuf. Essai sur une copie des modules du build H3d : 15 archives, 640 fichiers déplacés = 640 archivés, aucun reste ; refus vérifié avec un mod d'assets installé (copies d'essai dans `LifePlay_Backup_5.5\PUB_next`). +- **Rectification du 2026-10-03** : les modules `vin_*` optionnels (jeu d'origine de Vinfamy) forment **un seul zip**, + le paquet de base du jeu (`vin_Modules-for-LifePlay-.zip`, 14 modules, notice listant chaque module et ses + prérequis) ; `vin_Base` et `vin_VanillaRealistic` restent dans le build. Les autres mods (ex. `lpr_hair_pocolov`) ont + chacun leur zip. Configuration : `"groups"` dans `Tools/modules/next.json` (`name`, `pattern`, `title`, + `description`) ; un module non couvert par un groupe a son propre zip. V1.5 : `vin_Modules` (875 911 octets, 626 + fichiers) et `lpr_hair_pocolov-1.0` ; le premier découpage (un zip par module `vin_*`) est rangé dans + `LifePlay_Backup_5.5\PUB_V15\decoupage_un_zip_par_module`. diff --git a/Docs/Migration/Journal_Modifications.md b/Docs/Migration/Journal_Modifications.md index 83c0f4a..ed57858 100644 --- a/Docs/Migration/Journal_Modifications.md +++ b/Docs/Migration/Journal_Modifications.md @@ -955,3 +955,4 @@ Validation L7c/L7d (2026-10-02, parc, même cadrage) : la nuit reste claire (sol | CHG-108 | 2026-10-03 | H3c | `Docs/Modding/FullGuides/Creating_Asset_Mods.md` §5 | essai utilisateur de `Tools/EditMod.ps1` : mod monté et chargé (« Mounting Mod plugin lpr_hair_pocolov »), 12 coiffures visibles une fois « Afficher le contenu des plugins » coché dans le navigateur de contenu (masqué par défaut ; la recherche porte sur les noms d'assets) : précision ajoutée au guide. **H3c validé le 2026-10-03** | `git revert` du commit | | CHG-109 | 2026-10-03 | PUB | `Tools/SplitModules.ps1` (mode `per_module` : une archive par module, notice tirée du `.lpmod`, `INDEX.txt` ; refus d'un build contenant un mod d'assets installé) ; `Tools/modules/next.json` ; `Docs/Migration/15_Modules_Optionnels.md` §5, `09_Commandes_Utiles.md` §7 | décision utilisateur pour la prochaine publication : chaque mod livré dans un zip indépendant, sauf les modules de base (texte) gardés dans le build Shipping ; diffusion des modules sur Discord dans un premier temps. Essai sur une copie (15 archives, 640 fichiers, garde-fou vérifié) | `git revert` du commit | | CHG-110 | 2026-10-03 | H3c | sources texte de `ModSources/lpr_hair_pocolov` (`.uplugin`, `.lpmod`, 12 `.lphair`, `CREDITS.txt`) | incident : le commit `54f6604` (tag `H3c-valide`) a été fait pendant que le mod était monté dans `Mods/` par `EditMod.ps1` (éditeur ouvert) ; `git add -A` a enregistré la suppression de ses sources. Aucune perte sur disque (mod remis dans `ModSources/` à la fermeture de l'éditeur, 70 assets présents) ; sources réenregistrées par `bf9bb58`. Règle ajoutée (10_Protocole_Operations.md §6) : ne jamais commiter ni lancer un build tant que `Mods/` n'est pas vide. Le tag `H3c-valide` reste sur `54f6604` (déplacement non fait sans accord) | — | +| CHG-111 | 2026-10-03 | V1.5 | `Config/DefaultGame.ini` (`ProjectVersion=2026.10.1.5`), format de version (`14_Interface_V1.4.md`, `LPVersionSubsystem.h`), `README.md` (section V1.5, branche), `Tools/modules/next.json` (groupe `vin_*`), `Tools/SplitModules.ps1` (groupes), `Tools/BuildMod.ps1` (`INDEX.txt`), `15_Modules_Optionnels.md` ; build `LifePlay_Build_5.5_Shipping_V1.5` (version de référence `Releases/2026.10.1.5`, paquets identiques ; 2 modules de base) ; `Releases/2026.10.4` déplacé vers `LifePlay_Backup_5.5\Releases` ; modules `D:\Game\LifePlay_Publication\Modules_2026.10.1.5` (`vin_Modules`, `lpr_hair_pocolov-1.0`, `INDEX.txt`) | publication V1.5 (décisions utilisateur : version `année.mois.majeur.mineur` ; modules `vin_*` en un seul zip, autres mods chacun le leur ; diffusion des modules sur Discord, rien sur GitHub). Validé en jeu le 2026-10-03 ; les mods extraits dans le build pour le test et les fichiers de session ont été déplacés vers `LifePlay_Build_5.5_Shipping_V1.5_test_extraction` (build contrôlé contre le manifeste UAT : 0 fichier en trop, 1 459 fichiers) | `git revert` des commits V1.5 | diff --git a/README.md b/README.md index 9c3a59a..60b25f6 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ play, download the full source archive. - Same layout as the original author's full source archives: the project folder at the archive root, 7z LZMA2. - Contains the complete `Content` folder (including `Content/Heavy` converted to UE5 format), the compiled editor modules in `Binaries` (the project opens without compiling), the `StreetMap` and `ModdingExtra` plugins, and a - `.git` folder matching this repository. + `.git` folder matching this repository. From V1.5: the mod sources (`ModSources/`, with their assets) and the + reference version `Releases/` needed to cook asset mods. - Not included: `Saved`, `Intermediate` (regenerated on first build), local development tools. Check the file after downloading (PowerShell): @@ -31,6 +32,27 @@ Check the file after downloading (PowerShell): Get-FileHash .\LifePlay_Revival_V1.4_UE5.5_Full_Source_Code.7z -Algorithm SHA256 ``` +## Status: V1.5 (tag `v1.5`, 2026-10-03) — LifePlay 2026.10.1.5 + +Mods can now bring their own 3D assets, and the Mod Manager is available from the title screen. Verified in game. + +- **Version number.** New format `year.month.major.minor`: V1.5 is `LifePlay 2026.10.1.5` (V1.4 stays `2026.10.4`). +- **Asset mods.** A mod can ship cooked 3D assets (meshes, textures, materials) in `LifePlay/Mods//` next to its + text module in `LifePlay/Content/Modules//`, without rebuilding the game. Mods are cooked against the + **reference version** of the release (`Releases/2026.10.1.5`, included in the full source archive). Tools: + `Tools/NewMod.ps1`, `Tools/EditMod.ps1`, `Tools/HairPipeline.ps1`, `Tools/BuildMod.ps1`. Guide (English): + [`Docs/Modding/FullGuides/Creating_Asset_Mods.md`](Docs/Modding/FullGuides/Creating_Asset_Mods.md). +- **Mod Manager on the title screen.** Choose your mods before starting or loading a game; the choice is saved. A mod + that the game does not know yet starts disabled (as in the original game), unless its `.lpmod` declares + `MODULE_DEFAULT_ENABLED: true`. +- **Mod metadata and version warning.** New optional `.lpmod` keys (version, dates, license, author link, price, game + version), shown in the Mod Manager; the game warns when an enabled mod was built for another game version. +- **Pocolov hairstyles as a mod.** The Pocolov hairstyles left the base game: they are now the asset mod + `lpr_hair_pocolov` (12 hairstyles, CC BY 4.0; sources in `ModSources/lpr_hair_pocolov`, credits in its + `CREDITS.txt`). +- **Game build.** The packaged game only contains the base modules `vin_Base` and `vin_VanillaRealistic`. The source + archive and this repository keep all modules. + ## Status: V1.4 (tag `v1.4`, 2026-10-02) — LifePlay 2026.10.4 Moddable hairstyles, first new content, and a lighter game build. Verified in game. @@ -128,6 +150,7 @@ Changes since V1, each validated in game against UE 4.27 on an identical play pa | Branch | Contents | |---|---| | `main` | **reference**: the latest validated UE 5.5 version, base for further development | +| `ue5.5-v1.5` | the V1.5 as validated | | `ue5.5-v1.4` | the V1.4 as validated | | `ue5.5-v1.3` | the V1.3 as validated | | `ue5.5-v1.2` | the V1.2 as validated | diff --git a/Source/LifePlay/LPVersionSubsystem.h b/Source/LifePlay/LPVersionSubsystem.h index 8e918f3..e3c7149 100644 --- a/Source/LifePlay/LPVersionSubsystem.h +++ b/Source/LifePlay/LPVersionSubsystem.h @@ -2,7 +2,7 @@ // // Le menu principal affiche "LifePlay {text}" (UI/MainMenu, Get_Version_Text_0) avec text = GI.version_text. Ce // sous-systeme remplit GI.version_text au demarrage avec la version du projet (Config/DefaultGame.ini, -// [/Script/EngineSettings.GeneralProjectSettings] ProjectVersion, format annee.mois.publication : 2026.10.4). +// [/Script/EngineSettings.GeneralProjectSettings] ProjectVersion, format annee.mois.majeur.mineur depuis la V1.5 : 2026.10.1.5 ; V1.4 = 2026.10.4). // GI.version_main et GI.version_sub (5 et 9, utilises par les sauvegardes et ReturnStatIfNeeded) ne sont pas modifies. #pragma once diff --git a/Tools/BuildMod.ps1 b/Tools/BuildMod.ps1 index 7981f5b..e28e237 100644 --- a/Tools/BuildMod.ps1 +++ b/Tools/BuildMod.ps1 @@ -149,6 +149,15 @@ if ($staged -ne $listed) { throw "Archive : $listed fichier(s) pour $staged asse $hash = (Get-FileHash $zip -Algorithm SHA256).Hash Write-Host ("Archive : {0} ({1:N0} octets, {2} fichiers, SHA-256 {3})" -f $zip, (Get-Item $zip).Length, $listed, $hash) +# Index de diffusion (Tools/SplitModules.ps1, mode per_module) : ligne du mod ajoutee ou remplacee. +$index = Join-Path $Out 'INDEX.txt' +if (Test-Path $index) { + $entry = '{0} ({1}) : {2}, {3:N0} bytes, SHA-256 {4}' -f $title, $Name, (Split-Path $zip -Leaf), (Get-Item $zip).Length, $hash.ToLower() + $kept = @(Get-Content $index -Encoding utf8 | Where-Object { $_ -notlike "* ($Name) : *" }) + [IO.File]::WriteAllText($index, (($kept + $entry) -join "`r`n") + "`r`n", (New-Object Text.UTF8Encoding $false)) + Write-Host "Index mis a jour : $index" +} + # 5. Installation dans un jeu de test. if ($Install) { if (-not (Test-Path (Join-Path $Install 'LifePlay.exe'))) { throw "$Install ne contient pas LifePlay.exe" } diff --git a/Tools/SplitModules.ps1 b/Tools/SplitModules.ps1 index 54c85bd..1a381b8 100644 --- a/Tools/SplitModules.ps1 +++ b/Tools/SplitModules.ps1 @@ -68,23 +68,42 @@ if ($cfg.per_module) { 'Install: extract the zip into the game folder (the one containing LifePlay.exe), merging the LifePlay folder, then enable', 'the module in "Mod Manager" (title screen). Installation : extraire le zip dans le dossier du jeu, puis activer le module.', 'Adult content, adults only / contenu adulte, reserve aux adultes.', '') + # Paquets : un groupe de la configuration ("groups" : name, pattern, title, description) reunit ses modules dans une + # seule archive (ex. vin_* = modules de base du jeu, decision du 2026-10-03) ; chaque autre module a la sienne. + $packages = @() + $grouped = @() + foreach ($g in @($cfg.groups)) { + if (-not $g) { continue } + $members = @($optional | Where-Object { $_.Name -like $g.pattern } | Sort-Object Name) + if ($members) { $packages += [pscustomobject]@{ Name = $g.name; Title = $g.title; Description = $g.description; Members = $members }; $grouped += $members.Name } + } + foreach ($m in ($optional | Where-Object { $_.Name -notin $grouped } | Sort-Object Name)) { + $packages += [pscustomobject]@{ Name = $m.Name; Title = ''; Description = ''; Members = @($m) } + } $zipped = 0 - foreach ($m in ($optional | Sort-Object Name)) { - $src = Join-Path $target $m.Name - $lp = Get-Content (Join-Path $src "$($m.Name).lpmod") -Encoding utf8 - $val = { param($k) $l = $lp | Where-Object { $_ -match "^$k\s*:" } | Select-Object -First 1; if ($l) { ($l -split ':', 2)[1].Trim() } else { '' } } - $title = & $val 'MODULE_NAME'; $desc = & $val 'MODULE_DESCRIPTION'; $req = & $val 'MODULE_REQUIREMENTS' - $one = Join-Path $stage "_zip\$($m.Name)" + foreach ($p in $packages) { + $one = Join-Path $stage "_zip\$($p.Name)" New-Item -ItemType Directory -Force (Join-Path $one 'LifePlay\Content\Modules') | Out-Null - Copy-Item $src (Join-Path $one "LifePlay\Content\Modules\$($m.Name)") -Recurse - $note = @("$title ($($m.Name)) - LifePlay Revival $($cfg.version)", '', $desc, $(if ($req) { "Requires / necessite : $req" } else { '' }), '', + $lines = @(); $expected = 0 + foreach ($m in $p.Members) { + $src = Join-Path $target $m.Name + $lp = Get-Content (Join-Path $src "$($m.Name).lpmod") -Encoding utf8 + $val = { param($k) $l = $lp | Where-Object { $_ -match "^$k\s*:" } | Select-Object -First 1; if ($l) { ($l -split ':', 2)[1].Trim() } else { '' } } + $title = & $val 'MODULE_NAME'; $desc = & $val 'MODULE_DESCRIPTION'; $req = & $val 'MODULE_REQUIREMENTS' + Copy-Item $src (Join-Path $one "LifePlay\Content\Modules\$($m.Name)") -Recurse + $expected += @(Get-ChildItem $src -Recurse -File).Count + $lines += "- $title ($($m.Name))$(if ($req) { ", requires / necessite : $req" })" + if ($p.Members.Count -eq 1) { $p.Title = $title; $p.Description = $desc } + } + $modulesDir = if ($p.Members.Count -eq 1) { "LifePlay\Content\Modules\$($p.Members[0].Name)" } else { 'LifePlay\Content\Modules\' } + $note = @("$($p.Title) - LifePlay Revival $($cfg.version)", '', $p.Description, '') + $lines + @('', 'EN: extract this archive into the game folder (the one containing LifePlay.exe), merging the LifePlay folder, then', - "enable the module in `"Mod Manager`" (title screen). To remove it, delete LifePlay\Content\Modules\$($m.Name).", + "enable the module(s) in `"Mod Manager`" (title screen). To remove one, delete its folder $modulesDir.", 'FR : extraire cette archive dans le dossier du jeu (celui de LifePlay.exe) en fusionnant le dossier LifePlay, puis', - "activer le module dans `"Mod Manager`" (ecran titre). Pour le retirer : supprimer LifePlay\Content\Modules\$($m.Name).", + "activer le ou les modules dans `"Mod Manager`" (ecran titre). Pour en retirer un : supprimer $modulesDir.", 'Adult content, adults only / contenu adulte, reserve aux adultes.') [IO.File]::WriteAllText((Join-Path $one 'README.txt'), ($note -join "`r`n") + "`r`n", (New-Object Text.UTF8Encoding $false)) - $zip = Join-Path $dir "$($m.Name)-for-LifePlay-$($cfg.version).zip" + $zip = Join-Path $dir "$($p.Name)-for-LifePlay-$($cfg.version).zip" if (Test-Path $zip) { throw "L'archive existe deja : $zip" } Push-Location $one & $SevenZip a -tzip -mx=7 $zip 'LifePlay' 'README.txt' | Out-Null @@ -92,17 +111,16 @@ if ($cfg.per_module) { & $SevenZip t $zip | Out-Null if ($LASTEXITCODE -ne 0) { throw "Test 7-Zip en echec : $zip" } $n = (& $SevenZip l -slt $zip | Select-String '^Folder = -').Count - 1 - $expected = @(Get-ChildItem $src -Recurse -File).Count - if ($n -ne $expected) { throw "$($m.Name) : $n fichier(s) dans l'archive pour $expected" } + if ($n -ne $expected) { throw "$($p.Name) : $n fichier(s) dans l'archive pour $expected" } $zipped += $n $h = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLower() - $index += ('{0} ({1}) : {2}, {3:N0} bytes, SHA-256 {4}' -f $title, $m.Name, (Split-Path $zip -Leaf), (Get-Item $zip).Length, $h) - Write-Host " $($m.Name) : $(Split-Path $zip -Leaf) ($n fichiers)" + $index += ('{0} ({1}{2}) : {3}, {4:N0} bytes, SHA-256 {5}' -f $p.Title, $p.Name, $(if ($p.Members.Count -gt 1) { ': ' + ($p.Members.Name -join ', ') } else { '' }), (Split-Path $zip -Leaf), (Get-Item $zip).Length, $h) + Write-Host " $($p.Name) : $(Split-Path $zip -Leaf) ($($p.Members.Count) module(s), $n fichiers)" } [IO.File]::WriteAllText((Join-Path $dir 'INDEX.txt'), ($index -join "`r`n") + "`r`n", (New-Object Text.UTF8Encoding $false)) $left = Get-ChildItem $modules -Directory | Where-Object { $_.Name -in $optional.Name } Write-Host "Modules gardes dans le build : $($cfg.essential -join ', ')" - Write-Host "Modules optionnels : $($optional.Count) archive(s) dans $dir ; fichiers deplaces $files, archives $zipped ; restes dans le build $(@($left).Count)" + Write-Host "Modules optionnels : $($optional.Count) en $($packages.Count) archive(s) dans $dir ; fichiers deplaces $files, archives $zipped ; restes dans le build $(@($left).Count)" if ($zipped -ne $files -or @($left).Count -ne 0) { throw 'Controle en echec : contenu des archives different des fichiers deplaces' } return } diff --git a/Tools/modules/next.json b/Tools/modules/next.json index 5e51ca9..6e59586 100644 --- a/Tools/modules/next.json +++ b/Tools/modules/next.json @@ -1,5 +1,13 @@ { - "version": "next", + "version": "2026.10.1.5", "essential": ["vin_Base", "vin_VanillaRealistic"], - "per_module": true -} + "per_module": true, + "groups": [ + { + "name": "vin_Modules", + "pattern": "vin_*", + "title": "LifePlay base game modules (vin_*, by Vinfamy)", + "description": "The optional modules of the original game by Vinfamy, in one package. Enable the ones you want in the Mod Manager (vin_NTR is disabled by default)." + } + ] +} \ No newline at end of file