#!/usr/bin/env python3 """Validate metadata, references, and required binary assets in the pack.""" import json import struct from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def load(path): with path.open(encoding="utf-8") as stream: return json.load(stream) def assert_png(path, expected_size=None): data = path.read_bytes() assert data.startswith(b"\x89PNG\r\n\x1a\n"), f"not a PNG: {path}" width, height = struct.unpack(">II", data[16:24]) if expected_size: assert (width, height) == expected_size, f"unexpected PNG size for {path}: {(width, height)}" manifest = load(ROOT / "manifest.json") assert manifest["format_version"] == 2 assert manifest["header"]["uuid"] != manifest["modules"][0]["uuid"] assert manifest["modules"][0]["type"] == "resources" assert len(manifest["header"]["version"]) == 3 assert len(set(manifest["header"]["uuid"] for _ in [0])) == 1 assert manifest["header"]["min_engine_version"] >= [1, 21, 0] assert_png(ROOT / "pack_icon.png", (64, 64)) textures = load(ROOT / "textures/item_texture.json")["texture_data"] sound_defs = load(ROOT / "sounds/sound_definitions.json")["sound_definitions"] mappings = load(ROOT / "geyser/mappings.json") names = ( "interior_shop0", "pawn_shop1", "food_mart2", "hat_shop3", "clothing_shop4", "jump_up5", "city_under_siege6", ) assert set(textures) == {f"friends_cmp:{name}" for name in names} assert len(sound_defs) == len(names) for name in names: texture = textures[f"friends_cmp:{name}"] texture_path = ROOT / (texture["textures"] + ".png") assert texture_path.is_file(), texture_path assert_png(texture_path, (16, 16)) sound = sound_defs[f"music_disc.{name}"] sound_path = ROOT / (sound["sounds"][0]["name"] + ".ogg") assert sound_path.is_file(), sound_path assert sound_path.read_bytes()[:4] == b"OggS", f"not OGG: {sound_path}" assert mappings["format_version"] == 2 for java_item in ("minecraft:music_disc_13", "minecraft:paper"): definitions = mappings["items"][java_item][0]["definitions"] assert len(definitions) == len(names), java_item assert {entry["bedrock_identifier"] for entry in definitions} == set(textures) for entry in definitions: assert entry["bedrock_options"]["icon"] in textures assert entry["predicate"]["property"] == "custom_model_data" assert entry["predicate"]["value"] in names assert_png(ROOT / "textures/environment/clouds.png", (1, 1)) print("Bedrock pack validation passed")