def _create_loot_tables(ctx: Context, namespace: str, opts: HatsOptions): data = DataPack() registry = HatRegistry.get(opts.cmd_id) for category, hats in registry.categories.items(): # Create category loot tables for model_type in ["hat", "hat_on_head"]: data.loot_tables[ f"{namespace}/{model_type}/{category}/all"] = _create_all_hats_from_collection_loot_table( ctx, hats, namespace, model_type) data.loot_tables[ f"{namespace}/{model_type}/{category}/random"] = _create_random_hat_from_collection_loot_table( ctx, hats, namespace, model_type) # Create hat loot tables for hat in hats: data.loot_tables[ f"{namespace}/hat_on_head/{hat.type}"] = _create_hat_loot_table( ctx, hat, hat.item_head or opts.default_item_head) data.loot_tables[ f"{namespace}/hat/{hat.type}"] = _create_hat_loot_table( ctx, hat, hat.item_inventory or opts.default_item_inventory) return data
def test_merge_nuke(): def nuke(*args: Any) -> bool: raise Drop() p1 = DataPack( description="hello", merge_policy=MergePolicy(extra={"pack.mcmeta": [nuke]}), ) p1.merge_policy.extend(MergePolicy(namespace={Function: [nuke]})) p1.merge_policy.extend_namespace_extra("foo.json", nuke) p1["demo:foo"] = Function() p1["demo"].extra["foo.json"] = JsonFile() p1["thing"].extra["foo.json"] = JsonFile() p2 = DataPack(description="world") p2["demo:foo"] = Function() p2["demo:bar"] = Function() p2["demo"].extra["foo.json"] = JsonFile() p1.merge(p2) assert p1.description == "" assert list(p1.functions) == ["demo:bar"] assert list(p1["demo"].extra) == [] assert p1["thing"].extra["foo.json"] == JsonFile()
def test_context_manager_load(tmp_path: Path): with DataPack(path=tmp_path / "foobar") as p1: p1["hello:world"] = Function(["say hello"], tags=["minecraft:load"]) p2 = DataPack() p2.load(tmp_path / "foobar") assert p2 == p1
def test_tag_replace(): p1 = DataPack() p1["demo:foo"] = Function(["say hello"], tags=["minecraft:load"]) p2 = DataPack() p2["minecraft:load"] = FunctionTag({ "values": ["demo:bar"], "replace": True }) p1.merge(p2) assert p1 == { "demo": { Function: { "foo": Function(["say hello"]) } }, "minecraft": { FunctionTag: { "load": FunctionTag({ "values": ["demo:bar"], "replace": True }) } }, }
def test_with_tags(): p1 = DataPack() p2 = DataPack() p1["hello:world"] = Function(["say hello"], tags=["minecraft:load"]) assert p1 != p2 p2["hello"]["world"] = Function(["say hello"]) p2["minecraft"].function_tags["load"] = FunctionTag( {"values": ["hello:world"]}) assert p1 == p2
def test_context_manager(tmp_path: Path): with DataPack(path=tmp_path / "foobar") as p1: p1["hello:world"] = Function(["say hello"], tags=["minecraft:load"]) p2 = DataPack(path=tmp_path / "foobar") assert p2 == p1 assert p2.functions["hello:world"].lines == ["say hello"] assert p2.function_tags["minecraft:load"].data == { "values": ["hello:world"] } assert p2 == p1
def test_merge_block_tags(): p1 = DataPack() p1["custom:blocks"] = BlockTag({"values": ["minecraft:stone"]}) p2 = DataPack() p2["custom:blocks"] = BlockTag({"values": ["minecraft:dirt"]}) p1.merge(p2) assert dict(p1.block_tags) == { "custom:blocks": BlockTag({"values": ["minecraft:stone", "minecraft:dirt"]}) }
def _generate_function_for_hat(namespace: str, hat_type: str): data = DataPack() data.functions[f"{namespace}/event/recipe/{hat_type}"] = Function( textwrap.dedent(f""" loot give @s loot oran9eutan:hats/hat/{hat_type} clear @s knowledge_book 1 # Reset advancement revoke @s only oran9eutan:hats/event/recipe/{hat_type} recipe take @s oran9eutan:hats/{hat_type} """)[1:]) return data
def test_merge_tags(): p1 = DataPack() p1["hello:func1"] = Function(["say foo"], tags=["minecraft:tick"]) p2 = DataPack() p2["hello:func2"] = Function(["say bar"], tags=["minecraft:tick"]) p1.merge(p2) assert len(p1.functions) == 2 assert len(p1.function_tags) == 1 assert p1.function_tags["minecraft:tick"].data == { "values": ["hello:func1", "hello:func2"] }
def create_livereload_data_pack() -> DataPack: data = DataPack("livereload") prefix = {"text": "[livereload]", "color": "red"} ready = ["", prefix, " ", {"text": "Ready", "color": "gold"}] changes = ["", prefix, " ", {"text": f"Changes detected", "color": "gold"}] reloaded = ["", prefix, " ", {"text": f"Reloaded", "color": "gold"}] data["livereload:load"] = Function( [ "schedule clear livereload:poll", "scoreboard objectives add livereload dummy", f"execute unless score delta livereload matches 1.. run tellraw @a {json.dumps(ready)}", f"execute if score delta livereload matches 1.. run tellraw @a {json.dumps(reloaded)}", "schedule function livereload:poll 1s", ], tags=["minecraft:load"], ) data["livereload:poll"] = Function([ "execute store result score new_pack_count livereload run datapack list available", "scoreboard players operation delta livereload = new_pack_count livereload", "scoreboard players operation delta livereload -= pack_count livereload", "scoreboard players operation pack_count livereload = new_pack_count livereload", "execute unless score delta livereload matches 1.. run schedule function livereload:poll 1s", f"execute if score delta livereload matches 1.. run tellraw @a {json.dumps(changes)}", "execute if score delta livereload matches 1.. run schedule function livereload:reload 1s", ]) data["livereload:reload"] = Function(["reload"]) return data
def test_on_bind_rename(): @dataclass class RenameTo: name: str def __call__(self, instance: Function, pack: DataPack, path: str): if path != self.name: pack[self.name] = instance raise Drop() pack = DataPack() pack["hello:world"] = Function(["say hello"], tags=["minecraft:load"], on_bind=RenameTo("hello:other")) assert pack == { "hello": { Function: { "other": Function(["say hello"]) } }, "minecraft": { FunctionTag: { "load": FunctionTag({"values": ["hello:other"]}) } }, }
def test_merge_rules(): def combine_description( pack: DataPack, path: str, current: JsonFile, conflict: JsonFile, ) -> bool: current.data["pack"]["description"] += conflict.data["pack"][ "description"] return True pack = DataPack(description="hello") pack.merge_policy.extend_extra("pack.mcmeta", combine_description) pack.merge(DataPack(description="world")) assert pack.description == "helloworld"
def _generate_recipes_for_hat(namespace: str, hat_type: str, recipes: list[ShapelessHatRecipe]): data = DataPack() for i, recipe in enumerate(recipes, start=1): if isinstance(recipe, ShapelessHatRecipe): suffix = f"_{i}" if len(recipes) > 1 else "" data.recipes[f"{namespace}/{hat_type}{suffix}"] = Recipe({ "type": "minecraft:crafting_shapeless", "ingredients": recipe.ingredients, "result": { "item": "minecraft:knowledge_book", "count": 1 }, }) return data
def test_empty(): assert Document() == Document() assert Document().data == DataPack() assert Document().assets == ResourcePack() assert Document().get_text() == "" empty = "# Lectern snapshot\n\nThe data pack and resource pack are empty.\n" assert Document().get_markdown() == empty assert Document().get_markdown(emit_external_files=True) == (empty, {}) assert Document(text="Nothing to see here") == Document() assert Document(markdown="Nothing to see here") == Document()
def test_text_function(): pack = DataPack() pack["demo:foo"] = Function(["say foo"]) doc = Document(data=pack) doc.add_text("@function demo:bar\nsay bar\n") assert pack.functions == { "demo:foo": Function(["say foo"]), "demo:bar": Function(["say bar"]), }
def test_equality(): assert DataPack() == DataPack() assert DataPack("hello") == DataPack("hello") assert DataPack("hello") != DataPack("world") p1 = DataPack("foo", mcmeta=JsonFile({"pack": {"description": "bar"}})) p2 = DataPack("foo", mcmeta=JsonFile({"pack": {"description": "bar"}})) assert p1 == p2 p1 = DataPack("foo", mcmeta=JsonFile( {"pack": { "description": "bar", "pack_format": 6 }})) p2 = DataPack("foo", mcmeta=JsonFile( {"pack": { "description": "bar", "pack_format": 5 }})) assert p1 != p2
def _generate_category_fashion_show_functions(namespace: str, registry: HatRegistry): data = DataPack() for category, hats in registry.categories.items(): lines = [] for i, hat in enumerate(hats): lines += [ f"execute if score #show_progress hats.math matches {i} run loot replace entity @e[tag=fashion_model] armor.head loot {namespace}/hat_on_head/{hat.type}", f'execute if score #show_progress hats.math matches {i} run title @a subtitle {{"translate": "item.hats.hat.{hat.type}.name"}}', ] lines += [ f'title @a title {{"text": ""}}', "scoreboard players add #show_progress hats.math 1", f"execute if score #show_progress hats.math matches {len(hats)}.. run scoreboard players set #show_progress hats.math 0", ] data.functions[f"{namespace}/dev/fashion_show_{category}"] = Function( "\n".join(lines)) return data
def test_proxy_match(): pack = DataPack() custom = pack["custom"] hey = pack["hey"] for i in range(100): custom[f"path/to/func_{i:02d}"] = Function([f"say {i}"]) hey[f"path/to/func_{i:02d}"] = Function([f"say {i}"]) custom["path/to/end"] = Function(["say end"]) custom["other/subdir/hello"] = Function(["say hello"]) custom["other/subdir/world"] = Function(["say world"]) custom["other/thing"] = Function(["say thing"]) hey["other/subdir/hello"] = Function(["say hello"]) custom_funcs = [f"custom:path/to/func_{i:02d}" for i in range(100)] hey_funcs = [f"hey:path/to/func_{i:02d}" for i in range(100)] assert pack.functions.match() == set() assert pack.functions.match("*") == set(custom_funcs) | set(hey_funcs) | { "custom:path/to/end", "custom:other/subdir/hello", "custom:other/subdir/world", "custom:other/thing", "hey:other/subdir/hello", } assert pack.functions.match("custom:*") == set(custom_funcs) | { "custom:path/to/end", "custom:other/subdir/hello", "custom:other/subdir/world", "custom:other/thing", } assert pack.functions.match("*:other/subdir") == { "custom:other/subdir/hello", "custom:other/subdir/world", "hey:other/subdir/hello", } assert pack.functions.match( "*:path/to/func_0*", "*:path/to/end", "hey:other") == set(custom_funcs[:10]) | set(hey_funcs[:10]) | { "custom:path/to/end", "hey:other/subdir/hello", }
def _generate_advancement_for_hat(namespace: str, hat_type: str, recipes: list[ShapelessHatRecipe]): data = DataPack() criteria = {} for i, recipe in enumerate(recipes, start=1): suffix = f"_{i}" if len(recipes) > 1 else "" criteria[f"recipe{suffix}"] = { "trigger": "minecraft:recipe_unlocked", "conditions": { "recipe": f"{namespace}/{hat_type}{suffix}" }, } data.advancements[f"{namespace}/event/recipe/{hat_type}"] = Advancement({ "criteria": criteria, "requirements": [[c for c in criteria.keys()]], "rewards": { "function": f"{namespace}/event/recipe/{hat_type}" }, }) return data
def test_on_bind(): def on_bind_callback(instance: Function, pack: DataPack, path: str): pack[path + "_alias"] = Function([f"function {path}"]) pack = DataPack() pack["hello:world"] = Function(["say hello"], tags=["minecraft:load"], on_bind=on_bind_callback) assert pack.functions == { "hello:world": Function(["say hello"]), "hello:world_alias": Function(["function hello:world"]), } assert pack.function_tags == { "minecraft:load": FunctionTag({"values": ["hello:world"]}) }
def apply_directives( self, directives: Mapping[str, Directive], fragments: Iterable[Fragment], loaders: Iterable[FragmentLoader] = (), ) -> Tuple[ResourcePack, DataPack]: """Apply directives into a blank data pack and a blank resource pack.""" assets, data = ResourcePack(), DataPack() for fragment in fragments: for loader in loaders: fragment = loader(fragment, directives) if not fragment: break if fragment: directives[fragment.directive](fragment, assets, data) return assets, data
def __init__( self, assets: Optional[ResourcePack] = None, data: Optional[DataPack] = None, ): super().__init__() self.resolvers = [] self.assets = assets or ResourcePack() self.data = data or DataPack() self["data_pack"] = DataPackDirective() self["resource_pack"] = ResourcePackDirective() self["skip"] = SkipDirective() @self.add_resolver def _(self: DirectiveRegistry): for pack in [self.assets, self.data]: for file_type in pack.resolve_scope_map().values(): name = snake_case(file_type.__name__) self[name] = NamespacedResourceDirective(file_type)
def test_namespaces(): p1 = DataPack() p2 = DataPack() assert p1 == p2 assert p1["hello"] == p2["hello"] del p1["hello"] assert dict(p1) != dict(p2) assert p1.keys() != p2.keys() assert p1 == p2 del p1["hello"] p1["hello:world"] = Function(["say hello"]) assert p1 != p2 assert p1.keys() == p2.keys() assert p1["hello"] != p2["hello"] p2["hello:world"] = Function(["say hello"]) assert p1 == p2 assert p1["hello"] == p2["hello"] p2.functions["hello:world"].lines.append("say world") assert p1.functions["hello:world"] != p2.functions["hello:world"] assert p1["hello"] != p2["hello"] assert p1 != p2 p1["hello"].functions["world"].lines.append("say world") assert p1.functions["hello:world"] == p2.functions["hello:world"] assert p1["hello"] == p2["hello"] assert p1 == p2
def test_match(): pack = DataPack() custom = pack["custom"] for i in range(100): custom[f"path/to/func_{i:02d}"] = Function([f"say {i}"]) custom["path/to/end"] = Function(["say end"]) custom["other/subdir/hello"] = Function(["say hello"]) custom["other/subdir/world"] = Function(["say world"]) custom["other/thing"] = Function(["say thing"]) funcs = [f"path/to/func_{i:02d}" for i in range(100)] assert custom.functions.match() == set() assert custom.functions.match("*") == set(funcs) | { "path/to/end", "other/subdir/hello", "other/subdir/world", "other/thing", } assert custom.functions.match("path/to/func_0*") == set(funcs[:10]) assert custom.functions.match("path/to/func_*") == set(funcs) assert custom.functions.match("path/to") == set(funcs) | {"path/to/end"} assert custom.functions.match("path/to/func_*", "other") == set(funcs) | { "other/subdir/hello", "other/subdir/world", "other/thing", } assert custom.functions.match("other/subdir") == { "other/subdir/hello", "other/subdir/world", }
def test_vanilla_compare(minecraft_data_pack: Path): assert DataPack(path=minecraft_data_pack) == DataPack( path=minecraft_data_pack)
def test_vanilla_zip(minecraft_data_pack: Path, tmp_path: Path): pack = DataPack(path=minecraft_data_pack) zipped_pack = pack.save(tmp_path, zipped=True) assert DataPack(path=zipped_pack) == DataPack(path=zipped_pack)
def test_vanilla_content(minecraft_data_pack: Path): pack = DataPack(path=minecraft_data_pack) assert len(list(pack.content)) > 3000
def test_vanilla_igloo(minecraft_data_pack: Path): pack = DataPack(path=minecraft_data_pack) assert pack.structures["minecraft:igloo/top"].data["size"] == [7, 5, 8]
def test_merge_extra(): pack = DataPack() pack.merge(DataPack(description="hello", pack_format=88)) assert pack.description == "hello" assert pack.pack_format == 88
def test_vanilla_igloo_content(minecraft_data_pack: Path): pack = DataPack(path=minecraft_data_pack) content = dict(pack.content) igloo_structure = content["minecraft:igloo/top"] assert isinstance(igloo_structure, Structure) assert igloo_structure.data["size"] == [7, 5, 8]