Skip to content

Commit

Permalink
Add MobEffectEvent and deprecate PotionEvents
Browse files Browse the repository at this point in the history
  • Loading branch information
AlphaMode committed May 20, 2024
1 parent 219d725 commit aad1090
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

import javax.annotation.Nullable;

import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;

/**
* Use {@link MobEffectEvent}
*/
@Deprecated(forRemoval = true)
public class PotionEvents {
public static Event<PotionAdded> POTION_ADDED = EventFactory.createArrayBacked(PotionAdded.class, callbacks -> (entity, newEffect, oldEffect, source) -> {
for (PotionAdded e : callbacks)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Iterator;

import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent;
import io.github.fabricators_of_create.porting_lib.mixin.accessors.common.accessor.LivingEntityAccessor;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.LivingEntity;
Expand All @@ -19,7 +20,7 @@ public static boolean curePotionEffects(LivingEntity livingEntity, ItemStack cur
Iterator<MobEffectInstance> itr = livingEntity.getActiveEffects().iterator();
while (itr.hasNext()) {
MobEffectInstance effect = itr.next();
if (effect.isCurativeItem(curativeItem) /*&& !net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.living.PotionEvent.PotionRemoveEvent(this, effect))*/) {
if (effect.isCurativeItem(curativeItem) && !new MobEffectEvent.Remove(livingEntity, effect).post()) {
((LivingEntityAccessor)livingEntity).port_lib$onEffectRemoved(effect);
itr.remove();
ret = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ public boolean isCanceled() {
}

public abstract void sendEvent();

public boolean post() {
sendEvent();
return isCanceled();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package io.github.fabricators_of_create.porting_lib.entity.events.living;

import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* This event is fired when an interaction between a {@link LivingEntity} and {@link MobEffectInstance} happens.
*/
public abstract class MobEffectEvent extends LivingEntityEvents {
public static final Event<RemoveCallback> REMOVE = EventFactory.createArrayBacked(RemoveCallback.class, callbacks -> event -> {
for (RemoveCallback c : callbacks)
c.onEffectRemove(event);
});
public static final Event<ApplicableCallback> APPLICABLE = EventFactory.createArrayBacked(ApplicableCallback.class, callbacks -> event -> {
for (ApplicableCallback c : callbacks)
c.onEffectApplicable(event);
});
public static final Event<AddedCallback> ADDED = EventFactory.createArrayBacked(AddedCallback.class, callbacks -> event -> {
for (AddedCallback c : callbacks)
c.onEffectAdded(event);
});
public static final Event<ExpiredCallback> EXPIRED = EventFactory.createArrayBacked(ExpiredCallback.class, callbacks -> event -> {
for (ExpiredCallback c : callbacks)
c.onEffectExpired(event);
});

@Nullable
protected final MobEffectInstance effectInstance;

public MobEffectEvent(LivingEntity living, MobEffectInstance effectInstance) {
super(living);
this.effectInstance = effectInstance;
}

@Nullable
public MobEffectInstance getEffectInstance() {
return effectInstance;
}

/**
* This Event is fired when a {@link MobEffect} is about to get removed from an Entity.
* This Event is cancelable. If canceled, the effect will not be removed.
* This Event does not have a result.
*/
public static class Remove extends MobEffectEvent {
private final MobEffect effect;

public Remove(LivingEntity living, MobEffect effect) {
super(living, living.getEffect(effect));
this.effect = effect;
}

public Remove(LivingEntity living, MobEffectInstance effectInstance) {
super(living, effectInstance);
this.effect = effectInstance.getEffect();
}

/**
* @return the {@link MobEffectEvent} which is being removed from the entity
*/
public MobEffect getEffect() {
return this.effect;
}

/**
* @return the {@link MobEffectInstance}. In the remove event, this can be null if the entity does not have a {@link MobEffect} of the right type active.
*/
@Override
@Nullable
public MobEffectInstance getEffectInstance() {
return super.getEffectInstance();
}

@Override
public void sendEvent() {
REMOVE.invoker().onEffectRemove(this);
}
}

/**
* This event is fired to check if a {@link MobEffectInstance} can be applied to an entity.
* This event is not cancelable.
* This event has a result.
* <p>
* {@link Result#ALLOW ALLOW} will apply this mob effect.
* {@link Result#DENY DENY} will not apply this mob effect.
* {@link Result#DEFAULT DEFAULT} will run vanilla logic to determine if this mob effect is applicable in {@link LivingEntity#canBeAffected}.
*/
public static class Applicable extends MobEffectEvent {
public Applicable(LivingEntity living, @NotNull MobEffectInstance effectInstance) {
super(living, effectInstance);
}

@Override
@NotNull
public MobEffectInstance getEffectInstance() {
return super.getEffectInstance();
}

@Override
public void sendEvent() {
APPLICABLE.invoker().onEffectApplicable(this);
}
}

/**
* This event is fired when a new {@link MobEffectInstance} is added to an entity.
* This event is also fired if an entity already has the effect but with a different duration or amplifier.
* This event is not cancelable.
* This event does not have a result.
*/
public static class Added extends MobEffectEvent {
private final MobEffectInstance oldEffectInstance;
private final Entity source;

public Added(LivingEntity living, MobEffectInstance oldEffectInstance, MobEffectInstance newEffectInstance, Entity source) {
super(living, newEffectInstance);
this.oldEffectInstance = oldEffectInstance;
this.source = source;
}

/**
* @return the added {@link MobEffectInstance}. This is the unmerged MobEffectInstance if the old MobEffectInstance is not null.
*/
@Override
@NotNull
public MobEffectInstance getEffectInstance() {
return super.getEffectInstance();
}

/**
* @return the old {@link MobEffectInstance}. This can be null if the entity did not have an effect of this kind before.
*/
@Nullable
public MobEffectInstance getOldEffectInstance() {
return oldEffectInstance;
}

/**
* @return the entity source of the effect, or {@code null} if none exists
*/
@Nullable
public Entity getEffectSource() {
return source;
}

@Override
public void sendEvent() {
ADDED.invoker().onEffectAdded(this);
}
}

/**
* This event is fired when a {@link MobEffectInstance} expires on an entity.
* This event is not cancelable.
* This event does not have a result.
*/
public static class Expired extends MobEffectEvent {
public Expired(LivingEntity living, MobEffectInstance effectInstance) {
super(living, effectInstance);
}

@Override
public void sendEvent() {
EXPIRED.invoker().onEffectExpired(this);
}
}

public interface RemoveCallback {
void onEffectRemove(Remove event);
}

public interface ApplicableCallback {
void onEffectApplicable(Applicable event);
}

public interface AddedCallback {
void onEffectAdded(Added event);
}

public interface ExpiredCallback {
void onEffectExpired(Expired event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,31 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;

import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;

import com.llamalad7.mixinextras.sugar.ref.LocalRef;

import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent;
import io.github.fabricators_of_create.porting_lib.entity.events.LivingAttackEvent;
import io.github.fabricators_of_create.porting_lib.entity.events.ShieldBlockEvent;

import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingDamageEvent;

import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingHurtEvent;

import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent;
import net.minecraft.world.effect.MobEffect;

import net.minecraft.world.effect.MobEffectInstance;

import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
Expand Down Expand Up @@ -253,4 +262,41 @@ private float livingDamageEvent(float value, DamageSource pDamageSource) {
return 0;
return event.getAmount();
}

@Inject(method = "removeEffect", at = @At("HEAD"), cancellable = true)
private void onRemoveEffect(MobEffect effect, CallbackInfoReturnable<Boolean> cir) {
var event = new MobEffectEvent.Remove((LivingEntity) (Object) this, effect);
event.sendEvent();
if (event.isCanceled()) cir.setReturnValue(false);
}

@WrapWithCondition(method = "removeAllEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;onEffectRemoved(Lnet/minecraft/world/effect/MobEffectInstance;)V"))
private boolean onRemoveAllEffectEvent(LivingEntity instance, MobEffectInstance effect, @Share("event") LocalRef<MobEffectEvent.Remove> eventRef) {
var event = new MobEffectEvent.Remove(instance, effect);
eventRef.set(event);
event.sendEvent();
return !event.isCanceled();
}

@WrapWithCondition(method = "removeAllEffects", at = @At(value = "INVOKE", target = "Ljava/util/Iterator;remove()V"))
private boolean skipRemove(Iterator<MobEffectInstance> iterator, @Share("event") LocalRef<MobEffectEvent.Remove> eventRef) {
return !eventRef.get().isCanceled();
}

@Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true)
private void isEffectApplicable(MobEffectInstance effectInstance, CallbackInfoReturnable<Boolean> cir) {
MobEffectEvent.Applicable event = new MobEffectEvent.Applicable((LivingEntity) (Object) this, effectInstance);
event.sendEvent();
if (event.getResult() != BaseEvent.Result.DEFAULT) cir.setReturnValue(event.getResult() == BaseEvent.Result.ALLOW);
}

@Inject(method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z", at = @At(value = "JUMP", opcode = Opcodes.IFNONNULL))
private void onEffectAdded(MobEffectInstance newEffect, Entity entity, CallbackInfoReturnable<Boolean> cir, @Local(index = 3) MobEffectInstance oldEffect) {
new MobEffectEvent.Added((LivingEntity) (Object) this, oldEffect, newEffect, entity).sendEvent();
}

@ModifyExpressionValue(method = "tickEffects", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/Level;isClientSide:Z", ordinal = 0))
private boolean onEffectExpired(boolean original, @Local(index = 3) MobEffectInstance effect) {
return !(!original && !new MobEffectEvent.Expired((LivingEntity) (Object) this, effect).post());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent;
import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.monster.Spider;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(Spider.class)
public class SpiderMixin {
@Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true)
private void isEffectApplicable(MobEffectInstance effectInstance, CallbackInfoReturnable<Boolean> cir) {
if (effectInstance.getEffect() == MobEffects.POISON) {
MobEffectEvent.Applicable event = new MobEffectEvent.Applicable((LivingEntity) (Object) this, effectInstance);
event.sendEvent();
if (event.getResult() != BaseEvent.Result.DEFAULT)
cir.setReturnValue(event.getResult() == BaseEvent.Result.ALLOW);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"common.ServerPlayerMixin",
"common.ShulkerBulletMixin",
"common.SlimeMixin",
"common.SpiderMixin",
"common.SpreadPlayersCommandMixin",
"common.TeleportCommandMixin",
"common.ThrowableProjectileMixin",
Expand Down

0 comments on commit aad1090

Please sign in to comment.