WIP: ore nodes, catching rules, bee nest fix, smaller Deep Dark
Done and checked: surface and cave-floor ore nodes (companion mod ore/OreNodes.kt), bigger and rarer underground veins; template with nodes passed the world check and the island quick check (node self-tests). Built, not yet tested: catching rules (catch rate falls with the level gap to the trainer's strongest Pokemon, failed catch enrages, strong wild Pokemon hunt weaker trainers; catching/, Fight or Flight config), bee nests emptied when their bee is turned away. In progress: the Deep Dark no longer fills the deepslate layer (split by temperature: cold = Deep Dark, hot = basalt deltas, warm = ordinary caves; world/biomes.json), zone layout regenerated; cave zone types added to world/zones.json but tools/zone_spawns.py doesn't use them yet; template not rebuilt for the new caves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
362d06aa4b
commit
6361636da7
29 files changed
+1733
-357
No files matched your search
+22
-2
@@ -4,8 +4,11 @@
|
||||
Vanilla's overworld biome parameters come from Minecraft's own data generator
|
||||
(run on the vanilla server jar that the NeoForge installer put in
|
||||
build/server; no server is started). Every entry is sent to its target biome
|
||||
from world/biomes.json, the extra entries are appended, and the result becomes
|
||||
the inline biome list of WorldGen Editor's delegate in
|
||||
from world/biomes.json ("remap"), or cut into pieces along one climate
|
||||
parameter ("split": each piece of the parameter's range goes to its own
|
||||
biome; the parts no piece covers are dropped, so the biome around them takes
|
||||
over), the extra entries are appended ("add"), and the result becomes the
|
||||
inline biome list of WorldGen Editor's delegate in
|
||||
datapacks/core/data/cobblesurvival/worldgen/world_preset/island.json.
|
||||
|
||||
The world type has no Nether dimension.
|
||||
@@ -38,11 +41,28 @@ def vanilla_parameters():
|
||||
return json.loads(report.read_text())["biomes"]
|
||||
|
||||
|
||||
def split(entry, rule):
|
||||
"""The pieces of a vanilla entry along rule["parameter"], each sent to its own biome."""
|
||||
name = rule["parameter"]
|
||||
value = entry["parameters"][name]
|
||||
low, high = (value, value) if isinstance(value, (int, float)) else value
|
||||
pieces = []
|
||||
for piece in rule["pieces"]:
|
||||
a, b = max(low, piece["range"][0]), min(high, piece["range"][1])
|
||||
if a < b or (a == b and low == high):
|
||||
pieces.append({"biome": piece["to"], "parameters": {**entry["parameters"], name: [a, b]}})
|
||||
return pieces
|
||||
|
||||
|
||||
def main():
|
||||
spec = json.loads((ROOT / "world/biomes.json").read_text())
|
||||
targets = set(spec["allowed"]) | set(spec["water"])
|
||||
entries, unmapped = [], set()
|
||||
splits = {s["biome"]: s for s in spec.get("split", [])}
|
||||
for entry in vanilla_parameters():
|
||||
if entry["biome"] in splits:
|
||||
entries += split(entry, splits[entry["biome"]])
|
||||
continue
|
||||
target = spec["remap"].get(entry["biome"])
|
||||
if target is None:
|
||||
unmapped.add(entry["biome"])
|
||||
|
||||
+24
-50
@@ -8,12 +8,11 @@
|
||||
0,0 (the island plus a strip of sea; the sea corners inside the square
|
||||
border generate when someone gets there).
|
||||
3. In the same session: load the circle again row by row until Regenerating
|
||||
Ore Veins has put veins into every chunk (it only fills a new chunk while
|
||||
it is loaded, 8 a tick, and Chunky is faster), place the showcase ore veins (world/zones.json →
|
||||
"ores", tiers with "showcase": one vein sticking out of the ground near
|
||||
its zone's sample point, so players see what a regenerating vein looks
|
||||
like), save, measure where the land ends (tools/world_report.py) and set
|
||||
a square world border `border_margin` blocks outside the outermost coast.
|
||||
Ore Veins has put its veins and the companion mod its ore nodes into every
|
||||
chunk (both only fill a new chunk while it is loaded, a few a tick, and
|
||||
Chunky is faster), save, measure where the land ends (tools/world_report.py)
|
||||
and set a square world border `border_margin` blocks outside the outermost
|
||||
coast.
|
||||
4. Copy the world to build/world-template without player data, then run
|
||||
the world checks and render the map (build/island-map.png).
|
||||
|
||||
@@ -36,14 +35,29 @@ from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from mcserver import BUILD, ROOT, SERVER, Server, chunky, eula_accepted, prepare, scan_log # noqa: E402
|
||||
import world_report # noqa: E402
|
||||
import zone_grid # noqa: E402
|
||||
from numpy import hypot as np_hypot # noqa: E402
|
||||
|
||||
TEMPLATE = BUILD / "world-template"
|
||||
SKIP = shutil.ignore_patterns("playerdata", "advancements", "stats", "session.lock")
|
||||
# A showcase sits this far from its zone's sample point (where guardians and the self-tests stand), first offset
|
||||
# that is still inside the zone wins.
|
||||
SHOWCASE_OFFSETS = [(16, 0), (0, 16), (-16, 0), (0, -16), (24, 24), (-24, -24)]
|
||||
|
||||
|
||||
def border_for(world, recipe):
|
||||
"""Square border around the land, `border_margin` past the outermost coast."""
|
||||
data = world_report.analyse(world)
|
||||
land = world_report.island_mask(data)
|
||||
zs, xs = land.nonzero()
|
||||
ox, oz = data["origin"]
|
||||
x0, x1 = int(xs.min()) + ox, int(xs.max()) + ox + 1
|
||||
z0, z1 = int(zs.min()) + oz, int(zs.max()) + oz + 1
|
||||
far = float(np_hypot(xs + ox, zs + oz).max())
|
||||
if far + recipe["border_margin"] > recipe["pregen_radius"]:
|
||||
sys.exit(f"land reaches {far:.0f} blocks from 0,0; raise pregen_radius ({recipe['pregen_radius']}) in "
|
||||
f"world/world.json to at least land + border_margin")
|
||||
cx, cz = round((x0 + x1) / 2), round((z0 + z1) / 2)
|
||||
size = max(x1 - x0, z1 - z0) + 2 * recipe["border_margin"]
|
||||
print(f"land spans x {x0}..{x1}, z {z0}..{z1}, at most {far:.0f} blocks from 0,0; "
|
||||
f"border center {cx},{cz} size {size}")
|
||||
return cx, cz, size
|
||||
|
||||
|
||||
def fill_veins(server, radius):
|
||||
@@ -72,45 +86,6 @@ def fill_veins(server, radius):
|
||||
return left
|
||||
|
||||
|
||||
def place_showcases(server):
|
||||
"""One hand-placed vein per showcase tier, half sunk into the ground near the zone's sample point."""
|
||||
plan = json.loads((ROOT / "world/zones.json").read_text())
|
||||
grid = zone_grid.load()
|
||||
samples = json.loads(zone_grid.ISLAND.read_text())["samples"]
|
||||
for tier, spec in plan["ores"].items():
|
||||
if not spec.get("showcase"):
|
||||
continue
|
||||
sx, _, sz = samples[spec["zone"]]
|
||||
spot = next(((sx + dx, sz + dz) for dx, dz in SHOWCASE_OFFSETS if grid.zone_at(sx + dx, sz + dz) == spec["zone"]), None)
|
||||
if spot is None:
|
||||
raise RuntimeError(f"no showcase spot inside {spec['zone']} near its sample point {sx},{sz}")
|
||||
x, z = spot
|
||||
server.command(f"forceload add {x} {z}")
|
||||
reply = server.command(f"execute in minecraft:overworld positioned {x} 0 {z} positioned over world_surface "
|
||||
f"positioned ~ ~-1 ~ run regenerating_ore_veins place {tier}_showcase").strip()
|
||||
server.command(f"forceload remove {x} {z}")
|
||||
print(f" showcase {tier} at {x},{z}: {reply[:100]}")
|
||||
|
||||
|
||||
def border_for(world, recipe):
|
||||
"""Square border around the land, `border_margin` past the outermost coast."""
|
||||
data = world_report.analyse(world)
|
||||
land = world_report.island_mask(data)
|
||||
zs, xs = land.nonzero()
|
||||
ox, oz = data["origin"]
|
||||
x0, x1 = int(xs.min()) + ox, int(xs.max()) + ox + 1
|
||||
z0, z1 = int(zs.min()) + oz, int(zs.max()) + oz + 1
|
||||
far = float(np_hypot(xs + ox, zs + oz).max())
|
||||
if far + recipe["border_margin"] > recipe["pregen_radius"]:
|
||||
sys.exit(f"land reaches {far:.0f} blocks from 0,0; raise pregen_radius ({recipe['pregen_radius']}) in "
|
||||
f"world/world.json to at least land + border_margin")
|
||||
cx, cz = round((x0 + x1) / 2), round((z0 + z1) / 2)
|
||||
size = max(x1 - x0, z1 - z0) + 2 * recipe["border_margin"]
|
||||
print(f"land spans x {x0}..{x1}, z {z0}..{z1}, at most {far:.0f} blocks from 0,0; "
|
||||
f"border center {cx},{cz} size {size}")
|
||||
return cx, cz, size
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.parse_args()
|
||||
@@ -133,7 +108,6 @@ def main():
|
||||
seconds = server.pregenerate(0, 0, recipe["pregen_radius"], shape="circle")
|
||||
print(f"pregeneration finished in {seconds:.0f}s")
|
||||
fill_veins(server, recipe["pregen_radius"])
|
||||
place_showcases(server)
|
||||
server.command("save-all flush")
|
||||
cx, cz, size = border_for(world, recipe)
|
||||
print(f" {server.command(f'worldborder center {cx} {cz}').strip()}")
|
||||
|
||||
+30
-9
@@ -3,15 +3,17 @@
|
||||
|
||||
* Ore scan: every block in every stored chunk is checked. Ore ("*_ore",
|
||||
ancient debris, raw ore blocks from large veins) is only allowed as part of
|
||||
a regenerating vein (Regenerating Ore Veins' saved data), and each vein's
|
||||
blocks must lie in the zone of its ore tier (world/zones.json → "ores").
|
||||
a regenerating vein (Regenerating Ore Veins' saved data: the underground
|
||||
veins and the companion mod's ore nodes), and each vein's blocks must lie
|
||||
in the zone of its ore tier (world/zones.json → "ores").
|
||||
A surface tier's blocks must lie in its zone's grid cells (the mod checks
|
||||
every block against the zone's boxes; at a cave border a vein can reach
|
||||
into the cave biome). A cave tier's blocks must lie within two biome cells
|
||||
(8 blocks) of its cave biome: the mod checks the biome only at a vein's
|
||||
centre, and Minecraft blends biomes over a few blocks. Untracked ore fails
|
||||
the check, and so (except with --sample) do an ore tier without any vein
|
||||
and a chunk the mod never put veins into.
|
||||
the check, and so (except with --sample) do an ore tier without nodes, a
|
||||
surface tier without underground veins, and a chunk that never got its
|
||||
veins and nodes.
|
||||
* Biome set: every biome stored in any chunk section (surface and caves)
|
||||
must be listed in world/biomes.json ("allowed" or "water").
|
||||
* End access: at least one stronghold must start inside the world border.
|
||||
@@ -231,20 +233,37 @@ def read_veins(world):
|
||||
return veins, filled
|
||||
|
||||
|
||||
def read_node_chunks(world):
|
||||
"""The chunks the companion mod has put its ore nodes into (ore/OreNodes.kt)."""
|
||||
path = Path(world, "data/cobblesurvival_ore_nodes.dat")
|
||||
if not path.exists():
|
||||
return set()
|
||||
import gzip
|
||||
data = anvil.parse_nbt(gzip.decompress(path.read_bytes()))
|
||||
done = set()
|
||||
for packed in data.get("data", data).get("done", []):
|
||||
packed = int(packed)
|
||||
x, z = packed & 0xFFFFFFFF, (packed >> 32) & 0xFFFFFFFF
|
||||
done.add((x - (1 << 32) if x >= 1 << 31 else x, z - (1 << 32) if z >= 1 << 31 else z))
|
||||
return done
|
||||
|
||||
|
||||
def check_veins(world, ore_at, full_chunks, sample):
|
||||
"""Every ore block belongs to a tracked vein in its tier's zone; returns (blocks per tier and zone, problems)."""
|
||||
plan = json.loads((ROOT / "world/zones.json").read_text())
|
||||
grid = zone_grid.load()
|
||||
cave_biome = {c["id"]: c["biome"] for c in plan["caves"]}
|
||||
veins, filled = read_veins(world)
|
||||
per_tier, untracked, stray = {}, {}, {}
|
||||
nodes_done = read_node_chunks(world)
|
||||
per_tier, untracked, stray, kinds = {}, {}, {}, set()
|
||||
for x, y, z, name, biome, near_caves in ore_at:
|
||||
vein = veins.get((x, y, z))
|
||||
if vein is None:
|
||||
if ORE.search(name): # amethyst outside a vein is a natural geode
|
||||
untracked[name] = untracked.get(name, 0) + 1
|
||||
continue
|
||||
tier = vein.removesuffix("_showcase").removesuffix("_deep")
|
||||
tier = vein.removesuffix("_node").removesuffix("_deep")
|
||||
kinds.add((tier, "node" if vein.endswith("_node") else "vein"))
|
||||
zone = grid.zone_at(x, z, biome) or "none"
|
||||
counts = per_tier.setdefault(tier, {})
|
||||
counts[zone] = counts.get(zone, 0) + 1
|
||||
@@ -257,10 +276,12 @@ def check_veins(world, ore_at, full_chunks, sample):
|
||||
stray.setdefault((vein, zone, want), []).append((x, y, z))
|
||||
problems = [f"{n} {name} outside any regenerating vein" for name, n in sorted(untracked.items())]
|
||||
if not sample:
|
||||
problems += [f"ore tier {tier} has no vein in the world" for tier in plan["ores"] if tier not in per_tier]
|
||||
unfilled = [c for c in full_chunks if c not in filled]
|
||||
problems += [f"ore tier {tier} has no ore nodes in the world" for tier in plan["ores"] if (tier, "node") not in kinds]
|
||||
problems += [f"ore tier {tier} has no underground veins in the world" for tier, spec in plan["ores"].items()
|
||||
if "veins" in spec and (tier, "vein") not in kinds]
|
||||
unfilled = [c for c in full_chunks if c not in filled or c not in nodes_done]
|
||||
if unfilled:
|
||||
problems.append(f"{len(unfilled)} chunks never got their ore veins (e.g. chunk {unfilled[0]})")
|
||||
problems.append(f"{len(unfilled)} chunks never got their ore veins and nodes (e.g. chunk {unfilled[0]})")
|
||||
problems += [f"{len(at)} blocks of vein {vein} in zone {zone}, not {want or '(no tier)'} (e.g. {at[0]})"
|
||||
for (vein, zone, want), at in sorted(stray.items(), key=str)]
|
||||
return per_tier, problems
|
||||
|
||||
+59
-40
@@ -1,25 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Write Regenerating Ore Veins' config from the zone plan, so every ore tier only has veins in its zone.
|
||||
"""Write Regenerating Ore Veins' config and the companion mod's ore node table from the zone plan.
|
||||
|
||||
world/zones.json → "ores" lists the tiers. This tool writes pack/config/regenerating_ore_veins/:
|
||||
world/zones.json → "ores" lists the tiers (Adrian, 2026-10-30: small ore nodes on the surface, larger veins
|
||||
underground that are harder to find, and the cave zones' ores as nodes on the cave floor). This tool writes
|
||||
pack/config/regenerating_ore_veins/:
|
||||
|
||||
* areas.json: each surface zone that has a tier, as boxes from the zone grid (build/zone-layout.json,
|
||||
24-block cells; rows of cells merged into rectangles), named <zone>_<n>, reaching from bedrock to
|
||||
the build limit. The mod's boxes are centre plus half-size, so a box covers its cells except their
|
||||
last row and column of blocks: no box reaches into a neighbouring zone.
|
||||
* veins.json: one vein per tier, or two when the tier has "stone" and "deepslate" blocks (an upper vein
|
||||
from y 0 up, "<tier>_deep" below). A surface tier's veins are limited to its zone's boxes and kept out
|
||||
of the cave biomes, which are zones of their own; a cave tier's veins to its cave biome. The mod checks
|
||||
the area for every block and the biome at a vein's centre. One vein only for the self-tests comes
|
||||
last ("selftest", a single coal block); its area lies far outside the world border, so it never
|
||||
generates, and the tests place it by command. Each tier with "showcase" also gets "<tier>_showcase", a full
|
||||
radius-2 vein in the same place-only area, which tools/make_world.py places by hand near the zone's sample point.
|
||||
* veins.json: a surface tier's underground veins ("veins"): one vein, or two when the tier has "stone" and
|
||||
"deepslate" blocks (an upper vein from y 0 up, "<tier>_deep" below), limited to its zone's boxes and kept
|
||||
out of the cave biomes, which are zones of their own. The mod checks the area for every block and the
|
||||
biome at a vein's centre. Then every tier's "<tier>_node": the ore node (the stone ore, or the tier's
|
||||
blocks), placed only by the companion mod, so its area lies far outside the world border, where the mod
|
||||
never generates it by itself. The same goes for "selftest" (a single coal block the self-tests place).
|
||||
* global.json: regenerators can't be broken by players (allow_breaking false), so nobody can remove a
|
||||
vein for good; explosions don't destroy veins.
|
||||
* vein_locator.json: the Vein Locator from a compass and a copper ingot (mid-game) instead of netherite.
|
||||
|
||||
It also writes world/vein-sources.json, the veins as item sources for the field guide (tools/fieldguide/build.py
|
||||
reads it by default): what each tier's blocks drop and in which zone.
|
||||
It also writes datapacks/core/data/cobblesurvival/ore_nodes/island.json, the node table the companion mod reads
|
||||
(ore/OreNodes.kt: which node, in which zone, how often per chunk, on the surface or on a cave floor), and
|
||||
world/vein-sources.json, the nodes and veins as item sources for the field guide (tools/fieldguide/build.py reads it
|
||||
by default): what each tier's blocks drop and in which zone.
|
||||
|
||||
Re-run after changing the zone plan or the grid (tools/zone_layout.py) and commit the result.
|
||||
|
||||
@@ -35,6 +38,7 @@ LAYOUT = ROOT / "build/zone-layout.json"
|
||||
BOTTOM, TOP = -64, 320
|
||||
SELFTEST_AREA = "selftest_nowhere"
|
||||
SOURCES = ROOT / "world/vein-sources.json"
|
||||
NODES = ROOT / "datapacks/core/data/cobblesurvival/ore_nodes/island.json"
|
||||
# What an ore block drops, where it isn't the block itself or "<name>_ore" → "<name>".
|
||||
DROPS = {"iron": "raw_iron", "copper": "raw_copper", "gold": "raw_gold", "lapis": "lapis_lazuli",
|
||||
"nether_quartz": "quartz", "amethyst_block": "amethyst_block", "budding_amethyst": "amethyst_shard"}
|
||||
@@ -83,7 +87,8 @@ def zone_areas(layout, zone_id):
|
||||
return areas
|
||||
|
||||
|
||||
def vein(vein_id, blocks, spec, defaults, y_range, where):
|
||||
def vein(vein_id, blocks, spec, shape, defaults, y_range, where):
|
||||
"""One entry of veins.json: spec gives the regrowth time, shape the size and spacing."""
|
||||
seconds = spec["regen_minutes"] * 60
|
||||
jitter = round(seconds * spec.get("jitter", defaults["jitter"]))
|
||||
return {
|
||||
@@ -93,13 +98,13 @@ def vein(vein_id, blocks, spec, defaults, y_range, where):
|
||||
"dimension_whitelist": ["minecraft:overworld"],
|
||||
**where,
|
||||
"shape": "sphere",
|
||||
"min_radius": spec["radius"][0],
|
||||
"max_radius": spec["radius"][1],
|
||||
"attempts": spec.get("attempts", defaults["attempts"]),
|
||||
"min_radius": shape["radius"][0],
|
||||
"max_radius": shape["radius"][1],
|
||||
"attempts": shape.get("attempts", defaults["attempts"]),
|
||||
"min_y": y_range[0],
|
||||
"max_y": y_range[1],
|
||||
"chunk_minimum_generation_separation": spec["spacing"],
|
||||
"fill_factor": spec.get("fill", defaults["fill"]),
|
||||
"chunk_minimum_generation_separation": shape.get("spacing", 64),
|
||||
"fill_factor": shape.get("fill", defaults["fill"]),
|
||||
"regeneration_interval_seconds": seconds,
|
||||
"regeneration_interval_jitter": {"range_min": -jitter, "range_max": jitter},
|
||||
}
|
||||
@@ -122,34 +127,41 @@ def main():
|
||||
caves = {c["id"]: c["biome"] for c in plan["caves"]}
|
||||
surface = {z["id"] for z in plan["zones"]}
|
||||
|
||||
areas, area_names, veins = [], {}, []
|
||||
areas, area_names, veins, nodes = [], {}, [], []
|
||||
place_only = {"area_whitelist": [SELFTEST_AREA]}
|
||||
for tier, spec in plan["ores"].items():
|
||||
zone = spec["zone"]
|
||||
if zone in caves:
|
||||
where = {"biome_whitelist": [caves[zone]]}
|
||||
elif zone in surface:
|
||||
if zone not in area_names:
|
||||
boxes = zone_areas(layout, zone)
|
||||
if not boxes:
|
||||
sys.exit(f"zone {zone} (ore tier {tier}) has no cells in the grid")
|
||||
areas += boxes
|
||||
area_names[zone] = [a["name"] for a in boxes]
|
||||
where = {"area_whitelist": area_names[zone], "biome_blacklist": sorted(caves.values())}
|
||||
else:
|
||||
if zone not in caves and zone not in surface:
|
||||
sys.exit(f"ore tier {tier}: unknown zone {zone}")
|
||||
low, high = spec["y"]
|
||||
if spec.get("showcase"):
|
||||
blocks = [(spec["stone"], 1)] if spec.get("stone") else [tuple(b) for b in spec["blocks"]]
|
||||
showcase = vein(f"{tier}_showcase", blocks, spec, defaults, (0, 0), {"area_whitelist": [SELFTEST_AREA]})
|
||||
veins.append({**showcase, "min_radius": 2, "max_radius": 2, "fill_factor": 0.8})
|
||||
# A node is the stone ore; deepslate where there is no stone ore or the node sits below y 0 (deep caves).
|
||||
deep = not spec.get("stone") or (zone in caves and spec["nodes"]["y"][1] < 0)
|
||||
node_blocks = [tuple(b) for b in spec["blocks"]] if "blocks" in spec else [(spec["deepslate" if deep else "stone"], 1)]
|
||||
node_shape = {**spec["nodes"], "fill": 1.0 if spec["nodes"]["radius"][1] == 0 else defaults["node_fill"]}
|
||||
veins.append(vein(f"{tier}_node", node_blocks, spec, node_shape, defaults, (0, 0), place_only))
|
||||
node = {"vein": f"{tier}_node", "zone": zone, "where": "cave" if zone in caves else "surface",
|
||||
"chance": spec["nodes"]["chance"], "radius": spec["nodes"]["radius"][1]}
|
||||
if zone in caves:
|
||||
node.update({"biome": caves[zone], "tries": spec["nodes"]["tries"], "y": spec["nodes"]["y"]})
|
||||
nodes.append(node)
|
||||
if "veins" not in spec:
|
||||
continue
|
||||
if zone not in area_names:
|
||||
boxes = zone_areas(layout, zone)
|
||||
if not boxes:
|
||||
sys.exit(f"zone {zone} (ore tier {tier}) has no cells in the grid")
|
||||
areas += boxes
|
||||
area_names[zone] = [a["name"] for a in boxes]
|
||||
where = {"area_whitelist": area_names[zone], "biome_blacklist": sorted(caves.values())}
|
||||
shape = spec["veins"]
|
||||
low, high = shape["y"]
|
||||
if "blocks" in spec:
|
||||
veins.append(vein(tier, spec["blocks"], spec, defaults, (low, high), where))
|
||||
veins.append(vein(tier, spec["blocks"], spec, shape, defaults, (low, high), where))
|
||||
continue
|
||||
if spec.get("stone") and high >= 0:
|
||||
veins.append(vein(tier, [(spec["stone"], 1)], spec, defaults, (max(low, 0), high), where))
|
||||
veins.append(vein(tier, [(spec["stone"], 1)], spec, shape, defaults, (max(low, 0), high), where))
|
||||
if spec.get("deepslate") and low < 0:
|
||||
deep_id = f"{tier}_deep" if spec.get("stone") and high >= 0 else tier
|
||||
veins.append(vein(deep_id, [(spec["deepslate"], 1)], spec, defaults, (low, min(high, -1)), where))
|
||||
veins.append(vein(deep_id, [(spec["deepslate"], 1)], spec, shape, defaults, (low, min(high, -1)), where))
|
||||
|
||||
areas.append({"dimension": "minecraft:overworld", "name": SELFTEST_AREA, "type": "box",
|
||||
"x": 29_000_000, "y": 0, "z": 29_000_000, "dimx": 0, "dimy": 0, "dimz": 0})
|
||||
@@ -177,12 +189,18 @@ def main():
|
||||
"durability": 2,
|
||||
"stack_size": 64,
|
||||
}, indent=2) + "\n")
|
||||
NODES.parent.mkdir(parents=True, exist_ok=True)
|
||||
NODES.write_text(json.dumps({
|
||||
"_comment": "Generated by tools/zone_ores.py from world/zones.json; read by the companion mod (ore/OreNodes.kt).",
|
||||
"nodes": nodes}, indent=1) + "\n")
|
||||
names = {z["id"]: z["name"] for z in plan["zones"] + plan["caves"]}
|
||||
sources = []
|
||||
for tier, spec in plan["ores"].items():
|
||||
blocks = [b for b, _ in spec.get("blocks", [])] + [spec[k] for k in ("stone", "deepslate") if spec.get(k)]
|
||||
where = (f"ore nodes on the cave floor in {names[spec['zone']]}" if spec["zone"] in caves
|
||||
else f"ore nodes on the ground and veins underground in {names[spec['zone']]}")
|
||||
for item in dict.fromkeys(drop_of(b) for b in blocks):
|
||||
sources.append({"item": item, "how": f"Regenerating {tier.replace('_', ' ')} vein in {names[spec['zone']]}",
|
||||
sources.append({"item": item, "how": f"Regenerating {tier.replace('_', ' ')} {where}",
|
||||
"kind": "ore vein", "needs": []})
|
||||
SOURCES.write_text(json.dumps({
|
||||
"_comment": "Generated by tools/zone_ores.py from world/zones.json; extra item sources for the field guide.",
|
||||
@@ -190,10 +208,11 @@ def main():
|
||||
per_zone = {}
|
||||
for tier, spec in plan["ores"].items():
|
||||
per_zone.setdefault(spec["zone"], []).append(tier)
|
||||
print(f"wrote {len(veins)} veins ({len(plan['ores'])} tiers) and {len(areas)} areas to {OUT.relative_to(ROOT)}")
|
||||
print(f"wrote {len(veins)} veins ({len(plan['ores'])} tiers) and {len(areas)} areas to {OUT.relative_to(ROOT)}, "
|
||||
f"{len(nodes)} node kinds to {NODES.relative_to(ROOT)}")
|
||||
for zone, tiers in per_zone.items():
|
||||
boxes = len(area_names.get(zone, []))
|
||||
print(f" {zone}: {', '.join(tiers)}" + (f" ({boxes} boxes)" if boxes else " (cave biome)"))
|
||||
print(f" {zone}: {', '.join(tiers)}" + (f" ({boxes} boxes)" if boxes else " (cave nodes)"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user