Mob Effects & Potions
Status effects, sometimes known as potion effects and referred to in-code as MobEffects, are effects that influence a LivingEntity every tick. This article explains how to use them, what the difference between an effect and a potion is, and how to add your own.
Terminology
- A
MobEffectaffects an entity every tick. Like blocks or items,MobEffects are registry objects, meaning they must be registered and are singletons.- An instant mob effect is a special kind of mob effect that is designed to be applied for one tick. Vanilla has two instant effects, Instant Health and Instant Harming.
- A
MobEffectInstanceis an instance of aMobEffect, with a duration, amplifier and some other properties set (see below).MobEffectInstances are toMobEffects whatItemStacks are toItems. - A
Potionis a collection ofMobEffectInstances. Vanilla mainly uses potions for the four potion items (read on), however, they can be applied to any item at will. It is up to the item if and how the item then uses the potion set on it. - A potion item is an item that is meant to have a potion set on it. This is an informal term, the vanilla
PotionItemclass has nothing to do with this (it refers to the "normal" potion item). Minecraft currently has four potion items: potions, splash potions, lingering potions, and tipped arrows; however more may be added by mods.
MobEffects
To create your own MobEffect, extend the MobEffect class:
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) {
}
}
Like all registry objects, MobEffects must be registered, like so:
// 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
));
The MobEffect class also provides default functionality for adding attribute modifiers to affected entities, and also removing them when the effect expires or is removed through other means. For example, the speed effect adds an attribute modifier for movement speed. Effect attribute modifiers are added like so:
public static final Holder<MobEffect> 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
If you want to create an instant effect, you can use the helper class InstantenousMobEffect instead of the regular MobEffect class, like so:
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.
}
}
Then, register your effect like normal.
Events
Many effects have their logic applied in other places. For example, the levitation effect is applied in the living entity movement handler. For modded MobEffects, it often makes sense to apply them in an event handler. NeoForge also provides a few events related to effects:
MobEffectEvent.Applicableis fired when the game checks whether aMobEffectInstancecan be applied to an entity. This event can be used to deny or force adding the effect instance to the target.MobEffectEvent.Addedis fired when theMobEffectInstanceis added to the target. This event contains information about a previousMobEffectInstancethat may have been present on the target.MobEffectEvent.Expiredis fired when theMobEffectInstanceexpires, i.e. the timer goes to zero.MobEffectEvent.Removeis fired when the effect is removed from the entity through means other than expiring, e.g. through drinking milk or via commands.
MobEffectInstances
A MobEffectInstance is, simply put, an effect applied to an entity. Creating a MobEffectInstance is done by calling the constructor:
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
);
Several constructor overloads are available, omitting the last 1-5 parameters, respectively.
MobEffectInstances are mutable. If you need a copy, call new MobEffectInstance(oldInstance).