UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

939 lines (938 loc) 48.9 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); exports.SpawnRuleSchema = exports.RecipeSchema = exports.LootTableSchema = exports.LootPoolSchema = exports.LootConditionSchema = exports.LootEntrySchema = exports.FeatureSchema = exports.FeatureSpreadSchema = exports.ScatterPatternSchema = exports.HeightPlacementSchema = exports.FeaturePlacementSchema = exports.StructureSchema = exports.StructureGenerationSchema = exports.JigsawDefinitionSchema = exports.JigsawPieceSchema = exports.StructureLootSchema = exports.StructureSpawnSchema = exports.JigsawConnectionSchema = exports.BlockVolumeSchema = exports.ItemTypeSchema = exports.ProjectilePropertiesSchema = exports.ArmorPropertiesSchema = exports.WeaponPropertiesSchema = exports.ToolPropertiesSchema = exports.FoodPropertiesSchema = exports.FoodEffectSchema = exports.ItemCategorySchema = exports.ItemTraitSchema = exports.BlockTypeSchema = exports.FlammableConfigSchema = exports.BlockTextureSchema = exports.BlockSoundSchema = exports.BlockShapeSchema = exports.BlockTraitSchema = exports.EntityTypeSchema = exports.EntitySoundsSchema = exports.SpawnConfigSchema = exports.BreedableConfigSchema = exports.RideableConfigSchema = exports.TameableConfigSchema = exports.EntityAppearanceSchema = exports.DropSchema = exports.EntityBehaviorPresetSchema = exports.EntityTraitSchema = exports.GeometrySpecSchema = exports.GeometryTemplateSchema = exports.TextureSpecSchema = exports.PixelArtSchema = exports.TexturedRectangleSchema = exports.McpColorSchema = void 0; exports.MinecraftContentSchema = exports.GenerationOptionsSchema = exports.SharedResourcesSchema = exports.SoundDefinitionSchema = void 0; /** * Zod schemas for Minecraft Content Meta-Schema. * * These schemas are used for: * 1. MCP tool input validation * 2. Runtime type checking * 3. AI-friendly schema descriptions * * The schemas mirror the TypeScript interfaces in IContentMetaSchema.ts */ const zod_1 = require("zod"); // ============================================================================ // TEXTURE AND GEOMETRY SCHEMAS (reusing existing patterns) // ============================================================================ /** * Color specification - hex string or RGB object. */ exports.McpColorSchema = zod_1.z.union([ zod_1.z.string().describe("Hex color like '#FF0000' or 'rgb(255,0,0)'"), zod_1.z.object({ r: zod_1.z.number().min(0).max(255).describe("Red channel (0-255)"), g: zod_1.z.number().min(0).max(255).describe("Green channel (0-255)"), b: zod_1.z.number().min(0).max(255).describe("Blue channel (0-255)"), a: zod_1.z.number().min(0).max(255).optional().describe("Alpha channel (0-255, default 255)"), }), ]); /** * Textured rectangle - procedural texture generation. */ exports.TexturedRectangleSchema = zod_1.z .object({ type: zod_1.z .enum(["none", "solid", "random_noise", "dither_noise", "perlin_noise", "stipple_noise", "gradient"]) .describe("Fill algorithm: 'none' (fully transparent background — use with pixelArt for icon-style overlays), 'solid' (single color), or noise/gradient types for Minecraft-style textures"), colors: zod_1.z .array(exports.McpColorSchema) .optional() .describe("Colors to use. Required for all types except 'none'. For 'solid', only the first color is used. Omit or pass [] when type is 'none'."), factor: zod_1.z.number().min(0).max(1).optional().describe("Noise intensity (0-1). Default: 0.2"), seed: zod_1.z.number().int().optional().describe("Random seed for deterministic results"), pixelSize: zod_1.z.number().int().min(1).optional().describe("Pixel size for noise. Default: 1"), scale: zod_1.z.number().optional().describe("Scale for perlin noise. Default: 4"), }) .describe("Procedural texture using Minecraft-style patterns (or a transparent background when type is 'none')"); /** * Pixel art overlay. */ exports.PixelArtSchema = zod_1.z .object({ scaleMode: zod_1.z .enum(["unit", "exact", "cover"]) .optional() .describe("How the lines/palette grid is scaled onto the target rectangle. Default is 'unit'. " + "'unit' = each character represents 1 Minecraft unit (recommended for blocks/entities); x and y are in Minecraft units. " + "'exact' = each character represents 1 pixel at the native texture resolution; x and y are in pixels (use for precise 16x16 item icons). " + "'cover' = the grid is stretched to fill the entire face/texture (x and y are ignored; can cause non-square stretching)."), x: zod_1.z.number().optional().describe("X offset from the left edge. Units depend on scaleMode (see scaleMode)."), y: zod_1.z.number().optional().describe("Y offset from the top edge. Units depend on scaleMode (see scaleMode)."), lines: zod_1.z.array(zod_1.z.string()).describe("Rows of characters from top to bottom. Space (' ') is always transparent."), palette: zod_1.z .record(zod_1.z.object({ r: zod_1.z.number().min(0).max(255).optional(), g: zod_1.z.number().min(0).max(255).optional(), b: zod_1.z.number().min(0).max(255).optional(), a: zod_1.z.number().min(0).max(255).optional(), hex: zod_1.z.string().optional(), })) .describe("Map characters to colors. Don't define space - it's always transparent"), }) .describe("ASCII-art style pixel overlay for textures"); /** * Texture specification. */ exports.TextureSpecSchema = zod_1.z .object({ file: zod_1.z.string().optional().describe("Reference existing texture file (relative to resource pack)"), generate: exports.TexturedRectangleSchema.optional().describe("Generate texture procedurally. Use type:'none' with pixelArt for icon-style textures with a transparent background."), pixelArt: zod_1.z .array(exports.PixelArtSchema) .optional() .describe("Pixel art overlays drawn on top of the background. Space characters are transparent so you can layer art over (or without) a generated background."), }) .describe("Texture specification. Precedence: 'file' (use existing PNG) > 'generate'+'pixelArt' (procedural) > fallback (item.color / block.mapColor + trait-based template)."); /** * Geometry template types. */ exports.GeometryTemplateSchema = zod_1.z .enum(["humanoid", "quadruped", "quadruped_small", "bird", "fish", "insect", "slime", "flying", "block", "item"]) .describe("Pre-built geometry template"); /** * Geometry specification. */ exports.GeometrySpecSchema = zod_1.z .object({ file: zod_1.z.string().optional().describe("Reference an existing geometry file (relative to the resource pack)."), template: exports.GeometryTemplateSchema.optional().describe("Use a built-in template (humanoid, quadruped, etc.). Fastest path for common body types."), // Note: full IMcpModelDesign is complex, accepting any object for now design: zod_1.z .record(zod_1.z.any()) .optional() .describe("Inline model design (IMcpModelDesign format). Use for fully custom geometry with bones and cubes."), }) .describe("Geometry specification. Precedence (if multiple are provided): 'file' > 'design' > 'template'. " + "Use 'template' for a quick start, 'design' for custom models, 'file' to reference a .geo.json asset you already ship."); // ============================================================================ // ENTITY TYPE SCHEMAS // ============================================================================ /** * Entity traits. */ exports.EntityTraitSchema = zod_1.z .enum([ // Body types "humanoid", "quadruped", "quadruped_small", "flying", "aquatic", "arthropod", "slime", // Behavior archetypes "hostile", "passive", "neutral", "boss", // Combat styles "melee_attacker", "ranged_attacker", "exploder", // Interaction "trader", "tameable", "rideable", "breedable", "leasable", // Special "undead", "illager", "aquatic_only", "baby_variant", "wanders", "patrols", "guards", "flees_daylight", "teleporter", ]) .describe("Pre-packaged bundle of components, behaviors, and appearance"); /** * Entity behavior presets. */ exports.EntityBehaviorPresetSchema = zod_1.z .enum([ // Movement "wander", "swim", "fly_around", "float", "climb", // Combat "melee_attack", "ranged_attack", "target_players", "target_monsters", "flee_when_hurt", "retaliate", // Social "follow_owner", "follow_parent", "herd", "avoid_players", // Interaction "look_at_player", "beg", "tempt", "sit_command", // Actions "eat_grass", "break_doors", "open_doors", "pick_up_items", "sleep_in_bed", // Environment "hide_from_sun", "go_home_at_night", "seek_water", "seek_land", ]) .describe("Pre-built AI behavior that maps to one or more native minecraft:behavior.* components. " + "Movement: 'wander' (random walks, most land mobs), 'swim' (aquatic mobs), 'fly_around' (flying mobs), 'float' (stay upright in water), 'climb' (spiders/cave-dwellers). " + "Combat: 'melee_attack' (approach+strike, zombies), 'ranged_attack' (pair with ranged_attacker trait/projectile), " + "'target_players' (aggros players in range), 'target_monsters' (iron-golem style), 'flee_when_hurt' (run from attacker), 'retaliate' (fight back when hit). " + "Social: 'follow_owner' (tamed pets), 'follow_parent' (babies follow adults), 'herd' (cluster with same type), 'avoid_players' (endermen/foxes). " + "Interaction: 'look_at_player' (turns head), 'beg' (wolf begging for food), 'tempt' (follow held breed items), 'sit_command' (tamed sit/stand). " + "Actions: 'eat_grass' (cow/sheep grass-eating), 'break_doors' (zombie-style), 'open_doors' (villager-style), 'pick_up_items' (collect dropped items), 'sleep_in_bed' (villager sleep cycle). " + "Environment: 'hide_from_sun' (burns in daylight — undead), 'go_home_at_night' (return to bed at dusk), 'seek_water' (fish out of water), 'seek_land' (drowning prevention for non-aquatic)."); /** * Drop definition. */ exports.DropSchema = zod_1.z .object({ item: zod_1.z.string().describe("Item ID (vanilla like 'iron_sword' or namespaced like 'namespace:custom')"), chance: zod_1.z.number().min(0).max(1).optional().describe("Drop chance (0-1). Default: 1.0"), count: zod_1.z .union([zod_1.z.number().int(), zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() })]) .optional() .describe("Stack size - number or {min, max} range"), killedByPlayer: zod_1.z.boolean().optional().describe("Only drop if killed by player"), lootingBonus: zod_1.z.number().optional().describe("Bonus items per looting level"), }) .describe("What drops when entity is killed or block is mined"); /** * Entity appearance. */ exports.EntityAppearanceSchema = zod_1.z .object({ bodyType: exports.GeometryTemplateSchema.optional().describe("Base body template for geometry"), primaryColor: zod_1.z.string().optional().describe("Primary color (hex) for texture generation"), secondaryColor: zod_1.z.string().optional().describe("Secondary/accent color (hex)"), textureStyle: zod_1.z .enum(["solid", "spotted", "striped", "gradient", "organic", "armored"]) .optional() .describe("Procedural pattern used when the auto-generated texture is produced from primary/secondaryColor. " + "'solid' = flat color, 'spotted' = stipple (organic materials), 'striped' = dithered bands, " + "'gradient' = smooth transition, 'organic' = perlin noise (fur/stone), 'armored' = stippled with highlight effect. " + "Ignored when 'texture' is explicitly provided."), scale: zod_1.z .number() .optional() .describe("Scale multiplier. Equivalent to the top-level entity.scale; if both are set, appearance.scale wins."), eyes: zod_1.z .enum(["normal", "glowing", "red", "none"]) .optional() .describe("Eye treatment. 'normal' (default) = no special treatment. 'glowing' = emissive material (glows in the dark). " + "'red' = tinted emissive (spider/enderman style). 'none' = no eye treatment hint. " + "Applied via the entity's material/render controller."), particles: zod_1.z .array(zod_1.z.enum(["flames", "smoke", "drip", "sparkle", "hearts"])) .optional() .describe("Ambient particle effects emitted from the entity. Wired into the resource-pack client entity's particle_effects map. " + "Useful for visual flair (flames on fire mobs, hearts when happy, etc.)."), texture: exports.TextureSpecSchema.optional().describe("Custom texture. When provided, it overrides auto-generation from primary/secondaryColor and textureStyle."), geometry: exports.GeometrySpecSchema.optional().describe("Custom geometry. When provided, it overrides the geometry inferred from bodyType."), }) .describe("Simplified appearance specification. Fields are mixed into the resource-pack client entity and the generated texture/geometry."); /** * Tameable configuration. */ exports.TameableConfigSchema = zod_1.z.object({ tameItems: zod_1.z.array(zod_1.z.string()).describe("Items that can be used to tame"), chance: zod_1.z.number().min(0).max(1).optional().describe("Chance per attempt (0-1)"), }); /** * Rideable configuration. */ exports.RideableConfigSchema = zod_1.z.object({ seatCount: zod_1.z.number().int().optional().describe("Number of seats"), controllable: zod_1.z.boolean().optional().describe("Can be controlled by player"), controlItems: zod_1.z.array(zod_1.z.string()).optional().describe("Items required to control"), }); /** * Breedable configuration. */ exports.BreedableConfigSchema = zod_1.z.object({ breedItems: zod_1.z.array(zod_1.z.string()).describe("Items that trigger breeding"), breedCooldown: zod_1.z.number().optional().describe("Seconds between breeding"), }); /** * Spawn configuration. * * There are two spawn-rule shapes: inline on an entity (this one, `entity.spawning`) and a * separate top-level `spawnRules[]` entry (SpawnRuleSchema). Use the inline form for a rule * bound to a single entity. Use the top-level form when the rule references an entity defined * elsewhere (e.g. a vanilla entity) or when you want the rule file separate from the entity. */ exports.SpawnConfigSchema = zod_1.z .object({ biomes: zod_1.z.array(zod_1.z.string()).optional().describe("Biomes where entity spawns"), weight: zod_1.z.number().int().optional().describe("Spawn weight (higher = more common)"), groupSize: zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() }).optional().describe("Group size range"), lightLevel: zod_1.z .object({ min: zod_1.z.number().int().min(0).max(15).optional(), max: zod_1.z.number().int().min(0).max(15).optional(), }) .optional() .describe("Light level range (0-15)"), heightRange: zod_1.z.object({ min: zod_1.z.number(), max: zod_1.z.number() }).optional().describe("Y level range"), timeOfDay: zod_1.z.enum(["day", "night", "any"]).optional().describe("When to spawn"), surface: zod_1.z.boolean().optional().describe("Surface or underground"), spawnOn: zod_1.z.array(zod_1.z.string()).optional().describe("Block types to spawn on"), populationCap: zod_1.z.number().int().optional().describe("Max population in area"), rarity: zod_1.z.number().optional().describe("1 in N chance per spawn cycle"), }) .describe("Inline spawn configuration for an entity. Use this as `entity.spawning` when the spawn rule belongs " + "to a single custom entity. For spawn rules that reference external entities or that you want as " + "separate files, use the top-level `spawnRules[]` (SpawnRuleSchema) instead."); /** * Entity sounds. */ exports.EntitySoundsSchema = zod_1.z.object({ ambient: zod_1.z.string().optional(), hurt: zod_1.z.string().optional(), death: zod_1.z.string().optional(), step: zod_1.z.string().optional(), attack: zod_1.z.string().optional(), }); /** * Entity type definition. */ exports.EntityTypeSchema = zod_1.z .object({ id: zod_1.z.string().describe("Unique identifier (full ID becomes 'namespace:id')"), displayName: zod_1.z.string().describe("Display name shown in-game"), // Trait-based traits: zod_1.z.array(exports.EntityTraitSchema).optional().describe("Pre-built trait bundles to apply"), // Simplified properties health: zod_1.z.number().optional().describe("Health points"), attackDamage: zod_1.z.number().optional().describe("Attack damage"), movementSpeed: zod_1.z.number().optional().describe("Movement speed (blocks/sec)"), followRange: zod_1.z.number().optional().describe("Follow/detection range"), knockbackResistance: zod_1.z.number().min(0).max(1).optional().describe("Knockback resistance (0-1)"), scale: zod_1.z.number().optional().describe("Scale multiplier"), collisionWidth: zod_1.z.number().optional().describe("Collision box width"), collisionHeight: zod_1.z.number().optional().describe("Collision box height"), behaviors: zod_1.z.array(exports.EntityBehaviorPresetSchema).optional().describe("AI behavior presets"), drops: zod_1.z.array(exports.DropSchema).optional().describe("What drops when killed"), appearance: exports.EntityAppearanceSchema.optional().describe("Appearance specification"), families: zod_1.z.array(zod_1.z.string()).optional().describe("Entity type families"), hostile: zod_1.z.boolean().optional().describe("Is hostile to players?"), tameable: zod_1.z.union([zod_1.z.boolean(), exports.TameableConfigSchema]).optional().describe("Can be tamed"), rideable: zod_1.z.union([zod_1.z.boolean(), exports.RideableConfigSchema]).optional().describe("Can be ridden"), breedable: zod_1.z.union([zod_1.z.boolean(), exports.BreedableConfigSchema]).optional().describe("Can be bred"), // Native components (full control) components: zod_1.z.record(zod_1.z.any()).optional().describe("Native Minecraft components (override traits)"), componentGroups: zod_1.z.record(zod_1.z.record(zod_1.z.any())).optional().describe("Component groups for conditions"), events: zod_1.z.record(zod_1.z.any()).optional().describe("Events for component group changes"), // Resources geometry: exports.GeometrySpecSchema.optional().describe("Custom geometry"), texture: exports.TextureSpecSchema.optional().describe("Custom texture"), sounds: exports.EntitySoundsSchema.optional().describe("Sound definitions"), // Spawning spawning: exports.SpawnConfigSchema.optional().describe("Inline spawn rule"), }) .describe("Entity type definition with traits, simplified props, or native components"); // ============================================================================ // BLOCK TYPE SCHEMAS // ============================================================================ /** * Block traits. */ exports.BlockTraitSchema = zod_1.z .enum([ "solid", "transparent", "leaves", "log", "slab", "stairs", "fence", "wall", "door", "trapdoor", "container", "workstation", "light_source", "gravity", "liquid", "redstone_signal", "redstone_receiver", "button", "lever", "pressure_plate", ]) .describe("Pre-packaged block behavior bundle"); /** * Block shape. */ exports.BlockShapeSchema = zod_1.z .enum(["cube", "slab", "stairs", "fence", "wall", "cross", "custom"]) .describe("Block shape type"); /** * Block sound type. */ exports.BlockSoundSchema = zod_1.z .enum(["stone", "wood", "gravel", "grass", "sand", "glass", "metal", "cloth", "snow", "coral"]) .describe("Sound set for block"); /** * Block texture. */ exports.BlockTextureSchema = zod_1.z .object({ all: zod_1.z.union([zod_1.z.string(), exports.TextureSpecSchema]).optional().describe("All six faces use this texture."), up: zod_1.z.union([zod_1.z.string(), exports.TextureSpecSchema]).optional().describe("Top face (overrides 'all')."), down: zod_1.z.union([zod_1.z.string(), exports.TextureSpecSchema]).optional().describe("Bottom face (overrides 'all')."), north: zod_1.z.union([zod_1.z.string(), exports.TextureSpecSchema]).optional().describe("North face (overrides 'all' and 'side')."), south: zod_1.z.union([zod_1.z.string(), exports.TextureSpecSchema]).optional().describe("South face (overrides 'all' and 'side')."), east: zod_1.z.union([zod_1.z.string(), exports.TextureSpecSchema]).optional().describe("East face (overrides 'all' and 'side')."), west: zod_1.z.union([zod_1.z.string(), exports.TextureSpecSchema]).optional().describe("West face (overrides 'all' and 'side')."), side: zod_1.z .union([zod_1.z.string(), exports.TextureSpecSchema]) .optional() .describe("Shorthand for the four side faces (north/south/east/west). Overrides 'all' for side faces."), }) .describe("Block texture specification. Precedence per face: individual face (up/down/north/south/east/west) > 'side' (for side faces) > 'all'. " + "Note: the current placeholder PNG generator picks a single representative face in this order: all > side > up > north > south > east > west > down."); /** * Flammable config. */ exports.FlammableConfigSchema = zod_1.z.object({ catchChance: zod_1.z.number().min(0).max(1).describe("Chance to catch fire"), destroyChance: zod_1.z.number().min(0).max(1).describe("Chance to be destroyed"), }); /** * Block type definition. */ exports.BlockTypeSchema = zod_1.z .object({ id: zod_1.z.string().describe("Unique identifier"), displayName: zod_1.z.string().describe("Display name"), traits: zod_1.z.array(exports.BlockTraitSchema).optional().describe("Pre-built trait bundles"), destroyTime: zod_1.z.number().optional().describe("Seconds to mine (0=instant, -1=unbreakable)"), explosionResistance: zod_1.z.number().optional().describe("Explosion resistance"), friction: zod_1.z.number().min(0).max(1).optional().describe("Friction (0-1). Default: 0.6"), lightEmission: zod_1.z.number().int().min(0).max(15).optional().describe("Light emission (0-15)"), lightDampening: zod_1.z.number().int().min(0).max(15).optional().describe("Light dampening (0-15)"), flammable: zod_1.z.union([zod_1.z.boolean(), exports.FlammableConfigSchema]).optional().describe("Flammability"), mapColor: zod_1.z .string() .optional() .describe("Map color (hex). Also used as the fallback color for the auto-generated placeholder texture when 'texture' is not provided."), shape: exports.BlockShapeSchema.optional().describe("Block shape"), drops: zod_1.z.array(exports.DropSchema).optional().describe("What drops when mined"), texture: exports.BlockTextureSchema.optional().describe("Texture specification. If omitted, a placeholder is generated from mapColor."), geometry: exports.GeometrySpecSchema.optional().describe("Custom geometry"), sounds: exports.BlockSoundSchema.optional().describe("Sound set"), components: zod_1.z.record(zod_1.z.unknown()).optional().describe("Native Minecraft components"), permutations: zod_1.z.array(zod_1.z.record(zod_1.z.unknown())).optional().describe("Block state permutations"), states: zod_1.z.record(zod_1.z.union([zod_1.z.array(zod_1.z.boolean()), zod_1.z.array(zod_1.z.number()), zod_1.z.array(zod_1.z.string())])).optional(), events: zod_1.z.record(zod_1.z.unknown()).optional(), }) .describe("Block type definition"); // ============================================================================ // ITEM TYPE SCHEMAS // ============================================================================ /** * Item traits. */ exports.ItemTraitSchema = zod_1.z.enum([ "sword", "pickaxe", "axe", "shovel", "hoe", "bow", "crossbow", "food", "armor_helmet", "armor_chestplate", "armor_leggings", "armor_boots", "throwable", "placeable", ]); /** * Item category. */ exports.ItemCategorySchema = zod_1.z.enum(["construction", "nature", "equipment", "items", "none"]); /** * Food effect. */ exports.FoodEffectSchema = zod_1.z.object({ name: zod_1.z.string().describe("Effect name (e.g., 'speed', 'regeneration')"), duration: zod_1.z.number().describe("Duration in seconds"), amplifier: zod_1.z.number().int().optional().describe("Amplifier (0 = level 1)"), chance: zod_1.z.number().min(0).max(1).optional().describe("Chance to apply"), }); /** * Food properties. */ exports.FoodPropertiesSchema = zod_1.z.object({ nutrition: zod_1.z.number().int().describe("Hunger points restored"), saturation: zod_1.z.number().optional().describe("Saturation modifier"), canAlwaysEat: zod_1.z.boolean().optional().describe("Can eat when full"), effects: zod_1.z.array(exports.FoodEffectSchema).optional().describe("Status effects when eaten"), }); /** * Tool properties. */ exports.ToolPropertiesSchema = zod_1.z.object({ miningSpeed: zod_1.z.number().optional().describe("Mining speed multiplier"), miningLevel: zod_1.z.enum(["wood", "stone", "iron", "diamond", "netherite"]).optional(), durability: zod_1.z.number().int().describe("Tool durability"), }); /** * Weapon properties. */ exports.WeaponPropertiesSchema = zod_1.z.object({ damage: zod_1.z.number().describe("Attack damage"), attackSpeed: zod_1.z.number().optional().describe("Attacks per second"), durability: zod_1.z.number().int().optional().describe("Weapon durability"), knockback: zod_1.z.number().optional().describe("Knockback amount"), }); /** * Armor properties. */ exports.ArmorPropertiesSchema = zod_1.z.object({ defense: zod_1.z.number().int().describe("Defense points"), slot: zod_1.z.enum(["helmet", "chestplate", "leggings", "boots"]).describe("Armor slot"), durability: zod_1.z.number().int().describe("Armor durability"), toughness: zod_1.z.number().optional().describe("Armor toughness"), }); /** * Projectile properties (bow/crossbow/throwable items). */ exports.ProjectilePropertiesSchema = zod_1.z .object({ projectile: zod_1.z .string() .describe("Entity ID to shoot/throw (e.g., 'minecraft:arrow', 'minecraft:snowball', or a custom 'namespace:arrow_of_doom')."), launchPower: zod_1.z.number().optional().describe("Launch power multiplier. Default: 1.0."), chargeable: zod_1.z .boolean() .optional() .describe("True for bow/crossbow-style items that charge while held (emits minecraft:shooter + minecraft:chargeable). " + "False/omitted for snowball-style throwables (emits minecraft:throwable)."), }) .describe("Projectile behavior for items that shoot or throw an entity."); /** * Item type definition. */ exports.ItemTypeSchema = zod_1.z .object({ id: zod_1.z.string().describe("Unique identifier"), displayName: zod_1.z.string().describe("Display name"), traits: zod_1.z.array(exports.ItemTraitSchema).optional().describe("Pre-built trait bundles"), maxStackSize: zod_1.z.number().int().min(1).max(64).optional().describe("Max stack size. Default: 64"), category: exports.ItemCategorySchema.optional().describe("Creative menu category"), durability: zod_1.z.number().int().optional().describe("Durability"), food: exports.FoodPropertiesSchema.optional().describe("Food properties"), tool: exports.ToolPropertiesSchema.optional().describe("Tool properties"), weapon: exports.WeaponPropertiesSchema.optional().describe("Weapon properties"), armor: exports.ArmorPropertiesSchema.optional().describe("Armor properties"), projectile: exports.ProjectilePropertiesSchema.optional().describe("Projectile behavior — emits minecraft:shooter (+minecraft:chargeable when chargeable=true) or minecraft:throwable."), glint: zod_1.z.boolean().optional().describe("Enchanted glint effect"), fuel: zod_1.z.number().int().optional().describe("Burn duration in ticks"), color: zod_1.z .string() .optional() .describe("Primary color (hex, e.g., '#4A7BA5') for recoloring the auto-generated trait-based icon. " + "Ignored when 'icon' is provided (icon takes precedence)."), icon: zod_1.z .union([zod_1.z.string(), exports.TextureSpecSchema]) .optional() .describe("Inventory icon. Three modes: (1) string = use an existing texture file path (no placeholder PNG is emitted); " + "(2) ITextureSpec with 'file' = same as (1); (3) ITextureSpec with 'generate' and/or 'pixelArt' = procedurally generated placeholder. " + "If this field is omitted entirely, a placeholder is auto-generated from 'traits' + 'color'."), geometry: exports.GeometrySpecSchema.optional().describe("3D model when held"), components: zod_1.z.record(zod_1.z.any()).optional().describe("Native Minecraft components"), events: zod_1.z.record(zod_1.z.any()).optional(), }) .describe("Item type definition"); // ============================================================================ // STRUCTURE SCHEMAS // ============================================================================ /** * Block volume for inline structure definition. * Uses same format as MCP structure design tools. */ exports.BlockVolumeSchema = zod_1.z .object({ southWestBottom: zod_1.z .object({ x: zod_1.z.number(), y: zod_1.z.number(), z: zod_1.z.number(), }) .describe("World position of south-west-bottom corner"), size: zod_1.z .object({ x: zod_1.z.number().int(), y: zod_1.z.number().int(), z: zod_1.z.number().int(), }) .optional() .describe("Optional dimensions - inferred from data if not provided"), blockLayersBottomToTop: zod_1.z .array(zod_1.z.array(zod_1.z.string())) .describe("Y layers from bottom to top. Each layer: rows from north to south. Each char: X from west to east"), key: zod_1.z .record(zod_1.z.object({ typeId: zod_1.z.string().describe("Block type ID"), properties: zod_1.z.record(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()])).optional(), })) .describe("Map single characters to block types. Space = air"), }) .describe("Block volume using layer-by-layer character grid"); /** * Jigsaw connection. */ exports.JigsawConnectionSchema = zod_1.z.object({ name: zod_1.z.string().describe("Connection name for matching"), position: zod_1.z.object({ x: zod_1.z.number(), y: zod_1.z.number(), z: zod_1.z.number() }).describe("Position in structure"), direction: zod_1.z.enum(["up", "down", "north", "south", "east", "west"]).describe("Direction connection faces"), canConnectTo: zod_1.z.array(zod_1.z.string()).describe("Names of connections this can connect to"), required: zod_1.z.boolean().optional().describe("Is this connection required?"), }); /** * Structure spawn. */ exports.StructureSpawnSchema = zod_1.z.object({ entity: zod_1.z.string().describe("Entity ID to spawn"), count: zod_1.z .union([zod_1.z.number().int(), zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() })]) .describe("Spawn count"), position: zod_1.z.object({ x: zod_1.z.number(), y: zod_1.z.number(), z: zod_1.z.number() }).optional(), spread: zod_1.z.number().optional().describe("Spread radius"), }); /** * Structure loot. */ exports.StructureLootSchema = zod_1.z.object({ lootTable: zod_1.z.string().describe("Loot table ID"), position: zod_1.z.object({ x: zod_1.z.number(), y: zod_1.z.number(), z: zod_1.z.number() }).describe("Container position"), containerType: zod_1.z.enum(["chest", "barrel", "spawner"]).optional(), }); /** * Jigsaw piece. */ exports.JigsawPieceSchema = zod_1.z .object({ id: zod_1.z.string().describe("Piece identifier"), structureFile: zod_1.z.string().optional().describe("Path to .mcstructure file"), blocks: exports.BlockVolumeSchema.optional().describe("Inline block volume definition"), connections: zod_1.z.array(exports.JigsawConnectionSchema).describe("Connection points"), weight: zod_1.z.number().optional().describe("Weight for random selection. Default: 1"), maxCount: zod_1.z.number().int().optional().describe("Max times this piece can appear"), spawns: zod_1.z.array(exports.StructureSpawnSchema).optional().describe("Entities to spawn"), loot: zod_1.z.array(exports.StructureLootSchema).optional().describe("Loot containers"), }) .describe("Jigsaw structure piece"); /** * Jigsaw definition. */ exports.JigsawDefinitionSchema = zod_1.z .object({ pieces: zod_1.z.array(exports.JigsawPieceSchema).describe("All pieces in the structure"), startPiece: zod_1.z.string().describe("ID of starting piece"), maxDepth: zod_1.z.number().int().optional().describe("Maximum generation depth. Default: 7"), maxSize: zod_1.z.object({ x: zod_1.z.number(), y: zod_1.z.number(), z: zod_1.z.number() }).optional(), }) .describe("Jigsaw structure definition - auto-creates template pools and connections"); /** * Structure generation. */ exports.StructureGenerationSchema = zod_1.z.object({ biomes: zod_1.z.array(zod_1.z.string()).optional().describe("Biomes where structure generates"), heightRange: zod_1.z.object({ min: zod_1.z.number(), max: zod_1.z.number() }).optional(), rarity: zod_1.z.number().optional().describe("1 in N chunks. Default: 100"), terrainAdaptation: zod_1.z.enum(["none", "bury", "beard_thin", "beard_box"]).optional(), underground: zod_1.z.boolean().optional(), }); /** * Structure definition. */ exports.StructureSchema = zod_1.z .object({ id: zod_1.z.string().describe("Unique identifier"), displayName: zod_1.z.string().optional(), type: zod_1.z.enum(["simple", "jigsaw"]).describe("Structure type"), structureFile: zod_1.z.string().optional().describe("Path to .mcstructure (for simple)"), blocks: exports.BlockVolumeSchema.optional().describe("Inline blocks (for simple)"), jigsaw: exports.JigsawDefinitionSchema.optional().describe("Jigsaw definition"), generation: exports.StructureGenerationSchema.optional().describe("World generation settings"), }) .describe("Structure definition - simple or jigsaw"); // ============================================================================ // FEATURE SCHEMAS // ============================================================================ /** * Feature placement. */ exports.FeaturePlacementSchema = zod_1.z.object({ type: zod_1.z.enum(["block", "structure", "tree", "ore", "vegetation"]).describe("What to place"), id: zod_1.z.string().describe("Block/structure ID"), count: zod_1.z.union([zod_1.z.number().int(), zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() })]).optional(), replacesBlocks: zod_1.z.array(zod_1.z.string()).optional().describe("Blocks that can be replaced (for ore)"), }); /** * Height placement. */ exports.HeightPlacementSchema = zod_1.z.object({ type: zod_1.z.enum(["surface", "underground", "fixed", "range"]), y: zod_1.z.number().optional().describe("Y level for fixed"), min: zod_1.z.number().optional(), max: zod_1.z.number().optional(), }); /** * Scatter pattern. */ exports.ScatterPatternSchema = zod_1.z.object({ type: zod_1.z.enum(["uniform", "cluster", "line"]), radius: zod_1.z.number().optional(), }); /** * Feature spread - simplified feature hierarchy. */ exports.FeatureSpreadSchema = zod_1.z .object({ places: zod_1.z .array(exports.FeaturePlacementSchema) .describe("What to place. Use 'block' for single blocks, 'ore' for vein generation (pair with replacesBlocks), 'tree'/'vegetation' for botanical features, 'structure' for pre-built .mcstructure placements."), count: zod_1.z .union([zod_1.z.number().int(), zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() })]) .optional() .describe("Placements per generation attempt (fixed count or {min,max})."), heightPlacement: exports.HeightPlacementSchema.optional().describe("Where vertically to place. 'surface' = top of world, 'underground' = below surface, 'fixed' = at Y=y, 'range' = within [min, max]."), scatter: exports.ScatterPatternSchema.optional().describe("Distribution around the base point. 'uniform' spreads across a radius, 'cluster' groups tightly, 'line' places in a line."), biomes: zod_1.z.array(zod_1.z.string()).optional().describe("Biome IDs in which this feature generates."), rarity: zod_1.z.number().optional().describe("1 in N chunks - lower N = more frequent"), }) .describe("Simplified feature spread. Best for common patterns: ore veins, surface vegetation, tree clusters. " + "Generates the native feature + feature_rule JSONs and places them in the correct folders. " + "Use 'nativeFeature' + 'nativeFeatureRule' on FeatureSchema only when you need raw JSON control (e.g., weighted_random, conditional features)."); /** * Feature definition. */ exports.FeatureSchema = zod_1.z .object({ id: zod_1.z.string().describe("Unique identifier"), displayName: zod_1.z.string().optional(), spread: exports.FeatureSpreadSchema.optional().describe("Simplified feature spread (recommended). Covers 80% of use cases with less boilerplate."), nativeFeature: zod_1.z .record(zod_1.z.any()) .optional() .describe("Escape hatch: raw Minecraft feature JSON (minecraft:scatter_feature, minecraft:ore_feature, etc.). Use only if 'spread' doesn't cover your case."), nativeFeatureRule: zod_1.z .record(zod_1.z.any()) .optional() .describe("Escape hatch: raw Minecraft feature_rule JSON (minecraft:feature_rule). Pair with nativeFeature when you need full control over conditions/distribution."), }) .describe("Feature definition for world generation. Prefer 'spread' over 'nativeFeature'/'nativeFeatureRule' when possible."); // ============================================================================ // LOOT TABLE SCHEMAS // ============================================================================ /** * Loot entry. */ exports.LootEntrySchema = zod_1.z.object({ item: zod_1.z.string().describe("Item ID"), weight: zod_1.z.number().optional().describe("Weight for random selection"), count: zod_1.z.union([zod_1.z.number().int(), zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() })]).optional(), chance: zod_1.z.number().min(0).max(1).optional(), killedByPlayer: zod_1.z.boolean().optional(), lootingBonus: zod_1.z.number().optional(), }); /** * Loot condition. * * Conditions gate when a loot pool is rolled; all conditions in a pool's `conditions` * array must be true (logical AND). Use multiple pools if you need OR semantics. */ exports.LootConditionSchema = zod_1.z.union([ zod_1.z .object({ type: zod_1.z.literal("killed_by_player") }) .describe("Only roll this pool if the entity was killed directly by a player."), zod_1.z .object({ type: zod_1.z.literal("random_chance"), chance: zod_1.z.number() }) .describe("Roll this pool with the given probability (0-1)."), zod_1.z .object({ type: zod_1.z.literal("looting_enchant"), multiplier: zod_1.z.number() }) .describe("Multiply rolls by the Looting enchantment level times the given multiplier."), ]); /** * Loot pool. */ exports.LootPoolSchema = zod_1.z .object({ rolls: zod_1.z .union([zod_1.z.number().int(), zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() })]) .describe("How many entries to pick from this pool (fixed count or {min,max} range)."), entries: zod_1.z.array(exports.LootEntrySchema).describe("Candidate items; `weight` controls relative pick probability."), conditions: zod_1.z .array(exports.LootConditionSchema) .optional() .describe("Gate conditions for this pool. ALL listed conditions must be true (logical AND). " + "Use separate pools if you need OR semantics."), }) .describe("A single loot pool: rolls `rolls` times from `entries` if all `conditions` pass."); /** * Loot table definition. */ exports.LootTableSchema = zod_1.z .object({ id: zod_1.z.string().describe("Unique identifier"), pools: zod_1.z.array(exports.LootPoolSchema).describe("Loot pools"), }) .describe("Loot table definition"); // ============================================================================ // RECIPE SCHEMAS // ============================================================================ /** * Recipe definition. * * The optional fields below are consumed differently per `type`: * - type='shaped' → uses `pattern` + `key`; ignores `ingredients`/`input`/`experience`/`cookTime`. * - type='shapeless' → uses `ingredients`; ignores `pattern`/`key`/`input`/`experience`/`cookTime`. * - type='furnace' → uses `input` (+ optional `experience`, `cookTime`); ignores `pattern`/`key`/`ingredients`. * - type='brewing' → uses `input` + `ingredients[0]` (reagent); other shape fields ignored. * - type='smithing' → uses `input` + `ingredients[0]` (addition); other shape fields ignored. */ exports.RecipeSchema = zod_1.z .object({ id: zod_1.z.string().describe("Unique identifier"), type: zod_1.z .enum(["shaped", "shapeless", "furnace", "brewing", "smithing"]) .describe("Recipe category. Determines which of the remaining fields are used (see RecipeSchema comment). " + "Providing fields that don't apply to the chosen type is ignored (not an error)."), result: zod_1.z .union([zod_1.z.string(), zod_1.z.object({ item: zod_1.z.string(), count: zod_1.z.number().int() })]) .describe("Output item. String = single item ID; object = item + count."), pattern: zod_1.z .array(zod_1.z.string()) .optional() .describe("Pattern for type='shaped' (e.g., ['###', ' | ', ' | ']). Ignored for other types."), key: zod_1.z .record(zod_1.z.string()) .optional() .describe("Key → item-id map for type='shaped' pattern characters. Ignored for other types."), ingredients: zod_1.z .array(zod_1.z.string()) .optional() .describe("Ingredients for type='shapeless'. For 'brewing' and 'smithing', ingredients[0] is the reagent/addition."), input: zod_1.z .string() .optional() .describe("Input item for type='furnace' / 'brewing' / 'smithing'. Ignored for shaped/shapeless."), experience: zod_1.z.number().optional().describe("XP reward for type='furnace'. Ignored for other types."), cookTime: zod_1.z.number().int().optional().describe("Cook time (ticks) for type='furnace'. Ignored for other types."), unlocksWith: zod_1.z.array(zod_1.z.string()).optional().describe("Items that unlock recipe in the recipe book."), }) .describe("Recipe definition. See the RecipeSchema comment for which fields apply to each `type`."); // ============================================================================ // SPAWN RULE SCHEMAS // ============================================================================ /** * Spawn rule definition. * * Top-level spawn rule that can reference any entity ID (custom or vanilla). * Use this form when the rule should live in a separate file or reference an entity * defined outside this pack. For rules tightly bound to a single custom entity, * prefer the inline `entity.spawning` (SpawnConfigSchema) form. */ exports.SpawnRuleSchema = zod_1.z .object({ entity: zod_1.z.string().describe("Entity ID this rule applies to (can be vanilla or custom, namespaced)."), biomes: zod_1.z.array(zod_1.z.string()).optional(), weight: zod_1.z.number().optional(), groupSize: zod_1.z.object({ min: zod_1.z.number().int(), max: zod_1.z.number().int() }).optional(), lightLevel: zod_1.z.object({ min: zod_1.z.number().int().optional(), max: zod_1.z.number().int().optional() }).optional(), heightRange: zod_1.z.object({ min: zod_1.z.number().optional(), max: zod_1.z.number().optional() }).optional(), timeOfDay: zod_1.z.enum(["day", "night", "any"]).optional(), surface: zod_1.z.boolean().optional(), spawnOn: zod_1.z.array(zod_1.z.string()).optional(), populationCap: zod_1.z.number().int().optional(), }) .describe("Top-level spawn rule (emitted as a separate spawn_rules/*.json file). Prefer inline `entity.spawning` " + "for rules bound to a single custom entity; use this form when the rule references a non-local entity " + "or when you want the rule file decoupled from the entity definition."); // ============================================================================ // SHARED RESOURCES // ============================================================================ /** * Sound definition. */ exports.SoundDefinitionSchema = zod_1.z.object({ file: zod_1.z.string().optional(), volume: zod_1.z.number().min(0).max(1).optional(), pitch: zod_1.z.number().optional(), category: zod_1.z.enum(["master", "music", "ambient", "hostile", "neutral", "player"]).optional(), }); /** * Shared resources. */ exports.SharedResourcesSchema = zod_1.z.object({ textures: zod_1.z.record(exports.TextureSpecSchema).optional(), geometries: zod_1.z.record(exports.GeometrySpecSchema).optional(), sounds: zod_1.z.record(exports.SoundDefinitionSchema).optional(), }); // ============================================================================ // GENERATION OPTIONS // ============================================================================ /** * Generation options. */ exports.GenerationOptionsSchema = zod_1.z.object({ generatePlaceholderTextures: zod_1.z.boolean().optional().describe("Auto-generate placeholder textures. Default: true"), generateDefaultGeometry: zod_1.z.boolean().optional().describe("Auto-generate default geometry. Default: true"), createDefaultSpawnRules: zod_1.z.boolean().optional().describe("Auto-create spawn rules. Default: false"), createLootTablesFromDrops: zod_1.z.boolean().optional().describe("Create loot tables from drops. Default: true"), textureResolution: zod_1.z .union([zod_1.z.literal(1), zod_1.z.literal(2), zod_1.z.literal(4)]) .optional() .describe("Pixels per unit. Default: 2"), }); // ============================================================================ // ROOT SCHEMA // ============================================================================ /** * Complete Minecraft content definition schema. */ exports.MinecraftContentSchema = zod_1.z .object({ schemaVersion: zod_1.z.literal("1.0.0").describe("Schema version"), namespace: zod_1.z .string() .optional() .describe("Namespace for all content (e.g., 'orc_dungeon'). Optional if adding to existing project"), displayName: zod_1.z.string().optional().describe("Human-readable pack name"), description: zod_1.z.string().optional().describe("Pack description"), entityTypes: zod_1.z.array(exports.EntityTypeSchema).optional().describe("Entity type definitions"), blockTypes: zod_1.z.array(exports.BlockTypeSchema).optional().describe("Block type definitions"), itemTypes: zod_1.z.array(exports.ItemTypeSchema).optional().describe("Item type definitions"), structures: zod_1.z.array(exports.StructureSchema).optional().describe("Structure definitions"), features: zod_1.z.array(exports.FeatureSchema).optional().describe("Feature definitions for world generation"), lootTables: zod_1.z.array(exports.LootTableSchema).optional().describe("Loot table definitions"), recipes: zod_1.z.array(exports.RecipeSchema).optional().describe("Recipe definitions"), spawnRules: zod_1.z.array(exports.SpawnRuleSchema).optional().describe("Spawn rule definitions"), sharedResources: exports.SharedResourcesSchema.optional().describe("Resources shared by multiple content items"), options: exports.GenerationOptionsSchema.optional().describe("Generation options"), }) .describe("Minecraft content meta-schema - a simplified format for AI-friendly content creation. " + "Supports traits (pre-packaged bundles), simplified properties, and native Minecraft components.");