状态效果与药水
状态效果有时也称药水效果,在代码中表示为 MobEffect,每刻对 LivingEntity 产生影响。本文介绍它们的用法、效果与药水的区别,以及如何添加自己的效果。
术语
MobEffect每刻影响实体。与方块和物品一样,它是注册表对象,需要注册,并且是单例。- 瞬时状态效果是一类专门设计为只应用一刻的状态效果。原版有瞬间治疗和瞬间伤害两种。
MobEffectInstance是一个设置了持续时间、增幅等级及其他属性的MobEffect实例(见下文)。它与MobEffect的关系,类似ItemStack与Item的关系。Potion是一组MobEffectInstance。原版主要将药水用于四种药水物品(见下文),但也可以按需应用到任何物品。物品是否使用以及如何使用其上的药水,由物品自身决定。- 药水物品是指预期带有药水数据的物品。这是非正式称呼,与原版的
PotionItem类无关(该类专指普通药水物品)。Minecraft 目前有药水、喷溅药水、滞留药水和药箭四类,Mod 还可以添加更多。
MobEffect
要创建自己的 MobEffect,继承 MobEffect 类:
public class MyMobEffect extends MobEffect {
public MyMobEffect(MobEffectCategory category, int color) {
super(category, color);
}
@Override
public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) {
// Apply your effect logic here.
// If this returns false when shouldApplyEffectTickThisTick returns true, the effect will immediately be removed
return true;
}
// Whether the effect should apply this tick. Used e.g. by the Regeneration effect that only applies
// once every x ticks, depending on the tick count and amplifier.
@Override
public boolean shouldApplyEffectTickThisTick(int tickCount, int amplifier) {
return tickCount % 2 == 0; // replace this with whatever check you want
}
// Utility method that is called when the effect is first added to the entity.
// This does not get called again until all instances of this effect have been removed from the entity.
@Override
public void onEffectAdded(LivingEntity entity, int amplifier) {
super.onEffectAdded(entity, amplifier);
}
// Utility method that is called when the effect is added to the entity.
// This gets called every time this effect is added to the entity.
@Override
public void onEffectStarted(LivingEntity entity, int amplifier) {
}
}
和其他注册表对象一样,MobEffect 必须注册:
// MOB_EFFECTS is a DeferredRegister<MobEffect>
public static final Holder<MobEffect> MY_MOB_EFFECT = MOB_EFFECTS.register("my_mob_effect", () -> new MyMobEffect(
//Can be either BENEFICIAL, NEUTRAL or HARMFUL. Used to determine the potion tooltip color of this effect.
MobEffectCategory.BENEFICIAL,
//The color of the effect particles in RGB format.
0xffffff
));
MobEffect 类还提供了默认功能,可以为受影响实体添加属性修饰符,并在效果到期或以其他方式移除时删除这些修饰符。例如,速度效果会添加移动速度属性修饰符。添加方式如下:
public static final Holder<MobEffect> MY_MOB_EFFECT = MOB_EFFECTS.register("my_mob_effect", () -> new MyMobEffect(...)
.addAttributeModifier(Attributes.ATTACK_DAMAGE, Identifier.fromNamespaceAndPath("examplemod", "effect.strength"), 2.0, AttributeModifier.Operation.ADD_VALUE)
);
InstantenousMobEffect
要创建瞬时效果,可以使用辅助类 InstantenousMobEffect,替代普通 MobEffect:
public class MyMobEffect extends InstantenousMobEffect {
public MyMobEffect(MobEffectCategory category, int color) {
super(category, color);
}
@Override
public void applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) {
// Apply your effect logic here.
}
}
然后照常注册效果。
事件
许多效果的逻辑在其他位置执行。例如,飘浮效果在活体实体的移动处理逻辑中应用。Mod 的 MobEffect 通常适合在事件处理器中实现。NeoForge 还提供了几个与效果有关的事件:
MobEffectEvent.Applicable:游戏检查某个MobEffectInstance能否应用于实体时触发。可拒绝或强制向目标添加效果实例。MobEffectEvent.Added:向目标添加MobEffectInstance时触发。包含目标之前可能已有的MobEffectInstance信息。MobEffectEvent.Expired:MobEffectInstance到期,即计时归零时触发。MobEffectEvent.Remove:效果因到期以外的原因从实体上移除时触发,例如喝牛奶或使用命令。
MobEffectInstance
简单来说,MobEffectInstance 就是应用于实体的效果。调用构造函数创建:
MobEffectInstance instance = new MobEffectInstance(
// The mob effect to use.
MobEffects.REGENERATION,
// The duration to use, in ticks. Defaults to 0 if not specified.
500,
// The amplifier to use. This is the "strength" of the effect, i.e. Strength I, Strength II, etc.
// Must be between 0 and 255 (inclusive). Defaults to 0 if not specified.
0,
// Whether the effect is an "ambient" effect, meaning it is being applied by an ambient source,
// of which Minecraft currently has the beacon and the conduit. Defaults to false if not specified.
false,
// Whether the effect is visible in the inventory. Defaults to true if not specified.
true,
// Whether an effect icon is visible in the top right corner. Defaults to true if not specified.
true
);
另有多个构造函数重载,分别省略最后 1–5 个参数。
说明
MobEffectInstance是可变对象。需要副本时,调用new MobEffectInstance(oldInstance)。
使用 MobEffectInstance
可以这样为 LivingEntity 添加 MobEffectInstance:
MobEffectInstance instance = new MobEffectInstance(...);
livingEntity.addEffect(instance);
同样,也可以从 LivingEntity 移除效果实例。同一个实体上,同一种 MobEffect 的新实例会覆盖已有实例,因此每种效果只能有一个实例。移除时只需指定 MobEffect:
livingEntity.removeEffect(MobEffects.REGENERATION);
说明
MobEffect只能应用于LivingEntity及其子类,也就是玩家和生物。掉落物、掷出的雪球等对象不会受到状态效果影响。
Potion
调用 Potion 构造函数并传入所需的 MobEffectInstance,即可创建药水。例如:
//POTIONS is a DeferredRegister<Potion>
public static final Holder<Potion> MY_POTION = POTIONS.register("my_potion", registryName -> new Potion(
// The suffix applied to the potion
registryName.getPath(),
// The effects used by the potion
new MobEffectInstance(MY_MOB_EFFECT, 3600)
));
构造函数的第一个参数是药水名称,用作翻译键的后缀。例如,原版的延长型和增强型药水通过它沿用基础药水的名称。
new Potion 的 MobEffectInstance 参数是可变参数,因此可以添加任意数量的效果,也可以创建没有任何效果的空药水。原文以 new Potion() 说明空药水的创建方式,并指出原版的 awkward 药水即采用这一思路。
PotionContents 类提供了多种与药水物品相关的辅助方法。药水物品通过 DataComponent#POTION_CONTENTS 存储其 PotionContents。
酿造
添加药水后,相应药水物品便已存在,但生存模式下尚无获取途径,需要添加酿造配方。
药水通常在酿造台制作。Mojang 尚未为酿造配方提供数据包支持,因此需要通过 RegisterBrewingRecipesEvent 事件,以代码添加配方:
@SubscribeEvent // on the game event bus
public static void registerBrewingRecipes(RegisterBrewingRecipesEvent event) {
// Gets the builder to add recipes to
PotionBrewing.Builder builder = event.getBuilder();
// Will add brewing recipes for all container potions (e.g. potion, splash potion, lingering potion)
builder.addMix(
// The initial potion to apply to
Potions.AWKWARD,
// The brewing ingredient. This is the item at the top of the brewing stand.
Items.FEATHER,
// The resulting potion
MY_POTION
);
}
来源: NeoForged/Documentation(26.1)。中文翻译依据提交
4a680cdd4d15。