@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
939 lines (938 loc) • 48.9 kB
JavaScript
"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.");