Minecraft(我的世界)中文论坛

标题: [Tutorial][Bukkit][UD]如何给物品增加NBT数据

作者: 602723113    时间: 2017-6-11 08:40
标题: [Tutorial][Bukkit][UD]如何给物品增加NBT数据
本帖最后由 602723113 于 2020-4-15 12:04 编辑

2020/4/15 更新对1.13.2以上BukkitAPI对Attribute的相关操作

NBT

目录:
  • 导读
  • NBT是啥子(如果已经知道了的可以直接跳到下一章)
  • 代码实例
  • Attribute

导读

本教程使用的是 Spigot1.10.2-R0.1-SNAPSHOT 核心
Spigot1.15.2 的核心
在阅读之前请确保你具有NMSJava基础知识

首在教程开始之前我们需要知道其实BukkitAPI提供了几个可以“设置”NBT的方法,当然其实就只有DisplayName和Lore
  1. //实例化一个物品
  2. ItemStack item = new ItemStack(Material.DIAMOND_SWORD);
  3. ItemMeta im = item.getItemMeta();
  4. im.setDisplayName("§6[ §e§l钻石剑 §6]");
  5. im.setLore(Arrays.asList("展示剑..", "第二行Lore"));
  6. item.setItemMeta(im);
复制代码
输出其NBT:

那么既然BukkitAPI没有给我们包装NBT相关的方法那么我们就只能去NMS底层操作啦=w=


什么是NBT

NBT (Named Binary Tag) 是一种基于标签的二进制格式设计,携带大量与少量的附加数据的二进制数据。格式被设计成将数据存储在由各种标记组成的树结构中。
在Minecraft所有的物品中每一项都有一个NBTCompound它包含了[lore(描述), name(展示名), damage value(伤害值), attack_speed(攻击速度), 应该放在哪个物品栏当中(如头盔只能放头部), amount(数量)]

代码实例

那么既然我们要给一个物品增加NBT数据那么我们首先需要一个item
  1. ItemStack item = new ItemStack(Material.DIAMOND_SWORD);
复制代码
之后呢我们需要获取这个物品的nms对象
  1. net.minecraft.server.v1_10_R1.ItemStack nmsItem
  2. = CraftItemStack.asNMSCopy(item);
复制代码
之后我们需要获取该物品的NBT对象,下面我使用了三元运算符
  1. NBTTagCompound compound = (nmsItem.hasTag()) ? nmsItem.getTag()
  2. : new NBTTagCompound();
复制代码
那么我们获取到了物品的NBT对象,我们就可以对其进行set数据了
  1. //下面这个是set的一个使用方法
  2. //我们需要填入一个String和一个NBTBase的实例
  3. compound.set(String dataName, NBTBase data);

  4. //我们可以使用NBT来做一个类似绑定的效果
  5. compound.set("绑定", new NBTTagString("May_Speed"));
  6. //NBTTagString是什么?我给你指条路吧=w=
  7. //拿着反编译工具去nms包下查询NBTTagString这个类所继承了的类
  8. //(好吧其实就是NBTBase)
复制代码
那么我们set好之后只是在一个NBT上set了数据,我们还要把这个NBT给set进物品
  1. nmsItem.setTag(compound);
  2. //之后将nmsItem转换为BukkitAPI中的ItemStack
  3. ItemStack hasNBTItem = CraftItemStack.asBukkitCopy(nmsItem);
复制代码
输出其NBT数据: (图小的可以点开来看)

完整代码:


AttributeNBTTag

在一些RPG地图中我们有时会看到这样的武器


这个就是一把利用Attribute与NBTTag制造的一把武器=w=
那么我们要怎么利用代码做出这样的效果呢?

这里我要补充的是,在1.13.2版本的时候,BukkitAPI更新了对物品的Attribute的相关操作,相关的commit请点这个链接:点我

此外,如果你事先是不清楚BukkitAPI下 org.bukkit.attribute 的使用方法,我建议你可以看看这个教程

或者看我下面的一些操作,看你能不能看懂吧哈哈哈哈哈哈啊哈哈哈

1.13.2以下的版本
  1. //和往常一样我们实例化一个物品
  2. ItemStack item = new ItemStack(Material.DIAMOND_SWORD);
  3. ItemMeta im = item.getItemMeta();
  4. im.setDisplayName("§6[ §e§l战火 §6]");
  5. item.setItemMeta(im);
