状态效果与药水

状态效果与药水

状态效果有时也称药水效果,在代码中称为 MobEffect,会逐刻影响实体。本篇介绍其用法、效果与药水的区别,以及如何添加自己的效果和药水。

术语

  • MobEffect 逐刻影响实体。与方块或物品一样,它是注册表对象,必须注册,且为单例。
    • 瞬时效果是一种只施加一刻的特殊状态效果。原版有瞬间治疗和瞬间伤害两种。
  • MobEffectInstance 是设置了持续时间、等级及其他属性的效果实例。它与 MobEffect 的关系,类似 ItemStack 与 Item。
  • Potion 是一组 MobEffectInstance。原版主要将其用于下文的四种药水物品,但也可按需设置在任何物品上。物品如何使用其上设置的药水,由物品自身决定。
  • 药水物品是用于承载药水的物品。这是非正式术语,与原版 PotionItem 类无关(该类只表示普通药水物品)。Minecraft 当前有药水、喷溅药水、滞留药水和药箭四种;Mod 可以增加更多。

MobEffect

继承 MobEffect 类即可创建自己的效果:

public class MyMobEffect extends MobEffect {
    public MyMobEffect(MobEffectCategory category, int color) {
        super(category, color);
    }
    
    @Override
    public boolean applyEffectTick(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) {
    }
}

与所有注册表对象一样,效果必须注册:

//MOB_EFFECTS is a DeferredRegister<MobEffect>
public static final Holder<MyMobEffect> 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.
        0xffffff
));

MobEffect 也提供为受影响实体添加属性修饰符的默认功能。例如,迅捷效果会为移动速度添加属性修饰符。添加方式如下:

public static final Holder<MyMobEffect> MY_MOB_EFFECT = MOB_EFFECTS.register("my_mob_effect", () -> new MyMobEffect(...)
        .addAttributeModifier(Attributes.ATTACK_DAMAGE, ResourceLocation.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(LivingEntity entity, int amplifier) {
        // Apply your effect logic here.
    }
}

然后照常注册效果。

事件

许多效果在其他位置应用逻辑。例如,漂浮效果在活体实体的移动处理器中实现。Mod 效果通常适合放在事件处理器中应用。NeoForge 也提供了一些相关事件:

  • MobEffectEvent.Applicable:游戏检查能否向实体应用效果实例时触发,可拒绝或强制向目标添加效果。
  • MobEffectEvent.Added:效果实例加入目标时触发,包含目标先前可能已有的效果实例信息。
  • MobEffectEvent.Expired:效果实例过期,即计时器归零时触发。
  • 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;
        // starting at 0. 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

向实体添加效果实例:

MobEffectInstance instance = new MobEffectInstance(...);
entity.addEffect(instance);

也可以从实体移除效果实例。新实例会覆盖实体上已有的同种 MobEffect 实例,因此一个实体上的每种效果最多只有一个实例。移除时只需指定 MobEffect:

entity.removeEffect(MobEffects.REGENERATION);

说明 效果只能应用于 LivingEntity 及其子类,即玩家和生物。物品或投出的雪球等对象无法受其影响。

Potion

调用 Potion 构造函数,传入希望包含的 MobEffectInstance 即可创建药水。例如:

//POTIONS is a DeferredRegister<Potion>
public static final Supplier<Potion> MY_POTION = POTIONS.register("my_potion", () -> new Potion(new MobEffectInstance(MY_MOB_EFFECT, 3600)));

new Potion 接收可变参数,因此可添加任意数量的效果,也可以通过 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(1.21.1)。中文翻译依据提交 4a680cdd4d15。