161 lines
10 KiB
PowerShell
161 lines
10 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.', '')
|
|
# 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 ($p in $packages) {
|
|
$one = Join-Path $stage "_zip\$($p.Name)"
|
|
New-Item -ItemType Directory -Force (Join-Path $one 'LifePlay\Content\Modules') | Out-Null
|
|
$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\<module>' }
|
|
$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(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 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 "$($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
|
|
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
|
|
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}, {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) 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
|
|
}
|
|
|
|
$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' }
|