I wrote this specifications/explanation based on PocketMine-MP, Other softwares like Nukkit can be different with PM.
- Before starting
- What is ItemComponentPacket?
- The required NBT components to display your item correctly
- The Basic structure of Serialized NBT
- Step to send custom item by plugin
Table of contents generated with markdown-toc
ItemComponentPacket is the packet for setting item's components such as equippable in OffHand, setting block break speed, max stack size, etc.
But, This packet CANNOT override the existing item.
I don't describe what components exist and how to use on here, But you can refer to wiki.vg and bedrock.dev to find out them.
There is the root CompoundTag.
The following NBT components should be added:
Component Name | Tag Type | Description |
---|---|---|
item_properties | Tag_Compound | A Group of components that will be used to activate item ability |
minecraft:identifier | Tag_Short | A Runtime ID of item that will client use |
minecraft:display_name | Tag_Compound | A CompoundTag that contains only one String Tag that is used to display item's name |
item_properties
component requires those NBT components to show your item:
minecraft:icon
: Tag_Compound
The minecraft:icon
component should contain the tag named texture
, which is the path of your custom item's png file.
Note that the path is NOT the absolute path.
Let's suppose that you have your excalibur
item, located at textures/items/excalibur.png
.
Then the texture
's value should be excalibur
. without including the file's extension.
The minecraft:identifier
is used by client to identify items by runtime id.
Runtime IDs are flexible. It may change at any time depending on the version of Minecraft. However, custom items are an exception.
The Runtime ID should not conflict with the existing item. So I suggest you to use 1000+ above IDs to prevent conflict with an existing items.
The minecraft:display_name
component is used to display item.
This component's tag type is CompoundTag, but it only contains one StringTag.
A StringTag named value
is used to display item name, its value will be shown the client.
If I describe NBT structure as json, it will be look like:
{
"item_properties": {
"allow_off_hand": 1,
"max_stack_size": 1,
"minecraft:icon": {
"texture": "path/to/texture"
}
},
"minecraft:identifier": 1000,
"minecraft:display_name": {
"value": "excalibur"
}
}
In PocketMine-MP, you need to do two things to send a custom item.
First, register a custom item in the ItemTypeDictionary.
However, currently in PocketMine-MP, you cannot add items to ItemTypeDictionary in the normal way.
The ItemTypeDictionary should be set to an array containing ItemTypeEntry.
ItemTypeEntry must pass the namespace of the item as the first argument, the runtime ID of the item as the second argument, and a logical value of componentBased as the third argument.
Second, we need to register the item's runtime ID and generic ID with the ItemTranslator.
There are two array fields in ItemTranslator that we need to send items: simpleCoreToNetMapping
, simpleNetToCoreMapping
coreToNetMapping must contain an array of ItemID => RuntimeID format, and netToCoreMapping must contain an array of RuntimeID => ItemID format.
If all the above descriptions are written as PocketMine plugin code, it will be as follows:
$itemId = 1000;
$runtimeId = $itemId + 5000;
(function() use ($itemId, $runtimeId) : void{
$this->simpleCoreToNetMapping[$id] = $runtimeId;
$this->simpleNetToCoreMapping[$runtimeId] = $id;
)->call(ItemTranslator::getInstance());
(function() use ($itemId, $runtimeId) : void{
$this->itemTypes[] = new ItemTypeEntry("alvin0319:awsome_custom_item", $runtimeId, true); // pass componentBased to true to enable item components
})->call(GlobalItemTypeDictionary::getInstance()->getDictionary());
Finally, when the player enters the server, we need to send an ItemComponentPacket to the player.
Expressing this in the PocketMine-MP plug-in code is as follows.
public function onPlayerJoin(PlayerJoinEvent $event) : void{
$player = $event->getPlayer();
$entries = [];
$itemId = 1000;
$runtimeId = $itemId + 5000;
$nbt = CompoundTag::create()
->setTag("item_properties", CompoundTag::create()
->setTag("minecraft:icon", CompoundTag::create()
->setString("texture", "excallibur")
)->setByte("allow_off_hand", 1)
->setInt("max_stack_size", 1)
)->setShort("minecraft:identifier", $runtimeId)
->setTag("minecraft:display_name", CompoundTag::create()
->setString("value", "Excallibur")
);
$entries[] = new ItemComponentPacketEntry("alvin0319:awesome_custom_item", new CachableNbt($nbt));
$player->getNetworkSession()->sendDataPacket(ItemComponentPacket::create($entries));
}
Contribution is always welcome, by commenting in this gist!
If you have any question, leave it here. I'll add them on this gist!
It's also important to note if your item is mapped like so:
YourNamespace:Your_Item
in theitem_textures.json
file in your resource pack, while the texture is stored intextures/items/Your_Item
, then you will need to set the texture accordingly. Texture would in the above case beYourNamespace:Your_Item
and not justYour_Item
. The texture value you give is mapped withitem_textures.json
which then the client maps to the relevant file. It's important to recognize this.