复制代码
之后获取这个物品的NBT
  1. NBTTagCompound compound =
  2. (nmsItem.hasTag()) ? nmsItem.getTag() : new NBTTagCompound();
复制代码
那么之后我们需要新建一个NBT集合
  1. NBTTagList modifiers = new NBTTagList();
复制代码
之后我们再实例化一个NBT数据出来
  1. NBTTagCompound damage = new NBTTagCompound();
复制代码
之后往里面写入一些数据

  1. //AttributeName指该修改的位置也就是 属性名 (17-8-18修订 嘻嘻嘻)
  2. //Name指该Attribute的名字 可以通过NBTCompound.get(String name)得到
  3. //Amount指该Attribute的属性所修改的的值
  4. //Operation值该Attribute的值是百分比还是数值来算
  5. //  数值为0 百分比为1(7-2号修订=w=)
  6. //UUID是用于区分这些Attribute的建议可以设置大一些
  7. //Slot值该Attribute在玩家的哪个 部位 才会生效,不填写则所有部位都会生效
  8. damage.set("AttributeName", new NBTTagString("generic.attackDamage"));
  9. damage.set("Name", new NBTTagString("Damage"));
  10. damage.set("Amount", new NBTTagInt(20));
  11. damage.set("Operation", new NBTTagInt(0));
  12. damage.set("UUIDLeast", new NBTTagInt(20000));
  13. damage.set("UUIDMost", new NBTTagInt(1000));
  14. damage.set("Slot", new NBTTagString("mainhand"));
复制代码
将刚刚写入好数据的damageNBT给放入NBT集合当中
  1. modifiers.add(damage);
复制代码
之后将此NBT集合数据放入总NBT数据中
  1. compound.set("AttributeModifiers", modifiers);
复制代码
之后和上面的一样进行NBT保存
  1. nmsItem.setTag(compound);
复制代码
看不懂我在说啥?来看图吧=w=



1.13.2以上的版本

怎么说呢,早在1.13.2版本的时候BukkitAPI就已经更新了,并且相较于上面的方式来说,这种方法更为快捷,方便,同时也不用反射

但是要注意的是,只能编辑Attribute,而不是NBT这一点是要注意的

引入案例:我们现在需要做一个物品,这个物品名字叫 加速火把 当玩家手持它的时候它可以给玩家加速!那么在以前的时候,我们都是 使用Lore或者DisplayName 监听器,然后设置玩家的移速

那么现在我们可以不用这样了!因为好用的API增加了!

首先我们实例化一个火把
  1. ItemStack torch = new ItemStack(Material.TORCH);
复制代码
之后我们获取它的 ItemMeta
  1. ItemMeta itemMeta = torch.getItemMeta();
复制代码
为了让它更美观,这里增加一些修饰
  1. itemMeta.setDisplayName("§f§l[ §a§l加速火把 §f§l]");
  2. itemMeta.setLore(Lists.newArrayList("§fPY又痒了? 我来给你加加速!"));;
复制代码
重点来了,啪啪啪
在上方的代码里,我们使用了ItemMeta下的方法 addAttributeModifier,它的参数是长这样的
addAttributeModifier(Attribute attribute, AttributeModifier modifier)

  • 第一个参数 attribute,其实是一个枚举,你可以直接在IDE里 Attribute. 就可以看到所有可以操作的属性了
  • 第二个参数 modifier,这个就是属性修改器,我们可以在这里设置
  • 这个attribute的UUID(UUID.randomUUID())
  • 这个attitude的名字("我是加速火把")
  • 这个attribute所增加或减少的值(0.2D)
  • 增加的方式(Operation)
  • 限定物品指定的位置才能生效(EquipmentSlot)

那么在上面我写的是,当这个加速火把是在副手手持的时候,就增加 0.2 的速度

最后我们需要把itemMeta设置回物品
  1. torch.setItemMeta(itemMeta);
复制代码
现在让我们来看看成品的效果!

完整代码:

那么同样的我们也可以利用这种方式给其他的物品增加attribute
下面我写了一个测试代码,方便读者用以测试,代码你可以随意CV

论坛又吞代码了,那我就丢垃圾到github好了

