LifePlay-Revival/Tools/SplitModules.ps1
2026-10-03 10:43:53 +02:00

143 lines
9.2 KiB
PowerShell

<#
.SYNOPSIS
Separe les modules optionnels d'un build empaquete (Docs/Migration/15_Modules_Optionnels.md).
.DESCRIPTION
Les modules de Content/Modules sont livres en fichiers nus a cote du jeu. Ce script garde dans le build les modules
listes comme essentiels dans le fichier de configuration (Tools/modules/<version>.json) et deplace tous les autres
dans une archive zip, avec l'arborescence LifePlay\Content\Modules\<module>\..., a extraire dans le dossier du jeu
(celui de LifePlay.exe). Une notice LISEZMOI / README est ajoutee a l'archive.
Le jeu gere l'absence d'un module : au demarrage, GI.removeDeletedMods retire de GI.ModEnableds tout module dont le
fichier .lpmod est absent, et GI.IsModEnabled repond alors faux.
Controles : chaque module essentiel doit exister ; nombre de fichiers et d'octets deplaces = contenu de l'archive
(7-Zip, test d'integrite) ; aucun fichier de module optionnel ne reste dans le build. Les fichiers deplaces sont
conserves dans <build>\..\<nom>_modules_optionnels (rien n'est supprime).
.PARAMETER (configuration "per_module": true, depuis la publication qui suit la V1.4)
Une archive par module optionnel, <module>-for-LifePlay-<version>.zip (LifePlay\Content\Modules\<module> + notice
bilingue tiree du .lpmod), dans <Out>\<out_dir> ; un index INDEX.txt (nom, archive, taille, SHA-256) sert au message
de diffusion (Discord). Les mods d'assets (Tools/BuildMod.ps1) se deposent dans le meme dossier.
.EXAMPLE
.\Tools\SplitModules.ps1 -Build D:\Game\LifePlay_Build_5.5_Shipping_V1.5 -Config Tools\modules
ext.json -Out D:\Game\LifePlay_Publication
.EXAMPLE
.\Tools\SplitModules.ps1 -Build D:\Game\LifePlay_Build_5.5_Shipping_V1.4 -Config Tools\modules\V1.4.json -Out D:\Game\LifePlay_Publication
#>
param(
[Parameter(Mandatory)] [string] $Build,
[Parameter(Mandatory)] [string] $Config,
[Parameter(Mandatory)] [string] $Out
)
$ErrorActionPreference = 'Stop'
$SevenZip = 'C:\Program Files\7-Zip\7z.exe'
$cfg = Get-Content $Config -Raw | ConvertFrom-Json
$modules = Join-Path $Build 'Windows\LifePlay\Content\Modules'
if (-not (Test-Path $modules)) { throw "Dossier des modules introuvable : $modules" }
# Un build de distribution ne contient aucun mod d'assets installe (sa partie texte serait livree sans ses paquets) :
# ces mods sont livres par Tools/BuildMod.ps1.
$assetMods = @(Get-ChildItem (Join-Path $Build 'Windows\LifePlay\Mods') -Directory -ErrorAction SilentlyContinue | ForEach-Object Name)
if ($assetMods) { throw "Mod(s) d'assets installe(s) dans le build ($($assetMods -join ', ')) : utiliser un build neuf, ces mods sont livres par BuildMod.ps1" }
foreach ($m in $cfg.essential) {
if (-not (Test-Path (Join-Path $modules "$m\$m.lpmod"))) { throw "Module essentiel absent du build : $m" }
}
$optional = Get-ChildItem $modules -Directory | Where-Object { (Test-Path (Join-Path $_.FullName "$($_.Name).lpmod")) -and $_.Name -notin $cfg.essential }
if (-not $optional) { Write-Host 'Aucun module optionnel dans le build.'; return }
# Arborescence de l'archive : LifePlay\Content\Modules\<module>
$stage = Join-Path (Split-Path $Build -Parent) ((Split-Path $Build -Leaf) + '_modules_optionnels')
$target = Join-Path $stage 'LifePlay\Content\Modules'
New-Item -ItemType Directory -Force $target | Out-Null
$files = 0; $bytes = 0
foreach ($m in $optional) {
$items = Get-ChildItem $m.FullName -Recurse -File
$files += $items.Count; $bytes += ($items | Measure-Object Length -Sum).Sum
Move-Item $m.FullName (Join-Path $target $m.Name)
}
$list = ($optional.Name | Sort-Object) -join ', '
if ($cfg.per_module) {
# Une archive par module (publication suivant la V1.4).
$dir = Join-Path $Out $(if ($cfg.out_dir) { $cfg.out_dir } else { "Modules_$($cfg.version)" })
New-Item -ItemType Directory -Force $dir | Out-Null
$index = @("LifePlay Revival $($cfg.version) - optional modules / modules optionnels", '',
'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.', '')
$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)"
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 { '' }), '',
'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).",
'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).",
'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"
if (Test-Path $zip) { throw "L'archive existe deja : $zip" }
Push-Location $one
& $SevenZip a -tzip -mx=7 $zip 'LifePlay' 'README.txt' | Out-Null
Pop-Location
& $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" }
$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)"
}
[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)"
if ($zipped -ne $files -or @($left).Count -ne 0) { throw 'Controle en echec : contenu des archives different des fichiers deplaces' }
return
}
$readme = @"
LifePlay Revival $($cfg.version) - modules optionnels / optional modules
FR : extraire cette archive dans le dossier du jeu (celui qui contient LifePlay.exe), en fusionnant le dossier
LifePlay. Les modules apparaissent ensuite dans le gestionnaire de mods du jeu, ou ils s'activent et se desactivent.
vin_NTR est desactive par defaut. Pour retirer un module : supprimer son dossier LifePlay\Content\Modules\<module>.
EN: extract this archive into the game folder (the one containing LifePlay.exe), merging the LifePlay folder. The
modules then appear in the in-game mod manager, where they can be enabled or disabled. vin_NTR is disabled by
default. To remove a module, delete its LifePlay\Content\Modules\<module> folder.
Modules : $list
Contenu adulte, reserve aux adultes / adult content, adults only.
"@
Set-Content (Join-Path $stage 'LISEZMOI_README.txt') $readme -Encoding utf8
New-Item -ItemType Directory -Force $Out | Out-Null
$zip = Join-Path $Out $cfg.zip
if (Test-Path $zip) { throw "L'archive existe deja : $zip" }
Push-Location $stage
& $SevenZip a -tzip -mx=7 $zip 'LifePlay' 'LISEZMOI_README.txt' | Out-Null
Pop-Location
& $SevenZip t $zip | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Test 7-Zip en echec : $zip" }
$zipFiles = (& $SevenZip l -slt $zip | Select-String '^Folder = -').Count - 1 # moins la notice
$left = Get-ChildItem $modules -Directory | Where-Object { $_.Name -in $optional.Name }
$hash = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLower()
Write-Host "Modules gardes dans le build : $($cfg.essential -join ', ')"
Write-Host "Modules optionnels : $($optional.Count) ($list)"
Write-Host "Fichiers deplaces : $files ($bytes octets) ; dans l'archive : $zipFiles fichier(s) de module"
Write-Host "Restes dans le build : $(@($left).Count)"
Write-Host "Archive : $zip ($((Get-Item $zip).Length) octets), SHA-256 $hash"
if ($zipFiles -ne $files -or @($left).Count -ne 0) { throw 'Controle en echec : contenu de l''archive different des fichiers deplaces' }