from __future__ import annotations import json import shutil import zipfile from pathlib import Path from warium_source import MODID, ROOT, clean_dir, download_original, safe_java_identifier, write_json GENERATED_JAVA = ROOT / "src" / "generated" / "java" GENERATED_RESOURCES = ROOT / "src" / "generated" / "resources" INVENTORY_DIR = ROOT / "docs" / "inventory" def main() -> None: jar = download_original() clean_dir(GENERATED_JAVA) clean_dir(GENERATED_RESOURCES) INVENTORY_DIR.mkdir(parents=True, exist_ok=True) with zipfile.ZipFile(jar) as archive: names = archive.namelist() block_names = sorted(stem(n) for n in names if n.startswith(f"assets/{MODID}/blockstates/") and n.endswith(".json")) block_kinds = {name: block_kind(archive, name) for name in block_names} item_model_names = sorted(stem(n) for n in names if n.startswith(f"assets/{MODID}/models/item/") and n.endswith(".json")) standalone_items = sorted(name for name in item_model_names if name not in set(block_names)) extract_resources(archive) merge_language_defaults() inventory = { "source": "Warium 1.2.7", "source_sha1": "528d81630a23fb4004e3abdd99b16bd225cd1e92", "modid": MODID, "blocks_from_blockstates": block_names, "block_kinds": block_kinds, "standalone_items_from_item_models": standalone_items, "counts": { "blockstates": len(block_names), "item_models": len(item_model_names), "standalone_items": len(standalone_items), "classes": len([n for n in names if n.endswith(".class")]), "procedures": len([n for n in names if n.startswith("net/mcreator/crustychunks/procedures/") and n.endswith(".class")]), "entities": len([n for n in names if n.startswith("net/mcreator/crustychunks/entity/") and n.endswith(".class")]), "recipes": len([n for n in names if n.startswith(f"data/{MODID}/recipes/") and n.endswith(".json")]), "loot_tables": len([n for n in names if n.startswith(f"data/{MODID}/loot_tables/") and n.endswith(".json")]), }, } write_json(INVENTORY_DIR / "original-inventory.json", inventory) write_generated_registries(block_names, block_kinds, standalone_items) def stem(path: str) -> str: return Path(path).name.removesuffix(".json") def block_kind(archive: zipfile.ZipFile, name: str) -> str: with archive.open(f"assets/{MODID}/blockstates/{name}.json") as handle: data = json.loads(handle.read().decode("utf-8")) keys: set[str] = set() for variant in data.get("variants", {}): if not variant: continue for part in variant.split(","): keys.add(part.split("=")[0]) if {"facing", "half", "hinge", "open"}.issubset(keys): return "door" if {"facing", "half", "open"}.issubset(keys): return "trapdoor" if {"facing", "half", "shape"}.issubset(keys): return "stairs" if "type" in keys: return "slab" if {"face", "facing"}.issubset(keys): return "face_attached" if "axis" in keys: return "axis" if "facing" in keys: return "horizontal" return "plain" def extract_resources(archive: zipfile.ZipFile) -> None: for info in archive.infolist(): if info.is_dir(): continue name = info.filename if name.startswith(f"assets/{MODID}/"): target = GENERATED_RESOURCES / name elif name.startswith(f"data/{MODID}/"): target = GENERATED_RESOURCES / migrate_data_path(name) elif name == "pack.mcmeta": continue else: continue target.parent.mkdir(parents=True, exist_ok=True) with archive.open(info) as src, target.open("wb") as dst: shutil.copyfileobj(src, dst) def migrate_data_path(path: str) -> str: path = path.replace(f"data/{MODID}/loot_tables/", f"data/{MODID}/loot_table/") path = path.replace(f"data/{MODID}/tags/items/", f"data/{MODID}/tags/item/") path = path.replace(f"data/{MODID}/tags/blocks/", f"data/{MODID}/tags/block/") path = path.replace(f"data/{MODID}/tags/entity_types/", f"data/{MODID}/tags/entity_type/") path = path.replace(f"data/{MODID}/tags/fluids/", f"data/{MODID}/tags/fluid/") return path def write_generated_registries(blocks: list[str], block_kinds: dict[str, str], items: list[str]) -> None: package_dir = GENERATED_JAVA / "net" / "mcreator" / "crustychunks" / "init" package_dir.mkdir(parents=True, exist_ok=True) used: set[str] = set() lines: list[str] = [ "package net.mcreator.crustychunks.init;", "", "import net.mcreator.crustychunks.CrustyChunksMod;", "import net.minecraft.core.Direction;", "import net.minecraft.core.registries.Registries;", "import net.minecraft.network.chat.Component;", "import net.minecraft.world.item.BlockItem;", "import net.minecraft.world.item.CreativeModeTab;", "import net.minecraft.world.item.Item;", "import net.minecraft.world.item.ItemStack;", "import net.minecraft.world.item.Items;", "import net.minecraft.world.item.context.BlockPlaceContext;", "import net.minecraft.world.level.block.Block;", "import net.minecraft.world.level.block.Blocks;", "import net.minecraft.world.level.block.DoorBlock;", "import net.minecraft.world.level.block.FaceAttachedHorizontalDirectionalBlock;", "import net.minecraft.world.level.block.HorizontalDirectionalBlock;", "import net.minecraft.world.level.block.RotatedPillarBlock;", "import net.minecraft.world.level.block.SlabBlock;", "import net.minecraft.world.level.block.StairBlock;", "import net.minecraft.world.level.block.TrapDoorBlock;", "import net.minecraft.world.level.block.state.BlockState;", "import net.minecraft.world.level.block.state.BlockBehaviour;", "import net.minecraft.world.level.block.state.StateDefinition;", "import net.minecraft.world.level.block.state.properties.AttachFace;", "import net.minecraft.world.level.block.state.properties.BlockSetType;", "import net.neoforged.bus.api.IEventBus;", "import net.neoforged.neoforge.registries.DeferredHolder;", "import net.neoforged.neoforge.registries.DeferredRegister;", "", "public final class GeneratedRegistries {", " public static final DeferredRegister BLOCKS = DeferredRegister.create(Registries.BLOCK, CrustyChunksMod.MODID);", " public static final DeferredRegister ITEMS = DeferredRegister.create(Registries.ITEM, CrustyChunksMod.MODID);", " public static final DeferredRegister CREATIVE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, CrustyChunksMod.MODID);", "", ] for name in blocks: ident = safe_java_identifier(name, used) kind = block_kinds.get(name, "plain") lines.append(f' public static final DeferredHolder {ident} = BLOCKS.register("{name}", () -> createBlock("{kind}"));') lines.append(f' public static final DeferredHolder {ident}_ITEM = ITEMS.register("{name}", () -> new BlockItem({ident}.get(), new Item.Properties()));') for name in items: ident = safe_java_identifier(name, used) lines.append(f' public static final DeferredHolder {ident} = ITEMS.register("{name}", () -> new Item(new Item.Properties()));') lines.extend([ "", ' public static final DeferredHolder WARIUM_TAB = CREATIVE_TABS.register("warium", () -> CreativeModeTab.builder()', ' .title(Component.translatable("itemGroup.crusty_chunks.warium"))', " .icon(() -> new ItemStack(Items.IRON_INGOT))", " .displayItems((parameters, output) -> ITEMS.getEntries().forEach(entry -> output.accept(entry.get())))", " .build());", "", " private GeneratedRegistries() {", " }", "", " public static void register(IEventBus modBus) {", " BLOCKS.register(modBus);", " ITEMS.register(modBus);", " CREATIVE_TABS.register(modBus);", " }", "", " private static Block createBlock(String kind) {", " BlockBehaviour.Properties properties = BlockBehaviour.Properties.of().strength(2.0F, 6.0F);", " return switch (kind) {", ' case "axis" -> new RotatedPillarBlock(properties);', ' case "door" -> new DoorBlock(BlockSetType.IRON, properties);', ' case "face_attached" -> new GeneratedFaceAttachedHorizontalBlock(properties);', ' case "horizontal" -> new GeneratedHorizontalBlock(properties);', ' case "slab" -> new SlabBlock(properties);', ' case "stairs" -> new StairBlock(Blocks.STONE.defaultBlockState(), properties);', ' case "trapdoor" -> new TrapDoorBlock(BlockSetType.IRON, properties);', " default -> new Block(properties);", " };", " }", "", " private static final class GeneratedHorizontalBlock extends HorizontalDirectionalBlock {", " private GeneratedHorizontalBlock(BlockBehaviour.Properties properties) {", " super(properties);", " registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH));", " }", "", " @Override", " public BlockState getStateForPlacement(BlockPlaceContext context) {", " return defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());", " }", "", " @Override", " protected void createBlockStateDefinition(StateDefinition.Builder builder) {", " builder.add(FACING);", " }", " }", "", " private static final class GeneratedFaceAttachedHorizontalBlock extends FaceAttachedHorizontalDirectionalBlock {", " private GeneratedFaceAttachedHorizontalBlock(BlockBehaviour.Properties properties) {", " super(properties);", " registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(FACE, AttachFace.FLOOR));", " }", "", " @Override", " protected void createBlockStateDefinition(StateDefinition.Builder builder) {", " builder.add(FACING, FACE);", " }", " }", "}", "", ]) (package_dir / "GeneratedRegistries.java").write_text("\n".join(lines), encoding="utf-8") def merge_language_defaults() -> None: lang_path = GENERATED_RESOURCES / "assets" / MODID / "lang" / "en_us.json" if lang_path.exists(): data = json.loads(lang_path.read_text(encoding="utf-8")) else: data = {} data.setdefault("itemGroup.crusty_chunks.warium", "Warium") write_json(lang_path, data) if __name__ == "__main__": main()