Skip to content

Items

Lesson 12.1

Time to add something new to the game: an item of your own. An item needs two parts: a registration in your script, so the game knows it exists, and assets, so it has a name and a picture.

Registering an item

cl.on("lifecycle.register", function()
  cl.items.register{
    id = "ruby",
    creative_tab = "minecraft:ingredients",
    vanilla_fallback = "minecraft:emerald",
  }
end)
  • Items are registered in the lifecycle.register event, once, while the game starts. After that the list of items is frozen, and registering raises a wrong_phase error.
  • id = "ruby" becomes my_mod:ruby: an id without a : gets your mod id in front. You can only register in your own namespace.
  • creative_tab puts it into a creative inventory tab.
  • vanilla_fallback is the vanilla item that players without your mod see instead.

cl.items.register{ ... } is a function call with a table, the shortcut from part 1. It returns the registered entry; its id field is the full id, "my_mod:ruby".

Since registration only happens at startup, a new or changed item needs a game restart. Hot reload logs restart required and keeps the old one.

Item options

Field Default Means
id The item’s id. Required.
max_stack_size 64 How many fit in one slot, 1 to 99. Use 1 for tools.
creative_tab none "minecraft:ingredients", "minecraft:tools_and_utilities", "minecraft:combat", "minecraft:food_and_drinks", "minecraft:building_blocks", …
vanilla_fallback "minecraft:paper" What players without the mod see.
copy_from none A vanilla item to base this one on, when there is no fallback.
behavior none Your own code for using the item (below).

Assets: name and picture

The game finds an item’s look by its id. For my_mod:ruby it needs these files:

assets/my_mod/
  items/ruby.json            which model to use
  models/item/ruby.json      the model
  textures/item/ruby.png     the picture, 16 x 16 pixels
  lang/en_us.json            the name

items/ruby.json points at the model:

{
  "model": {
    "type": "minecraft:model",
    "model": "my_mod:item/ruby"
  }
}

models/item/ruby.json says “a flat item with this texture”, the same as most vanilla items:

{
  "parent": "minecraft:item/generated",
  "textures": {
    "layer0": "my_mod:item/ruby"
  }
}

And the name goes into the language file. Item keys are item.<mod id>.<name>:

{
  "item.my_mod.ruby": "Ruby"
}

These are the same files a resource pack uses, so everything you know about resource packs works here. A missing texture shows the purple and black checkerboard; a missing name shows the key.

Using it in code

Your item is a normal item now. Everything from Players works with it:

player:give("my_mod:ruby", 5)

if player:held_item().id == "my_mod:ruby" then
  player:send_message("Shiny!")
end

Behaviour: when the item is used

behavior gives the item its own code. Right now an item can react to use: the player right-clicks with it in hand.

cl.on("lifecycle.register", function()
  cl.items.register{
    id = "heal_crystal",
    max_stack_size = 16,
    creative_tab = "minecraft:tools_and_utilities",
    behavior = {
      use = function(ctx)
        local player = ctx.entity
        player:set_health(20)
        player:send_action_bar("You feel better.")
        return "success"
      end,
    },
  }
end)

use gets one table, ctx, with:

Field Means
ctx.entity The player using the item.
ctx.level The world it happens in.
ctx.hand "main" or "off".
ctx.stack The item stack being used.

The return value says what happened:

  • "success": the use worked; the arm swings.
  • "consume": it worked, without the swing.
  • "fail": it was refused.
  • nil (no return): your code did nothing, so the game handles the click as for the fallback item.

Unlike registrations, the behaviour’s code reloads: change the body of use, save, and the next right-click runs the new code.

An item can use itself up. ctx.entity:held_item(ctx.hand) is the live slot the item is in, so shrink takes one away, like eating an apple:

use = function(ctx)
  local player = ctx.entity
  player:set_health(20)
  player:held_item(ctx.hand):shrink(1)   -- one crystal is used up
  return "success"
end,

Players has the other ways to take items.

Try it

Register an item my_mod:compass_stone with a stack size of 1 in the tools tab. When it is used, it tells the player their coordinates in the action bar, like x 12, y 64, z -30. Add the language entry too.

Show a solution
cl.on("lifecycle.register", function()
  cl.items.register{
    id = "compass_stone",
    max_stack_size = 1,
    creative_tab = "minecraft:tools_and_utilities",
    vanilla_fallback = "minecraft:flint",
    behavior = {
      use = function(ctx)
        local p = ctx.entity.pos
        ctx.entity:send_action_bar(("x %d, y %d, z %d"):format(math.floor(p.x), math.floor(p.y), math.floor(p.z)))
        return "success"
      end,
    },
  }
end)

assets/my_mod/lang/en_us.json:

{
  "item.my_mod.compass_stone": "Compass Stone"
}

Without a texture it shows the checkerboard, which is fine for testing. Add items/, models/item/ and textures/item/ files like the ruby’s when you have a picture.

Recap: register items in lifecycle.register with cl.items.register{ id = ... }, give them a model, texture and name under assets/<mod id>/, and add behavior.use for right-click code.