Inventory and items
inventory is game.inventory() — the 36 main slots plus the four armor slots and the off-hand. Reads are free; every mutation is queued onto the client's move queue and needs the client thread.
on<PrePlayerTickEvent> {
val slot = inventory.find("golden_apple")
if (!slot.found() || inventory.busy()) return@on
val stack = inventory.item(slot)
chat.print("${stack.count()} x ${stack.name()}")
inventory.shiftClick(slot)
}Addressing a slot
| Method | Type | Description |
|---|---|---|
Slot.hotbar(index) |
Slot |
hotbar slot by index (throws ScriptException outside 0..8) |
Slot.inventory(index) |
Slot |
main-inventory slot, below 9 yields kind HOTBAR (throws ScriptException outside 0..35) |
Slot.armor(slot) |
Slot |
armor slot from an ArmorSlot (throws ScriptException on null) |
Slot.offhand() |
Slot |
the off-hand slot |
Slot.NONE |
Slot |
not-found constant, kind NONE and index -1 |
Slot.HOTBAR_SIZE |
int |
constant 9 |
Slot.MAIN_SIZE |
int |
constant 36 |
slot.kind() |
Slot.Kind |
which part of the inventory the slot addresses |
slot.index() |
int |
index inside the kind, -1 for NONE, ArmorSlot ordinal for ARMOR |
slot.found() |
boolean |
kind is not NONE |
slot.inHotbar() |
boolean |
kind is HOTBAR |
slot.isArmor() |
boolean |
kind is ARMOR |
slot.isOffhand() |
boolean |
kind is OFFHAND |
slot.hotbarIndex() |
int |
hotbar index 0..8, -1 when not a hotbar slot |
slot.armorSlot() |
ArmorSlot? |
the armor slot, null when kind is not ARMOR |
slot.toString() |
String |
none, hotbar N, inventory N, armor HELMET or offhand |
Slot.Kind
| Constant | Description |
|---|---|
NONE |
not found or absent slot |
HOTBAR |
hotbar, index 0..8 |
INVENTORY |
main inventory, index 9..35 |
ARMOR |
armor slot, index is the ArmorSlot ordinal |
OFFHAND |
off-hand slot, index 0 |
ArmorSlot
| Constant | Description |
|---|---|
HELMET |
head slot, ordinal 0 |
CHESTPLATE |
chest slot, ordinal 1 |
LEGGINGS |
legs slot, ordinal 2 |
BOOTS |
feet slot, ordinal 3 |
Reading
| Method | Type | Description |
|---|---|---|
inventory.held() |
Item |
main-hand stack, empty item when nothing held |
inventory.offhand() |
Item |
off-hand stack |
inventory.item(slot) |
Item |
stack in that slot (throws ScriptStateException on a not-found slot) |
inventory.armor(slot) |
Item |
equipped stack in that armor slot (throws ScriptException on null) |
inventory.items() |
List<Item> |
immutable list of the 36 main stacks in index order |
inventory.selected() |
Slot |
currently selected hotbar slot |
inventory.count(itemId) |
int |
total count of that item across the 36 main slots |
inventory.full() |
boolean |
no empty stack among the 36 main slots |
inventory.empty() |
boolean |
all 36 main slots are empty |
inventory.wearing(itemId) |
boolean |
that item is equipped in one of the four armor slots |
Item ids default to the minecraft: namespace, so "mace" and "minecraft:mace" are the same id.
No read returns null: an absent stack comes back as an item whose empty() is true.
Searching
| Method | Type | Description |
|---|---|---|
inventory.find(itemId) |
Slot |
first main-inventory slot holding that item, Slot.NONE when absent |
inventory.find(filter) |
Slot |
first main-inventory slot passing the filter (throws ScriptException on a null filter) |
inventory.findByTag(tagId) |
Slot |
first main-inventory slot in that item tag, leading # stripped |
inventory.findInHotbar(itemId) |
Slot |
first hotbar slot 0..8 holding that item |
inventory.findInHotbar(filter) |
Slot |
first hotbar slot 0..8 passing the filter |
inventory.findUsable(filter) |
Slot |
first matching slot that is non-empty and not on cooldown |
inventory.findAll(filter) |
List<Slot> |
every matching main-inventory slot in index order |
Moving things
| Method | Type | Description |
|---|---|---|
inventory.click(slot, rightButton) |
void |
queues a PICKUP click, button 1 when rightButton (main thread only) |
inventory.shiftClick(slot) |
void |
queues a QUICK_MOVE click (main thread only) |
inventory.swap(slot, hotbarSlot) |
void |
queues a SWAP into that hotbar slot (main thread only) (throws ScriptException when hotbarSlot is not a hotbar slot) |
inventory.drop(slot, wholeStack) |
void |
queues a THROW, button 1 for the whole stack (main thread only) |
inventory.dropHeld(wholeStack) |
void |
drops the selected hotbar stack directly (main thread only) |
inventory.batch(actions) |
void |
enqueues the collected actions as one move sequence (main thread only) |
inventory.busy() |
boolean |
the client inventory-move queue is non-empty |
Inventory.Batch
| Method | Type | Description |
|---|---|---|
batch.click(slot, rightButton) |
Batch |
appends a PICKUP click |
batch.shiftClick(slot) |
Batch |
appends a QUICK_MOVE click |
batch.swap(slot, hotbarSlot) |
Batch |
appends a SWAP (throws ScriptException when hotbarSlot is not a hotbar slot) |
batch.drop(slot, wholeStack) |
Batch |
appends a THROW, button 1 for the whole stack |
batch.delay(ticks) |
Batch |
appends a pause in game ticks (throws ScriptException when ticks is 0 or less) |
batch.onFinish(action) |
Batch |
runs the action when the queue closes (API 2) (throws ScriptException when action is null) |
Every mutation needs an open screen handler, and with a non-player screen open the ARMOR and OFFHAND slots throw ScriptStateException; a batch does not block, its queue drains over the following ticks.
Slots of an open chest or server menu are addressed by Containers; switching the held hotbar slot is Slots and armor.
The stack
| Method | Type | Description |
|---|---|---|
item.empty() |
boolean |
the stack is empty |
item.id() |
String |
namespaced item id, minecraft:air for an empty stack |
item.name() |
String |
plain display name |
item.count() |
int |
stack size |
item.maxCount() |
int |
maximum stack size |
item.damage() |
int |
current damage value |
item.maxDamage() |
int |
maximum durability, 0 when not damageable |
item.damageable() |
boolean |
stack can take durability damage |
item.stackable() |
boolean |
stack can hold more than one item |
item.unbreakable() |
boolean |
has the UNBREAKABLE component |
item.enchanted() |
boolean |
has at least one enchantment |
item.rarity() |
Rarity |
vanilla stack rarity |
item.isA(itemId) |
boolean |
id matches, false for an empty stack |
item.hasTag(tagId) |
boolean |
item is in that tag, leading # stripped |
What it can do
| Method | Type | Description |
|---|---|---|
item.placeable() |
boolean |
BlockItem whose default state has a collision shape |
item.buildable() |
boolean |
BlockItem: full cube, no block entity, default friction/multipliers, not falling or magma (API 2) |
item.food() |
boolean |
has the FOOD component |
item.nutrition() |
int |
food nutrition points, 0 when not food |
item.saturation() |
float |
food saturation value, 0 when not food |
item.useAction() |
String |
lowercase use action: none, eat, bow, block |
item.disablesBlocking() |
boolean |
WEAPON component disables shield blocking |
item.enchantments() |
Map<String, Integer> |
namespaced enchantment id to level, insertion-ordered |
item.enchantmentLevel(id) |
int |
level for that id, 0 when absent, minecraft: added when unqualified (throws ScriptException when the id is blank) |
item.attributeModifiers() |
List<AttributeModifier> |
ATTRIBUTE_MODIFIERS entries, empty when absent |
item.containerItems() |
List<Item> |
CONTAINER contents, else BUNDLE_CONTENTS, else empty |
AttributeModifier
| Method | Type | Description |
|---|---|---|
modifier.attribute() |
String |
namespaced attribute id the modifier applies to |
modifier.id() |
String |
modifier identifier |
modifier.value() |
double |
modifier amount |
modifier.operation() |
String |
add_value, add_multiplied_base or add_multiplied_total |
modifier.slot() |
String |
equipment-slot group: any, mainhand, head |
Cooldowns
| Method | Type | Description |
|---|---|---|
item.onCooldown() |
boolean |
this stack's cooldown group is cooling down, false out of world |
item.cooldownProgress() |
float |
remaining cooldown fraction at tickDelta 0, counts down 1..0 (API 2) |
item.cooldownProgress(tickDelta) |
float |
the same fraction interpolated by tickDelta, 1..0 (API 2) |
item.setCooldown(ticks) |
void |
client-side cooldown of that many ticks, 0 or less removes it (API 2) (main thread only) (throws ScriptStateException when out of world) |
item.removeCooldown() |
void |
clears this group's client-side cooldown (API 2) (main thread only) (throws ScriptStateException when out of world) |
A cooldown belongs to the item's cooldown group, not to the stack, so every stack of that item reports the same value.
setCooldown and removeCooldown write only the client's copy; the server keeps its own, and the next cooldown packet for that group overwrites yours.
Names, lore, components
| Method | Type | Description |
|---|---|---|
item.displayName() |
Text |
styled display name |
item.customName() |
String? |
plain CUSTOM_NAME text, null when absent |
item.lore() |
List<Text> |
styled LORE lines, empty when absent |
item.tooltip(advanced) |
List<Text> |
vanilla tooltip lines, F3+H version when advanced is true |
item.tags() |
List<String> |
namespaced item tag ids on this item |
item.hasComponent(id) |
boolean |
data component present, false for an unknown id |
item.component(id) |
String? |
toString() of the component value, null when absent |
item.nbt() |
String |
CUSTOM_DATA compound as text, empty string when absent |
item.customData(key) |
String? |
string value of that key in CUSTOM_DATA, null when missing |
Text values are styled text.
Rarity
| Constant | Description |
|---|---|
COMMON |
white name |
UNCOMMON |
yellow name |
RARE |
aqua name |
EPIC |
light purple name |
Hands
Hand
| Constant | Description |
|---|---|
MAIN_HAND |
main hand |
OFF_HAND |
off hand |
Arm
| Constant | Description |
|---|---|
LEFT |
left arm |
RIGHT |
right arm |
Arm is nursultan.item.Arm, the main-arm side reported by RenderItemEvent.arm() and the client-settings packets.
Last updated