Build-Tweaks: validate every jar before declaring success

Adds three structural assertions that run after the zip is built:

1. No backslash separators in any entry name. NeoForge needs
   "META-INF/neoforge.mods.toml" to be at exactly that forward-slash
   path; PowerShell 5.1's [ZipFile]::CreateFromDirectory() puts
   "META-INF\neoforge.mods.toml" instead, which the loader silently
   rejects. The current build code uses CreateEntry with explicit
   forward slashes, but this guard fires if anyone reverts to the
   simpler-looking CreateFromDirectory.

2. META-INF/neoforge.mods.toml exists at the canonical path. Without
   it, NeoForge skips the jar with a bland "not a valid mod file"
   warning that's easy to miss in a 500-line game log.

3. The modId declared in the embedded TOML matches the source folder's
   modId. Catches the case where a tweak folder is renamed but its
   neoforge.mods.toml isn't updated, which would otherwise ship a jar
   whose declared identity differs from its filename.

Each tweak jar's build line now tags "[validated]" so a casual reader
of the log sees that the post-build checks ran. Failure raises a
specific exception with the offending entries listed, so the build
fails loudly at the source instead of producing a pack that mysteriously
doesn't apply its tweaks at runtime.
This commit is contained in:
Matt Sijbers
2026-05-09 22:33:52 +01:00
parent 62c88d4895
commit 372b5090cd
+37 -1
View File
@@ -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 ""