Skip to content

Custom Items

Dan Alexander edited this page Nov 3, 2026 · 1 revision

Custom items and inheritance

Defining items using VoxelCore content IDs, render metadata and inherited configuration.

Documentation for VoxelCore v1.0.0. Home · Installation · Compatibility

Item authoring

items:
  gem_base:
    abstract: true
    material: minecraft:paper
    bound: false
    lore:
      - Shared values for inherited gemstone definitions

  ruby:
    extends: gem_base
    abstract: false
    display_name: Ruby
    bound: false
    render:
      model: mypack:item/ruby
      unbreakable: true
      durability: 0
      attributes:
        hide_attributes: true
      custom_model_data: 1001
    properties:
      category: gemstone

Supported item fields:

  • extends
  • type
  • material
  • display_name
  • lore
  • bound
  • abstract
  • render
  • properties
  • events

Unknown keys and malformed values are rejected rather than ignored.

Abstract definitions and bound state

abstract is an inherited scalar for reusable definitions that must not become game items. A resolved abstract: true definition remains available as an inheritance parent and through item info, but it is hidden from item list and cannot be created by item give or item verify. Abstract definitions with both material and render.model receive a stable render allocation and pack model for addon use (for example VoxelFurniture neighbor variants); the internal ItemManager.createRenderItem API is not a player give command. Abstract definitions without a render model may omit material; concrete definitions may not.

Because abstract is inherited, a concrete child of an abstract parent must explicitly set abstract: false.

bound is independent of abstraction and visibility. It remains inherited item metadata intended for future ownership restrictions; full bound-item inventory, drop, death, container, trade, and cross-server transfer enforcement is not implemented yet.

Identity

Persistent gameplay identity is a namespaced ContentID, for example:

mypack:ruby

It is independent of Custom Model Data and model paths. IDs are normalized to lowercase and each namespace/value segment uses [a-z0-9._-]+.

Inheritance

VoxelCore currently supports one parent per item. Resolution is bounded and cycle-aware: missing parents, duplicate IDs, and circular inheritance fail compilation.

Merge behavior:

  • omitted scalar → inherit parent
  • provided scalar → replace parent
  • explicit false → replaces inherited true
  • list → child replaces parent list
  • properties maps → recursive deep merge; explicit null clears inherited keys
  • render metadata → field-by-field merge; render.rule maps also merge recursively
  • structured custom_model_data → semantic-key merge when both sides are structured
  • events → merge by event path; a child's actions list replaces only that event's list, while explicitly empty events: {} disables all inherited event actions

Child-authored values always take precedence in the compiled definition. An addon should read the resolved ItemDefinition.properties() from VoxelCore rather than reimplementing inheritance. In nested property maps, omitted keys inherit; a child-authored map merges recursively, a child-authored list replaces the parent list, and false, 0, an empty string, or explicit null replaces a parent value. This makes optional capabilities (for example, properties.vehicle: null on render-only descendants) possible without special cases in the addon.

Item identity vs. inherited references: A literal property such as vehicle.model_item: voxel:tractor is an explicit reference and remains voxel:tractor in tractor-yellow unless overridden. When the addon provides a current-item-ID default, omit model_item (and drop) from the base item so variants naturally use their own IDs.

Compiled definitions and nested property/render-rule structures are immutable.

Rendering

Rendering state is separate from item identity.

Common render metadata

render:
  model: mypack:item/ruby
  unbreakable: true
  durability: 4
  attributes:
    hide_attributes: true
  custom_model_data: 1001

attributes currently maps to Bukkit ItemFlag names. It is not the future combat AttributeModifier system.

durability is independent of custom_model_data. Before 1.14, Custom Model Data has no runtime representation; legacy resource-pack damage predicates use explicit render.durability.

Structured Custom Model Data — 1.21.4

render:
  model: mypack:item/ruby
  custom_model_data:
    variant: red
    powered: true
    intensity: 0.75
    tint: '#ff0000'

VoxelCore allocates stable typed indices for semantic keys in render-allocations.yml; adding/removing a key does not renumber existing keys.

The inferred types are:

  • number → float
  • boolean → flag
  • ordinary string → string
  • #RRGGBB → color

Modern render rules — 1.21.4

render.rule tells the generated item-model graph how to read structured state:

render:
  model: mypack:item/ruby
  custom_model_data:
    variant: red
    powered: true
    intensity: 0.75
    tint: '#ff0000'
  rule:
    select:
      key: variant
      cases:
        red:
          condition:
            key: powered
            true:
              range:
                key: intensity
                entries:
                  0.75:
                    model:
                      id: mypack:item/ruby_powered
                      tint: tint
                fallback: mypack:item/ruby
            false: mypack:item/ruby
      fallback: mypack:item/ruby

Rule nodes support select, condition, range, and model. Pre-1.21.4 pack targets reject render.rule rather than silently discarding it.

Dyeable custom items — 1.21.4+

An item whose model faces use tintindex: 0 can expose a mutable per-stack colour:

render:
  model: voxel:furniture/curtain/curtain_closed
  custom_model_data:
    color: '#FFFFFF'
  rule:
    model:
      id: voxel:furniture/curtain/curtain_closed
      tint: color
properties:
  dyeable:
    key: color
    color: '#FFFFFF'

Players can place a vanilla dye onto the item in an inventory to recolour it. The selected RGB value is stored in structured Custom Model Data, so the content ID remains unchanged and differently coloured stacks remain variants of the same item. Addons can use ItemManager.getDyeColor, setDyeColor, and createRenderItem(id, source) to preserve the mutable colour in their own renderers. Dynamic tinting is disabled safely before 1.21.4.

Stable render allocations

plugins/VoxelCore/render-allocations.yml is the shared authority for runtime item creation and pack compilation. The current manifest schema is 3.

It persists:

  • numeric Custom Model Data allocations
  • inactive tombstones so removed IDs do not silently recycle allocations
  • model association
  • stable structured float/flag/string/color semantic-key indices

Do not casually delete this file on a live content set: doing so discards allocation history.

Clone this wiki locally