1. 实体属性修饰符
实体属性修饰符(Attribute Modifier)是一种修改当前实体属性的值的机制。 通过这套(简单的?)机制我们可以为任何生物实体(自然包括玩家本身)提供正面或负面效果。
1.1. 创建
// 我们首先需要一个能和别的修饰符区分开的 UUID。
// 有鉴于 UUID 的性质,我们在网上随便找个生成器生成一个就行了。
// 如果随机生成的 UUID 还能和别的修饰符撞车的话,建议去买彩票。
public static final UUID MODIFIER_ID = UUID.fromString("b44157cd-2a86-4dc4-ae8a-9820767db864");
// 第一个参数是刚才的 UUID。实际上可以省略,Minecraft 默认会随机生成一个。
// 随机生成的 UUID 影响也不大,只是不稳定。
// 第二个参数是我们一看就知道是干什么的名字。不能是 null。
//
// 第三个参数(double value)和第四个参数(int operation)共同决定了这个修饰符会如何影响该属性:
// - operation == 0 时,原属性值 + value = 新属性值。
// - operation == 1 时,原属性值 + 原属性值 * value = 新属性值。
// - operation == 2 时,原属性值 * (1 + value) = 新属性值。
AttributeModifier mod = new AttributeModifier(MODIFIER_ID, "my_modifier", 1.0, 0);
// 如果你希望这个修饰符在退出游戏/服务器关闭时不保存,请调用 setSaved(false)。
// 原版默认保存所有修饰符,疾跑加速的修饰符是一个例外。
// 通常来说你可以无视这个的存在……
mod = mod.setSaved(false);
1.1.1. 最后两个参数到底是什么意思???
假如说某个属性当前值为 10,且拥有下列修饰符:
修饰符名称 | 运算类型(operation) | 操作数(value) |
---|---|---|
Foo | 0 | 2 |
Bar | 0 | -4 |
Baz | 1 | 0.5 |
Thonk | 1 | 1 |
Donk | 2 | 0.25 |
Wut | 2 | 0.25 |
那么这个属性实际生效的值是这样计算的:
- 首先结算运算 0(Foo 和 Bar):10 + 2 + (-4) = 8
- 然后结算运算 1(Baz 和 Thonk):8 + 8 0.5 + 8 1 = 20
- 最后结算运算 2(Donk 和 Wut):20 (0.25 + 1) (0.25 + 1) = 31.25
因此该属性实际值为 31.25。
1.1.2. 幻数
你可能已经注意到了,代表运算类型的参数是个无厘头的幻数。Forge 提供了对应的常量以消灭幻数的使用。
这些常量位于 net.minecraftforge.common.util.Constants
下:
运算类型 | 常量 |
---|---|
0 | Constants.AttributeModifierOperation.ADD |
1 | Constants.AttributeModifierOperation.ADD_MULTIPLE |
2 | Constants.AttributeModifierOperation.MULTIPLY |
1.2. 为指定属性追加或删除修饰符
EntityLivingBase living = ...;
IAttributeInstance attr = living.getAttributeMap().getAttributeInstance(...);
// 追加修饰符
attr.applyModifier(...);
// 删除修饰符
attr.removeModifier(...);
有必要指出的是,若是通过这种方式手动添加修饰符,则也需要通过这种方式手动删除修饰符,否则修饰符会一直存在。 然而,在原版底层中,有些透过此系统追加修饰符的方式不需要我们自己手动清理,因为原版自己已经有清理修饰符相关的代码了。
1.2.1. 物品与修饰符
装备在身上或手持的物品也可以为当前实体提供修饰符。这些修饰符受 Minecraft 底层自动管理,我们只需要在 Item
类下覆写一个方法就行了:
@Override
public Multimap<String, AttributeModifier> getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) {
ArrayListMultimap<String, AttributeModifier> modifiers = ArrayListMultimap.create();
// 往 modifiers 里塞东西就可以改攻击改防御改各种属性了
// slot 决定了当前物品被装备到了什么地方(四个护甲格、主手或副手)
// 而 stack 则是具体的物品,你可以根据物品当前的 NBT 数据判断
// 应该追加什么修饰符。
// 你只需要发挥你的想象力……
return modifieres;
}
需要注意的是,若指定 ItemStack
的 NBT 数据中含有名为 AttributeModifiers
的标签且类型为 NBTTagList
,Minecraft 会从这个标签中读取属性修饰符,而忽略 Item.getAttributeModifiers
方法的返回结果。这个特性可以用来修改原版或其他 Mod 的武器装备的“属性”(本质上是实体属性修饰符)。
类似的,ItemStack.addAttributeModifier
方法可以为任意 ItemStack
添加任意属性修饰符,这些人为添加的修饰符也会写入物品 NBT 的 AttributeModifiers
标签下。
1.2.2. 状态效果与修饰符
原版有一部分状态效果也是通过属性修饰符实现的。关于这方面的信息,可在对应章节中找到。