Minecraft-Friends-AI-ZeroGPU / tests /test_world_map.py
Erinaldordso's picture
Give the world the features and structures the curriculum needs, and measure player latency
16d7054 verified
Raw History Blame Contribute Delete
6.7 kB
"""The world map is a contract with the rest of the runtime.
Voyager's placement, navigation and prompts are all pinned to a walkable surface
at Y=64, and generator settings are only read when a world is first created, so
a careless layer edit silently moves the ground under the bot or leaves the old
map in place. These tests lock both properties down.
"""
from __future__ import annotations
import json
import tempfile
from pathlib import Path
import minecraft_stack as mc
# Every ore a farming bot is expected to be able to reach on foot.
FARMABLE_ORES = (
"coal_ore",
"copper_ore",
"iron_ore",
"gold_ore",
"redstone_ore",
"diamond_ore",
"lapis_ore",
"emerald_ore",
)
def _column() -> list[tuple[str, int, int]]:
"""Return (block, lowest_y, highest_y) from the bottom of the world up."""
y = mc.WORLD_FLOOR_Y
column = []
for block, height in mc.WORLD_FLAT_LAYERS:
column.append((block, y, y + height - 1))
y += height
return column
def test_layer_stack_reaches_the_declared_surface():
column = _column()
assert sum(height for _, height in mc.WORLD_FLAT_LAYERS) == (
mc.WORLD_SURFACE_Y - mc.WORLD_FLOOR_Y
)
# The top layer is the walkable surface and its first air block is Y=64.
assert column[-1][0] == "minecraft:grass_block"
assert column[-1][2] == mc.WORLD_SURFACE_Y - 1
assert column[-1][1] == column[-1][2]
def test_surface_has_farmable_soil_over_the_ores():
column = _column()
by_block = {}
for block, low, high in column:
by_block.setdefault(block, []).append((low, high))
# Soil and grass on top so crops and building have something to work with.
assert "minecraft:dirt" in by_block
assert by_block["minecraft:dirt"][-1][1] == mc.WORLD_SURFACE_Y - 2
# A resource band close enough to the surface to mine without a long shaft.
for ore in FARMABLE_ORES:
assert f"minecraft:{ore}" in by_block, f"{ore} missing from the map"
shallow = [span for span in by_block[f"minecraft:{ore}"] if span[0] > 0]
assert shallow, f"{ore} is only in the deepslate band"
assert min(low for low, _ in shallow) >= mc.WORLD_SURFACE_Y - 32, (
f"{ore} sits too deep to mine from the surface"
)
# The deepslate band duplicates the table at the bottom of the column.
for ore in FARMABLE_ORES:
assert f"minecraft:deepslate_{ore}" in by_block, f"deepslate {ore} missing"
assert "minecraft:bedrock" in by_block
def test_every_layer_block_exists_in_minecraft_1_19():
# An unknown block name makes the server refuse to generate the world, which
# would take the whole Space down on boot. The registry shipped in the repo
# is the same minecraft-data dataset the runtime ships to Mineflayer.
registry = json.loads(
(Path(__file__).resolve().parents[1] / "minecraft_ids_1_19.json").read_text(
encoding="utf-8"
)
)
known = {
entry if isinstance(entry, str) else entry.get("name")
for entry in registry["diggable_blocks"]
}
# bedrock is the one layer that is never diggable, so it is absent by design.
known.add("bedrock")
unknown = [
block for block, _ in mc.WORLD_FLAT_LAYERS if block.split(":", 1)[1] not in known
]
assert unknown == [], f"blocks absent from Minecraft 1.19: {unknown}"
def test_generator_settings_match_the_declared_layers():
settings = json.loads(mc.FLAT_GENERATOR_SETTINGS)
assert settings["layers"] == [
{"block": block, "height": height} for block, height in mc.WORLD_FLAT_LAYERS
]
# Lava lakes stay off: they are the only thing `lakes` controls, and they
# would put lava on the surface the bot builds and pathfinds on.
# (minecraft.wiki/w/Superflat/Settings)
assert settings["lakes"] is False
# `features` was previously asserted False on the theory that vegetation
# would sit on the walkable surface. It does not: biome features such as
# trees and grass occupy blocks *above* WORLD_SURFACE_Y, which is unchanged.
# Leaving it off left a plains superflat with no wood at all, so the official
# curriculum kept proposing crafting tasks the bot could not satisfy.
assert settings["features"] is True
# Omitted on purpose: the documented default is "all the structure sets",
# while an empty list disables every structure. This used to pass [].
assert "structure_overrides" not in settings
def test_map_change_uses_a_new_world_directory():
# Generator settings are only applied when level.dat is created, so the map
# can only be replaced by pointing at a directory that has no world yet.
assert mc.WORLD_DIR != mc.PREVIOUS_WORLD_DIR
assert mc.WORLD_DIR.parent == mc.PERSIST_ROOT
def test_carrying_player_saves_keeps_the_human_session_and_resets_the_bot():
with tempfile.TemporaryDirectory() as tmp:
previous = Path(tmp) / "old-world"
current = Path(tmp) / "new-world"
human = f"{mc._offline_player_uuid(mc.ADMIN_USERNAME)}.dat"
bot = f"{mc._offline_player_uuid(mc.BOT_USERNAME)}.dat"
(previous / "playerdata").mkdir(parents=True)
(previous / "playerdata" / human).write_bytes(b"human-save")
(previous / "playerdata" / bot).write_bytes(b"bot-save")
(previous / "playerdata" / "README.txt").write_text("not a save", encoding="utf-8")
current.mkdir(parents=True)
mc._carry_player_saves(previous, current)
carried = sorted(p.name for p in (current / "playerdata").iterdir())
assert carried == [human]
assert (current / "playerdata" / human).read_bytes() == b"human-save"
# A full bot inventory is what pins the official CurriculumAgent to its
# hardcoded full-inventory branch, so the bot must start clean.
assert not (current / "playerdata" / bot).exists()
# Running again on an already-populated world must not resurrect the bot
# save, and must be safe when there is no previous world at all.
mc._carry_player_saves(previous, current)
mc._carry_player_saves(Path(tmp) / "missing", current)
assert sorted(p.name for p in (current / "playerdata").iterdir()) == [human]
if __name__ == "__main__":
test_layer_stack_reaches_the_declared_surface()
test_surface_has_farmable_soil_over_the_ores()
test_every_layer_block_exists_in_minecraft_1_19()
test_generator_settings_match_the_declared_layers()
test_map_change_uses_a_new_world_directory()
test_carrying_player_saves_keeps_the_human_session_and_resets_the_bot()
print("PASS resource map, surface Y=64 and player save carry-over")