AgentSkillsCN

mcdoc-language

全面介绍 mcdoc 模式语言,用于描述 Minecraft 数据结构(CODECs、JSONs、NBTs)。当用户需要处理 .mcdoc 文件、编写数据结构模式、理解类型定义、设计分发系统,或验证 Minecraft 数据格式时,此方案可提供有力支持。

SKILL.md
--- frontmatter
name: mcdoc-language
description: Comprehensive guide to the mcdoc schema language for describing Minecraft data structures (CODECs, JSONs, NBTs). Use when working with .mcdoc files, writing schemas, understanding type definitions, dispatch systems, or validating Minecraft data formats.

mcdoc Language Guide

mcdoc is a schema format for describing data structures used by Minecraft, including its CODECs, JSONs, and NBTs. It is interpreted by the Spyglass language server.

Core Concepts

Primitive Types

  • boolean - true/false values
  • byte, short, int, long - Integer types (use suffix: 0b, 0s, 0, 0L)
  • float, double - Floating-point types
  • string - Text values
  • any - Accepts any value (use sparingly)

Struct Definitions

Structs define composite types with named fields:

mcdoc
struct EntityData {
    id: string,              // Required field
    pos?: [double] @ 3,      // Optional field (note the ?)
    /// Doc comment shown in hover
    custom_name?: string,
}

Enum Definitions

Enums define fixed sets of values with a backing type:

mcdoc
enum(string) Direction {
    Down = "down",
    Up = "up",
    North = "north",
}

enum(byte) DyeColorByte {
    White = 0,
    Orange = 1,
}

Type Aliases

Type aliases create named references to types, optionally with generics:

mcdoc
type Text = ::java::util::text::Text

type Tag<E> = struct {
    replace?: boolean,
    values: [TagEntry<E>],
}

Union Types

Union types allow a value to be one of several types (using |):

mcdoc
type Color = (
    #[color="hex_rgb"] string |
    #[color="composite_rgb"] int |
)

Arrays and Collections

mcdoc
[Type]           // Array of any length
[Type] @ 3       // Array of exactly 3 elements
[Type] @ 1..5    // Array with 1-5 elements
[Type] @ 1..     // Array with 1+ elements

Numeric Constraints

mcdoc
int @ 0..100       // Inclusive range (0 to 100)
float @ 0<..1      // Exclusive lower bound (>0, <=1)
float @ 0..<1      // Exclusive upper bound (>=0, <1)
int @ 0..          // Minimum only (0 or greater)

Dispatch System

Dispatches map registry entries to specific type schemas:

mcdoc
// Direct dispatch
dispatch minecraft:entity[zombie] to struct Zombie {
    ...super::Monster,
    CanBreakDoors?: boolean,
}

// Multiple keys to same type
dispatch minecraft:item[potion, splash_potion, lingering_potion] to struct PotionItem {
    Potion?: #[id="potion"] string,
}

// Polymorphic dispatch using a type field
struct TreeDecorator {
    type: #[id="worldgen/tree_decorator_type"] string,
    ...minecraft:tree_decorator[[type]],  // Dispatch based on type field value
}

Special Dispatch Keys

  • %unknown - Fallback for unrecognized keys
  • %none - When no key is specified
  • %fallback - Used in NBT path references

Path Variables

Path variables reference values from the data structure in dispatch keys:

  • %parent - The containing struct (chain for ancestors: %parent.%parent)
  • %key - The current map key (in mapped types)
mcdoc
struct CopyState {
    block: #[id="block"] string,
    properties: [mcdoc:block_state_keys[[%parent.block]]],  // References sibling field
}

// Arrays don't count as levels - %parent skips over them
struct Container {
    modifier: ModifierType,
    items: [struct {
        value: minecraft:modifier[[%parent.%parent.modifier]],  // %parent.%parent = Container
    }],
}

Generic Dispatchers

Dispatchers can have type parameters:

mcdoc
// Define generic dispatcher
dispatch minecraft:int_provider[constant]<T> to struct {
    value: T,
}

dispatch minecraft:int_provider[uniform]<T> to struct {
    min_inclusive: T,
    max_inclusive: T,
}

// Use with type parameter passed through
type IntProvider<T> = (
    T |
    struct {
        type: #[id="int_provider_type"] string,
        ...minecraft:int_provider[[type]]<T>,
    } |
)

// Usage with constrained type
log_length: IntProvider<int @ 0..16>,

Structural Composition

Spread Operator

The spread operator (...) includes fields from another struct:

mcdoc
struct Monster {
    Health?: float,
}

dispatch minecraft:entity[zombie] to struct Zombie {
    ...super::Monster,       // Include Monster fields
    CanBreakDoors?: boolean, // Add zombie-specific fields
}

Inline Structs

Structs can be defined inline within fields:

mcdoc
struct Container {
    items: [struct SlottedItem {
        Slot: byte,
        ...ItemStack,
    }],
}

Attributes

Attributes provide metadata using #[name] or #[name="value"] syntax:

Version Control

mcdoc
#[since="1.20"]           // Available from version 1.20
#[until="1.21"]           // Removed in version 1.21
#[deprecated="1.19"]      // Deprecated since 1.19

Registry References

mcdoc
#[id="item"] string                           // Reference to item registry
#[id(registry="block",tags="allowed")] string // Allow tags
#[id(registry="texture",path="entity/")] string // Path prefix

Validation

mcdoc
#[color="composite_rgb"] int    // RGB color as integer
#[color="hex_rgb"] string       // Hex color string
#[regex_pattern] string         // Regex pattern
#[uuid] string                  // UUID format
#[nbt=minecraft:item[[item]]] string // NBT validation

Other Attributes

mcdoc
#[canonical]              // Preferred form in a union
#[id]                     // Mark as identifier

Module System

Use Statements

mcdoc
use ::java::util::text::Text           // Absolute path
use super::block_state::BlockState     // Parent directory
use super::super::HeightmapType        // Grandparent

Module Resolution

A path like use modifier::Type resolves to either:

  • modifier.mcdoc (single-file module) — check first
  • modifier/mod.mcdoc (directory module)

Path Conventions

  • :: prefix for absolute paths from root
  • super:: for parent module
  • No prefix for sibling imports

Mapped Types (String Maps)

Define structs with dynamic string keys:

mcdoc
struct Lang {
    [#[translation_key(definition=true)] string]: #[translation_value] string,
}

struct Criteria {
    [#[criterion(definition=true)] string]: AdvancementCriterion,
}

Comments

mcdoc
// Single-line comment (not included in output)

/// Doc comment (appears in hover/autocomplete)
/// Multiple lines supported
field_name: Type,

Best Practices

  1. Naming: Use PascalCase for NBT/CODEC structs, snake_case for JSON fields
  2. Avoid unnecessary doc comments - Only document complex or non-obvious fields
  3. Use string enums when a string union changes between MC versions
  4. Always name dispatched structs - Named types for all dispatch targets
  5. Limit nesting to 3 levels - Extract deeply nested structs
  6. Use spread operator to avoid code repetition

Additional Resources