本帖最后由 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]