Give the world the features and structures the curriculum needs, and measure player latency
16d7054 verified Download tests/test_world_map.py from Erinaldordso/Minecraft-Friends-AI-ZeroGPU: direct link, hf CLI and curl.
- Browser
- Download file 6.7 kB
-
https://huggingface.co/spaces/Erinaldordso/Minecraft-Friends-AI-ZeroGPU/resolve/main/tests/test_world_map.py
- Command line
-
hf download hf://spaces/Erinaldordso/Minecraft-Friends-AI-ZeroGPU/tests/test_world_map.py
-
curl -L -o test_world_map.py https://huggingface.co/spaces/Erinaldordso/Minecraft-Friends-AI-ZeroGPU/resolve/main/tests/test_world_map.py
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") | |