Phase 5: breeding with Cobbreeding, Ditto a rare Deep Dark find
Adrian (2026-10-31): add Cobbreeding without a gate; only Ditto should
be rare, in an endgame area or gated behind something else.
- Cobbreeding 2.4.1 (Modrinth only) and Cloth Config (client) in the
pack; Cobblebase's hatchery takes Cobbreeding's eggs.
- Ditto moved from Button Isle to the Deep Dark with both of Cobblemon's
entries (rare in slime chunks, ultra-rare elsewhere): zone_spawns.py
pins take {"zone", "all_entries"}; Deep Dark target +1, Button Isle -1
so no other line moved; Southwold and Frostpeak guardians pinned (they
tie on base stats and flipped between runs).
- HMs' Trainer Ditto is made uncatchable; it still trades.
- check_deps.py skips other-side dependencies; Cobbreeding's harmless
client-mixin log line allowlisted.
- Self-tests cobbreeding_eggs_fit_the_hatchery, trainer_ditto_cant_be_caught;
docs, balance table, Phase 5 checklist.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5b304025c6
commit
5cae9252c3
20 files changed
+274
-148
No files matched your search
+8
-6
@@ -11,9 +11,10 @@ Build metadata after "+" is ignored, so Cobblemon "1.8.4+1.21.1" compares as
|
||||
1.8.4; qualifiers follow Maven (21-beta < 21 < 21.1.265). A mismatch on the `minecraft` dependency is only a warning: every JEI
|
||||
build for 1.21.1 declares "[1.21, 1.21.1)" and NeoForge 21.1 still loads it
|
||||
(checked on the test server, 2026-10-28), so this check is stricter than the
|
||||
loader there.
|
||||
loader there. A dependency limited to the other side (`side = "CLIENT"` in a
|
||||
server folder, e.g. Cobbreeding's Cloth Config) is skipped.
|
||||
|
||||
Usage: tools/check_deps.py <mods_dir> [--neoforge VER] [--minecraft VER]
|
||||
Usage: tools/check_deps.py <mods_dir> [--neoforge VER] [--minecraft VER] [--side server|client]
|
||||
"""
|
||||
import argparse
|
||||
import io
|
||||
@@ -65,7 +66,7 @@ def in_range(version, spec):
|
||||
return False
|
||||
|
||||
|
||||
def read_mods(data, name, found, deps):
|
||||
def read_mods(data, name, found, deps, side):
|
||||
z = zipfile.ZipFile(io.BytesIO(data))
|
||||
names = set(z.namelist())
|
||||
if "META-INF/neoforge.mods.toml" in names:
|
||||
@@ -78,10 +79,10 @@ def read_mods(data, name, found, deps):
|
||||
for mod_id, entries in toml.get("dependencies", {}).items():
|
||||
for dep in entries:
|
||||
required = dep.get("type", "required" if dep.get("mandatory", True) else "optional") == "required"
|
||||
if required:
|
||||
if required and dep.get("side", "BOTH").upper() in ("BOTH", side.upper()):
|
||||
deps.append((mod_id, dep["modId"], dep.get("versionRange", "*"), name))
|
||||
for inner in (n for n in names if n.startswith("META-INF/jarjar/") and n.endswith(".jar")):
|
||||
read_mods(z.read(inner), f"{name}!{inner.rsplit('/', 1)[-1]}", found, deps)
|
||||
read_mods(z.read(inner), f"{name}!{inner.rsplit('/', 1)[-1]}", found, deps, side)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -89,11 +90,12 @@ def main():
|
||||
parser.add_argument("mods_dir", type=Path)
|
||||
parser.add_argument("--neoforge")
|
||||
parser.add_argument("--minecraft", default="1.21.1")
|
||||
parser.add_argument("--side", choices=["server", "client"], default="server")
|
||||
args = parser.parse_args()
|
||||
|
||||
found, deps = {}, []
|
||||
for jar in sorted(args.mods_dir.glob("*.jar")):
|
||||
read_mods(jar.read_bytes(), jar.name, found, deps)
|
||||
read_mods(jar.read_bytes(), jar.name, found, deps, args.side)
|
||||
if args.neoforge:
|
||||
found["neoforge"] = (args.neoforge, "loader")
|
||||
found["minecraft"] = (args.minecraft, "game")
|
||||
|
||||
Reference in new issue
Block a user