Item Registry

Adding new items to game


Custom items are created in a startup script. They cannot be reloaded without restarting the game. The event is not cancellable.
// Listen to item registry event
StartupEvents.registry('item', event => {
  // The texture for this item has to be placed in kubejs/assets/kubejs/textures/item/test_item.png
  // If you want a custom item model, you can create one in Blockbench and put it in kubejs/assets/kubejs/models/item/test_item.json
  event.create('test_item')

  // If you want to specify a different texture location you can do that too, like this:
  event.create('test_item_1').texture('mobbo:item/lava') // This texture would be located at kubejs/assets/mobbo/textures/item/lava.png

  // You can chain builder methods as much as you like
  event.create('test_item_2').maxStackSize(16).glow(true)

  // You can specify item type as 2nd argument in create(), some types have different available methods
  event.create('custom_sword', 'sword').tier('diamond').attackDamageBaseline(10.0)
})
Valid item types:
  • 'basic' (this is the default)
  • 'sword'
  • 'pickaxe'
  • 'axe'
  • 'shovel'
  • 'shears'
  • 'hoe'
  • 'helmet'
  • 'chestplate'
  • 'leggings'
  • 'boots'
Other methods item builder supports (you can chain these methods after create()):
  • maxStackSize(size)
  • unstackable() Identical to maxStackSize(1)
  • maxDamage(damage)
  • burnTime(ticks)
  • fireResistant(true/false)
  • rarity(rarity)
  • glow(true/false)
  • tooltip(text...)
  • color(index, colorHex)
  • color((itemstack, tintIndex) => ...)
  • displayName(name)
  • name(itemstack => ...)
  • translationKey(key)
  • textureJson(json)
  • modelJson(json)
  • parentModel(customParentModelLocation)
  • texture(customTextureLocation)
  • texture(key, customTextureLocation)
  • barColor(itemstack => ...)
  • barWidth(itemstack => ...)
  • useAnimation(animation)
  • useDuration(itemstack => ...)
  • use((level, player, hand) => ...)
  • finishUsing((itemstack, level, entity) => ...)
  • releaseUsing((itemstack, level, entity, tick) => ...)
  • tag(resourceLocation)
  • modifyAttribute(attribute, identifier, d, operation)
  • group(groupId)
  • containerItem(itemId)
  • subtypes(itemstack => ...)
  • food(foodBuilder => ...) For full syntax see below
Old/Removed methods:
  • type(type) - 1.16 and 1.18
  • tool(type, level) - 1.16
Methods available if you use a tool type ('sword', 'pickaxe', 'axe', 'shovel' or 'hoe'):
  • tier(toolTier)
  • modifyTier(tier => ...) Same syntax as custom tool tier, see Custom Tiers
  • attackDamageBaseline(damage) You only want to modify this if you are creating a custom weapon such as Spear, Battleaxe, etc.
  • attackDamageBonus(damage)
  • speedBaseline(speed) Same as attackDamageBaseline, only modify for custom weapon types
  • speed(speed)
Default available tool tiers:
  • 'wood'
  • 'stone'
  • 'iron'
  • 'gold'
  • 'diamond'
  • 'netherite'
Methods available if you use an armor type ('helmet', 'chestplate', 'leggings' or 'boots'):
  • tier(armorTier)
  • modifyTier(tier => ...) Same syntax as custom armor tier, see Custom Tiers
Default available armor tiers:
  • 'leather'
  • 'chainmail'
  • 'iron'
  • 'gold'
  • 'diamond'
  • 'turtle'
  • 'netherite'
Vanilla group/creative tab IDs:
  • 'search'
  • 'buildingBlocks'
  • 'decorations'
  • 'redstone'
  • 'transportation'
  • 'misc'
  • 'food'
  • 'tools'
  • 'combat'
  • 'brewing'

#Examples

#Custom Foods

StartupEvents.registry('item', event => {
  event.create('magic_steak').food(food => {
    food
      .hunger(6)
      .saturation(6) // This value does not directly translate to saturation points gained
      // The real value can be assumed to be:
      // min(hunger * saturation * 2 + saturation, foodAmountAfterEating)
      .effect('minecraft:speed', 600, 0, 1)
      .removeEffect('minecraft:poison')
      .alwaysEdible() // Like golden apples
      .fastToEat() // Like dried kelp
      .meat() // Dogs are willing to eat it
      .eaten(ctx => {
        // runs code upon consumption
        ctx.player.tell(Text.gold('Yummy Yummy!'))
        // If you want to modify this code then you need to restart the game.
        // However, if you make this code call a global startup function
        // and place the function *outside* of an event handler
        // then you may use the command:
        // /kubejs reload startup_scripts
        // to reload the function instantly.
        // See example below
      })
  })

  event.create('magicer_steak')
    .unstackable()
    .food(food =>
      food
        .hunger(7)
        .saturation(7)
        // This references the function below instead of having code directly, so it is reloadable!
        .eaten(ctx => global.myAwesomeReloadableFunction(ctx))
    )
})