具体使用方法:
为了方便起见,这只是一个测试代码,请使用者在玩家状态下使用这个指令,如果你的指令是其他名字可以自己改成别的,默认指令是test
使用方法:
  • /test 1 获得所有的物品
  • /test 2 查询玩家身上所有的物品的attribute
使用效果:


一些资源

可以用于ItemStack的 属性名


所有部位的Slot名



想要设置无法破坏?只需要在主NBTTagCompound里面写上
  1. compound.set("Unbreakable", new NBTTagByte((byte) 1));
  2. //1就是开启无法破坏 0就是关闭
复制代码

其实在1.11以上的版本,ItemMeta增加了 unbreakable 的api
你可以直接  ItemMeta.setUnbreakable(true) 来设置


本教程完工于
2017/6/11 11:30

在2020/4/15 更新!

如需转载请站内PM我
[groupid=1181]Unknown Domain[/groupid]
作者: YPXxiaoK    时间: 2017-6-11 08:53
楼主快点更新啊,我们都等着呢
作者: PHontdoge棒冰    时间: 2017-6-11 08:53
提示: 作者被禁止或删除 内容自动屏蔽
作者: 炎黄始祖    时间: 2017-6-11 09:31
萌新一脸懵逼
作者: SmallFatCYW    时间: 2017-6-11 11:58
本帖最后由 SmallFatCYW 于 2017-6-11 12:05 编辑

请教一下,"NMS"是?谢谢
好吧。。。刚刚找到了老外的解释帖子。原来是net.minecraft.server这个包啊

作者: Bryan33    时间: 2017-6-11 21:54
本来之前不会用插件的NBT 看完帖子才会
但是这样写必须对应版本
所以我自己改成了用反射执行方法的泛用工具包
作者: w_cn    时间: 2017-6-16 20:05
ItemStack可以存储NBT么?
1.7.2R的包
作者: kqn3    时间: 2017-6-27 08:08
好帖,写强化去了~
作者: Arobcher    时间: 2017-8-7 16:11
反馈:
1.9版本以下 AttributeName 的名字必须填写为类型名,不然会无效!
作者: dust_of_heart    时间: 2017-8-16 20:38
感谢楼主,非常有用,但是有个小地方似乎写错了把
  1. //AttributeName指该Attribute的名字,可以随意填写
复制代码
这一段里面的
damage.set("AttributeName", new NBTTagString("Damage"));
damage.set("Name", new NBTTagString("generic.attackDamage"));
这两个似乎写反了把#(滑稽)
难道是防伸手党#(坏笑)

作者: 2280761425    时间: 2017-9-8 19:46
属性有更简单的添加方法QWQ
作者: 343362619    时间: 2017-9-11 00:29
请问有没有正版版本加入nbt标签的教程
作者: 陋室铭    时间: 2017-9-14 11:18
支持版主 期待更新 萌新一脸萌萌~
作者: jiangzizhong    时间: 2017-9-16 14:37
版主大大莫老,求该java文件。
作者: 神奇的滑稽    时间: 2018-3-22 19:45
generic.attackDamage    伤害
generic.attackSpeed      攻击速度
generic.maxHealth        生命值上线
generic.movementSpeed   移动速度
generic.armor  护甲
generic.luck  新云

装备的韧性的那个属性是那个
作者: 狡诈师    时间: 2018-5-11 19:30
有一个问题,可以回答吗?
这个显示
+ 100伤害(新增)
而不是 100伤害(固定,非新增)
我想实现 固定默认的属性,而不是 +

作者: 思念丶···    时间: 2018-5-12 14:17
好难。头晕眼花
作者: quantumyao    时间: 2020-4-5 10:46
我现在看起来还不太懂.......单我总有一天会懂的!
作者: William_Shi    时间: 2020-4-16 16:51
1.15.2的请看这里
https://www.mcbbs.net/thread-1020301-1-1.html
教程内代码不完全适用
作者: 2418013844@qq    时间: 2020-7-21 16:35
请问1.7.2的Bukkit的ItemStack不包含nbt数据 那么用CraftItemStack.asBukkitCopy()的时候转**ukkit的ItemStack的时候造成NBT数据丢失(修改无效) 该怎么办?
作者: 折纸不知    时间: 2020-7-21 17:28
大佬啊好厉害,虽然有的地方还是看不懂,前面还好后面就蒙了