diff --git a/scripts/Build-Tweaks.ps1 b/scripts/Build-Tweaks.ps1 index 763b1a8..e1833a9 100644 --- a/scripts/Build-Tweaks.ps1 +++ b/scripts/Build-Tweaks.ps1 @@ -122,8 +122,44 @@ foreach ($dir in $tweakDirs) { } } finally { $zip.Dispose() } + # ── Post-build validation ──────────────────────────────────────────────── + # Catch structural problems BEFORE the jar gets bundled into the manifest + # and shipped to clients. NeoForge silently rejects invalid jars with a + # bland "not a valid mod file" warning that's easy to miss in a 500-line + # game log; this fails the build loudly with a specific reason instead. + $verify = [System.IO.Compression.ZipFile]::OpenRead($jarPath) + try { + $names = @($verify.Entries | ForEach-Object { $_.FullName }) + + # 1. No backslashes in entry names. PowerShell 5.1's CreateFromDirectory + # leaks Windows path separators into ZIP entries, which makes + # NeoForge fail to find META-INF/neoforge.mods.toml. We build with + # explicit CreateEntry above, but if anyone "simplifies" the zip + # path back to CreateFromDirectory, this guard fires. + $badSep = $names | Where-Object { $_ -match '\\' } + if ($badSep) { + throw ("$jarName has entries with backslash separators (NeoForge will reject it):`n - " + ($badSep -join "`n - ")) + } + + # 2. META-INF/neoforge.mods.toml must be at the canonical path. + if (-not ($names -contains 'META-INF/neoforge.mods.toml')) { + throw "$jarName is missing META-INF/neoforge.mods.toml at the canonical forward-slash path. Found: $($names -join ', ')" + } + + # 3. modId from the embedded toml must match the jar's filename, so a + # misnamed source folder doesn't ship a jar whose manifest declares + # a different mod (which loads silently under the wrong identity). + $tomlEntry = $verify.GetEntry('META-INF/neoforge.mods.toml') + $reader = New-Object System.IO.StreamReader($tomlEntry.Open()) + try { $tomlContent = $reader.ReadToEnd() } finally { $reader.Dispose() } + $tomlModId = [regex]::Match($tomlContent, '(?m)^\s*modId\s*=\s*"([^"]+)"').Groups[1].Value + if ($tomlModId -ne $meta.ModId) { + throw "$jarName modId mismatch: source folder advertises '$($meta.ModId)' but built jar's neoforge.mods.toml says '$tomlModId'." + } + } finally { $verify.Dispose() } + $size = (Get-Item $jarPath).Length - Write-Host (" built {0,-40} {1,8:N0} bytes" -f $jarName, $size) + Write-Host (" built {0,-40} {1,8:N0} bytes [validated]" -f $jarName, $size) } Write-Host ""