自定义物品
想要创建一个自定义物品,需要包含两个部分:
- 插件内成功注册到 Nukkit-MOT
- 资源包内定义物品贴图发送给客户端
接下来以 糖果剑 为例,演示自定义物品的步骤。
在插件中注册物品
我们按照以下序列图进行操作
创建新物品的类
在插件中,新建 CandyCaneSword
类,继承 ItemCustom 并重写相应方法
package cn.nukkitmot.exampleplugin.custom.item;
import cn.nukkit.item.customitem.CustomItemDefinition;
import cn.nukkit.item.customitem.ItemCustom;
import cn.nukkit.item.customitem.data.ItemCreativeCategory;
import cn.nukkit.item.customitem.data.ItemCreativeGroup;
import cn.nukkit.item.customitem.data.RenderOffsets;
public class CandyCaneSword extends ItemCustom {
private static String spacenameId = "nukkit:candy_cane_sword";
private static String textureName = "candy_cane_sword";
private static String name = null;
public CandyCaneSword() {
super(spacenameId, name, textureName);
}
public int scaleOffset() {
return 32; // 需要是16的倍数,如 32、64、128
}
/**
* 该方法设置自定义物品的定义
*/
@Override
public CustomItemDefinition getDefinition() {
return CustomItemDefinition
.simpleBuilder(this, ItemCreativeCategory.EQUIPMENT)
.creativeGroup(ItemCreativeGroup.SWORD)
.allowOffHand(true)
.handEquipped(true)
.renderOffsets(RenderOffsets.scaleOffset(scaleOffset()))
.build();
}
@Override
public int getMaxDurability() {
return 500;
}
@Override
public int getMaxStackSize() {
return 1;
}
@Override
public int getAttackDamage() {
return 4;
}
@Override
public boolean isSword() {
return true;
}
}
ItemCustom 主要方法
引自 cn.nukkit.item.customitem.ItemCustom
我们需要用 @Override
来重写下面的方法。
-
getMaxStackSize()
方法用于设置自定义物品的最大堆叠数量。 -
scaleOffset()
方法用于设置自定义物品的贴图大小,返回值需要是16的倍数,如 32、64、128。 -
getDefinition()
返回一个 CustomItemDefinition 类概括了该物品的基本属性,如 是否允许副手、在创造栏的分类、附魔效果。
CustomItemDefinition 主要方法
引自 cn.nukkit.item.customitem.CustomItemDefinition
常用构建器
-
customBuilder
自定义物品的定义构造器 -
simpleBuilder
简单物品的构建器 (默认使用这个) -
toolBuilder
工具物品的构建器 -
armorBuilder
盔甲物品的构建器 -
edibleBuilder
食品的构建器
先使用构建器返回一个 CustomItemDefinition
类
CustomItemDefinition.simpleBuilder(ItemCustom item, ItemCreativeCategory creativeCategory);
常用方法
由于方法直接返回 this
因此我们可以使用扁平化的写法。
-
allowOffHand(boolean allowOffHand)
是否允许副手持有。 -
handEquipped(boolean handEquipped)
控制第三人称手持物品的显示方式。 -
foil(boolean foil)
是否有附魔光辉效果,比如附魔书就有。 -
creativeGroup(ItemCreativeGroup creativeGroup)
控制自定义物品在创造栏的分组,例如所有的附魔书都是ItemCreativeGroup.ENCHANTED_BOOK
组。 -
canDestroyInCreative(boolean value)
控制拿该物品的玩家是否可以在创造模式挖掘方块。
ItemCreativeGroup 主要方法
引自 cn.nukkit.item.customitem.data.ItemCreativeGroup
注册物品
最后,在插件入口类的 onEnable 方法中注册物品
import cn.nukkit.item.Item;
import cn.nukkitmot.exampleplugin.custom.item.CandyCaneSword;
public class ExamplePlugin extends PluginBase {
@Override
public void onEnable() {
Item.registerCustomItem(CandyCaneSword.class);
}
}
制作资源包
教程将指导您如何制作资源包,确保正确指向物品贴图,以在游戏内正确显自定义物品。
如果在游戏内创造物品栏中仍然看到空白格子,请检查资源包配置和物品贴图路径是否正确。
详细步骤包括:
- 定义资源包的 UUID 和信息。
- 在资源包中定义物品贴图路径。
- 打包资源包并放入服务器的 resource_packs 文件夹。
资源包目录构成
资源包目录应该包含以下文件:
manifest.json
参考 Bedrock Wiki 对 RP Manifest 的讲解。
{
"format_version": 2,
"header": {
"description": "BY.nukkit-mot",
"name": "§7测试资源包",
"uuid": "00000000-0000-0000-0000-000020160300",
"version": [1, 1, 6],
"min_engine_version": [1, 14, 0]
},
"modules": [
{
"type": "resources",
"uuid": "dde211f9-e1a6-435e-9a84-06fa9242f63e",
"version": [1, 0, 0]
}
]
}
item_texture.json
{
"resource_pack_name": "nukkit-mot",
"texture_name": "atlas.items",
"texture_data": {
"candy_cane_sword": {
"textures": "textures/items/candy_cane_sword"
}
}
}
打包好资源包放入服务器的 resource_packs
文件夹。
进入服务器,正常情况下您会看见资源包正常显示。
很抱歉听到这个消息,但请保持冷静。并按下列情形进行排查:
- 若非插件内置资源包,资源包打包时是以根目录压缩的吗?
也就是点开压缩包就能看到
manifest.json
文件。
- 资源包后缀是否从
.zip
改为.mcpack
后缀?
非 zip 格式的压缩算法客户端不支持。
- 更新资源包后,是否有清理客户端缓存?
在
设置 → 存储 → 资源包
存有资源包缓存时,客户端不会向服务器请求更新的资源包。
深入了解
插件内置资源包
得益于 Nukkit-MOT 的设计,我们可以在插件开发中非常方便的编辑资源包。
只需要在插件的 resources
创建 assets/resource_pack
文件夹,并在其中放置资源包。
示例插件就是这么做的。
示例插件的 resources 目录结构
与 Bedrock Wiki 的对照关系
如果 CustomItemDefinition 中没有您想要的封装方法,该怎么做呢?
我们可以直接参照 Bedrock Wiki 的 ItemComponents 文档!
以允许副手举例。
在 Nukkit-MOT 的 CustomItemDefinition 类中的内容如下
public class CustomItemDefinition {
public static class SimpleBuilder {
/**
* 是否允许副手持有
*/
public SimpleBuilder allowOffHand(boolean allowOffHand) {
this.nbt.getCompound("components")
.getCompound("item_properties")
.putBoolean("allow_off_hand", allowOffHand);
return this;
}
}
}
而 Bedrock Wiki 中是这么介绍 Allow Off Hand 的:
## Allow Off Hand
Determines whether an item can be placed in the off-hand slot of the inventory.
"minecraft:allow_off_hand": {
"value": true
}
SimpleBuilder#allowOffHand 方法中的 this.nbt
在构建器中被创建,可参考 Nukkit-MOT 的 CustomItemDefinition.java#L208
public static class SimpleBuilder {
/**
* 是否允许副手持有
*/
public SimpleBuilder allowOffHand(boolean allowOffHand) {
this.nbt.getCompound("components")
.getCompound("item_properties")
.putBoolean("allow_off_hand", allowOffHand);
return this;
}
}
并不是所有方法都能通过简单的添加 nbt 就达成其效果的,譬如 minecraft:cooldown
就需要服务器来处理 PlayerStartItemCoolDownPacket
以实现物品的使用冷却行为。
可以在 cn.nukkit.network.protocol.ProtocolInfo 中查看协议支持的所有数据包。
RenderOffsets 渲染偏移
渲染偏移的知识较为庞大、复杂,当前也没有可视化工具所以需要一定的空间想象能力。
引用:
通过观察下面的高亮部分代码可知,需要向 RenderOffsets
类传入 4 个 Offset
对象。
@Override
public CustomItemDefinition getDefinition() {
return CustomItemDefinition
.toolBuilder(this, ItemCreativeCategory.EQUIPMENT)
.addRepairItems(List.of(Item.fromString("minecraft:amethyst_shard")), 100)
.addRepairItems(List.of(Item.fromString("yes:amethyst_spear")), 400)
.renderOffsets(new RenderOffsets(
Offset.builder()
.position(0.48f, -0.128f, -0.946f)
.rotation(11.696f, -64.536f, 79.413f)
.scale(0.038f, 0.037f, 0.038f),
Offset.builder()
.position(0.258f, 0.979f, -0.541f)
.rotation(-63.268f, -43.969f, 144.041f)
.scale(0.094f, 0.094f, 0.094f),
Offset.builder()
.position(-1.053f, 0.136f, -0.803f)
.rotation(27.273f, 67.731f, -64.494f)
.scale(0.063f, 0.063f, 0.063f),
Offset.builder()
.position(0.258f, 0.979f, -0.541f)
.rotation(-63.268f, -43.969f, 144.041f)
.scale(0.094f, 0.094f, 0.094f)
)
)
.creativeGroup("itemGroup.name.sword")
.allowOffHand(false)
.handEquipped(true)
.customBuild(nbt -> {
nbt.getCompound("components")
.putCompound("minecraft:cooldown", new CompoundTag()
.putString("category", "amethyst_spear")
.putFloat("duration", 3f))
.getCompound("item_properties").putBoolean("animates_in_toolbar", true)
.getCompound("item_properties").putInt("use_duration", 640);
});
}
在 RenderOffsets 类的定义中
public RenderOffsets(@Nullable Offset mainHandFirstPerson, @Nullable Offset mainHandThirdPerson, @Nullable Offset offHandFirstPerson, @Nullable Offset offHandThirdPerson) {}
可以知道四个参数分别为:
- mainHandFirstPerson: 主手第一人称
- mainHandThirdPerson: 主手第三人称
- offHandFirstPerson: 副手第一人称
- offHandThirdPerson: 副手第三人称
需要更多的发现...