YUNG's Cave Biomes hard-requires geckolib>=4.7.6 and terrablender>=4.1.0.8;
both now in the distribution. Classified both (server worldgen libs).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Added picaxe (both). Pruned 5 stale keys for removed jars: LittleFrames,
waterframes, watermedia, watervision (WaterMedia stack dropped from the
pack) and the orphan iris key. sides keys 135→131 = current dist count.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
watermedia throws IllegalEnvironmentException on server-side ("keep it
on client"). Its natives (wm_binaries) and dependents (watervision,
waterframes) are client-render media mods too — flip all four to client
so sync drops them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cwb declares @Mod(dist=CLIENT); classify-mods.py read its toml side as
BOTH (the dist annotation isn't in the manifest), so it synced to the
server and RuntimeDistCleaner FATAL'd on CubesWithoutBordersImpl. Flip
to client so sync drops it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Distribution grew 76→135 forgemods; classify-mods.py seeded the 59
new jars into mods-sides.json (57 both, 2 client). Unblocks the server
mod sync — server was stuck on the old 52-jar subset.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drippy Loading Screen (and other client-only mods declaring BOTH in their
manifest) crashed the dedicated server with "Attempted to load class
net/minecraft/client/gui/screens/Screen for invalid dist DEDICATED_SERVER".
tomllib can't catch these (they declare BOTH), so hand-classify the leaf
client-only mods as `client`: BetterF3, JustEnoughResources, MouseTweaks,
Searchables, TravelersTitles, drippyloadingscreen, entityculling, fancymenu,
konkrete, melody, ponderjs, welcomescreen, yeetusexperimentus. Now 24 client
/ 52 both.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop packwiz entirely. The server now loads a filtered mod subset from a
local ./server-mods volume instead of fetching a packwiz pack at boot.
New flow:
- tooling/classify-mods.py (tomllib only, no network) reads each jar's
META-INF/neoforge.mods.toml and seeds mods-sides.json with a side
(client|server|both; default both). Existing entries are preserved.
- mods-sides.json: committed, keyed by jar filename, hand-editable override
surface. Initial seed: 65 both, 11 client, 0 server (76 jars).
- tooling/sync-server-mods.sh mirrors the both/server jars from
$DISTRIBUTION_WEB_ROOT into ./server-mods/ (authoritative; prunes strays;
halts on a missing jar). Replaces render-pack.sh.
- compose: minecraft mounts ./server-mods:/mods:ro with REMOVE_OLD_MODS=TRUE
(itzg auto-syncs /mods -> /data/mods). Removed PACKWIZ_URL, the pack.
extra_host (auth. kept for authlib), and depends_on caddy (drasl kept).
Both classify-mods.py and sync-server-mods.sh resolve their source dir as:
CLI arg / MODS_DIST_DIR env / $DISTRIBUTION_WEB_ROOT (in that order).
Removed: tooling/render-pack.sh + add-custom-mod.sh (packwiz tooling),
pack/ (packwiz source), custom/ (76 jars now sourced from the distribution),
the pack. caddy vhost + its mounts/alias, and the packwiz .gitignore block.
Client distribution is UNCHANGED: HeliosLauncher still installs the full
modset from distribution.json. Docs (CLAUDE.md, plan/04/05/14, runtime)
updated; plan/04-packwiz.md stubbed as superseded by plan/04-mods.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>