global.myAwesomeReloadableFunction = ctx => {
  ctx.player.tell('Hello there!')
  ctx.player.tell(Text.of('Change me then reload with ').append(Text.red('/kubejs reload startup_scripts')).append(' to see your changes!'))
}

#Custom Uses

StartupEvents.registry('item', event => {
  event.create('nuke_soda', 'basic')
    .tooltip('§5Taste of Explosion!')
    .tooltip('§c...Inappropriate intake may cause disastrous result.')
    /**
     * The use animation of the item, can be  "spear" (trident),
     * "crossbow", "eat" (food), "spyglass", "block", "none", "bow", "drink"
     * When using certain animations, corresponding sound will be played.
     */
    .useAnimation('drink')
    /**
     * The duration before the item finishs its using,
     * if you need something like hold-and-charge time (like bow),
     * consider set this to 72000 (1h) or more.
     * A returned value of 0 or lower will render the item not usable.
     */
    .useDuration(itemstack => 64)
    /**
     * When item is about to be used.
     * If true, item will starts it use animation if duration > 0.
     */
    .use((level, player, hand) => true)
    // When the item use duration expires.
    .finishUsing((itemstack, level, entity) => {
      let effects = entity.potionEffects
      effects.add('minecraft:haste', 120 * 20)
      itemstack.itemStack.shrink(1)
      if (entity.player) {
        entity.minecraftPlayer.addItem(Item.of('minecraft:glass_bottle').itemStack)
      }
      return itemstack
    })
    /**
     * When the duration is not expired yet, but
     * players release their right button.
     * Tick is how many ticks remained for player to finish using the item.
     */
    .releaseUsing((itemstack, level, entity, tick) => {
      itemstack.itemStack.shrink(1)
      level.createExplosion(entity.x, entity.y, entity.z).explode()
    })
})

#Bar

StartupEvents.registry('item', event => {
  event.create('hammer')
    /**
     * Determine how long the bar is, should be an integer between 0 (empty) and 13 (full)
     * If the value is below 0, it will be treated as 0.
     * The value is capped at 13, any value over 13 will be considered "full", thus making it not shown
     */
    .barWidth(itemstack => itemstack.nbt.contains('hit_count') ? itemstack.nbt.getInt('hit_count') / 13.0 : 0)
    // Determine what color should the bar be.
    .barColor(itemstack => Color.AQUA)
})

#Dynamic Tinting and Model Stuff

StartupEvents.registry('item', event => {
  // Old style with just setting color by index still works!
  event.create('old_color_by_index')
    .textureJson({
      layer0: 'minecraft:item/paper',
      layer1: 'minecraft:item/ghast_tear'
    })
    .color(0, '#70F00F')
    .color(1, '#00FFF0')

  event.create('cooler_sword', 'sword')
    .displayName('Test Cooler Sword')
    .texture('minecraft:item/iron_sword')
    /**
     * Example by storing the color in the nbt of the itemstack
     * You have to return -1 to apply no tint.
     *
     * You can test this through: /give @p kubejs:cooler_sword{color:"#ff0000"}
     */
    .color(itemstack => itemstack.nbt && itemstack.nbt.color ? itemstack.nbt.color : -1)

  event.create('test_item')
    .displayName('Test Item')
    .textureJson({
      layer0: 'minecraft:item/beef',
      layer1: 'minecraft:item/ghast_tear'
    })
    /**
     * If you want to apply the color to a specific layer, you can use the tintIndex
     * tintIndex is the texture layer index from the model: layer0 -> 0, layer1 -> 1, etc.
     * U can use the `Color` wrapper for some default colors
     *
     * This example will apply the color to the ghast_tear texture.
     */
    .color((itemstack, tintIndex) => tintIndex == 1 ? Color.BLUE : -1)

  // Set a texture for a specific layer
  event.create('test_sword', 'sword')
    .displayName('Test Sword')
    .texture('layer0', 'minecraft:item/bell')

  // Directly set your custom model json
  event.create('test_something')
    .displayName('Test something')
    .modelJson({
      parent: 'minecraft:block/anvil'
    })
})