Skip to content

Commit

Permalink
Add ProjectileImpactEvent and deprecate ProjectileImpactCallback
Browse files Browse the repository at this point in the history
  • Loading branch information
AlphaMode committed Dec 11, 2023
1 parent d623971 commit 533760c
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ public Entity getEntity() {
callback.onEntityStruckByLightning(event);
});

public static final Event<ProjectileImpact> PROJECTILE_IMPACT = EventFactory.createArrayBacked(ProjectileImpact.class, callbacks -> event -> {
for (ProjectileImpact callback : callbacks)
callback.onProjectileImpact(event);
});

@FunctionalInterface
public interface ProjectileImpact {
void onProjectileImpact(ProjectileImpactEvent event);
}

@FunctionalInterface
public interface EnteringSection {
void onEntityEnterSection(Entity entity, long packedOldPos, long packedNewPos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.phys.HitResult;

/**
* Will be removed in 1.20.2+
* Use {@link ProjectileImpactEvent} instead.
*/
@Deprecated(forRemoval = true)
public interface ProjectileImpactCallback {
Event<ProjectileImpactCallback> EVENT = EventFactory.createArrayBacked(ProjectileImpactCallback.class, callbacks -> (proj, hit) -> {
for (ProjectileImpactCallback callback : callbacks) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.github.fabricators_of_create.porting_lib.entity.events;

import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.phys.HitResult;

/**
* This event is fired when a projectile entity impacts something.<br>
* This event is fired for all vanilla projectiles by Porting Lib,
* custom projectiles should fire this event and check the result in a similar fashion.
* This event is cancelable. When canceled, the impact will not be processed and the projectile will continue flying.
* Killing or other handling of the entity after event cancellation is up to the modder.
*/
public class ProjectileImpactEvent extends EntityEvents {
private final HitResult ray;
private final Projectile projectile;

public ProjectileImpactEvent(Projectile projectile, HitResult ray) {
super(projectile);
this.ray = ray;
this.projectile = projectile;
}

public HitResult getRayTraceResult() {
return ray;
}

public Projectile getProjectile() {
return projectile;
}

@Override
public void sendEvent() {
// setCanceled(ProjectileImpactCallback.EVENT.invoker().onImpact(getProjectile(), getRayTraceResult())); ProjectileImpactCallback fires for all projectiles including none vanilla
PROJECTILE_IMPACT.invoker().onProjectileImpact(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Share;

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

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

import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.projectile.AbstractArrow;

import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

@Mixin(AbstractArrow.class)
public abstract class AbstractArrowMixin extends Entity {
public AbstractArrowMixin(EntityType<?> variant, Level world) {
super(variant, world);
}

@WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;onHit(Lnet/minecraft/world/phys/HitResult;)V"))
private boolean onImpact(AbstractArrow arrow, HitResult result, @Share("event") LocalRef<ProjectileImpactEvent> eventRef, @Share("state") LocalBooleanRef hasImpulseState) {
ProjectileImpactEvent event = new ProjectileImpactEvent(arrow, result);
event.sendEvent();
eventRef.set(event);
hasImpulseState.set(this.hasImpulse);
return !event.isCanceled();
}

@WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;getPierceLevel()B"))
private byte shouldBreak(AbstractArrow instance, Operation<Byte> original, @Share("event") LocalRef<ProjectileImpactEvent> eventRef, @Share("state") LocalBooleanRef hasImpulseState) {
if (eventRef.get().isCanceled()) {
this.hasImpulse = hasImpulseState.get();
return 0;
}
return original.call(instance);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.llamalad7.mixinextras.injector.WrapWithCondition;

import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent;
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
import net.minecraft.world.phys.HitResult;

@Mixin(AbstractHurtingProjectile.class)
public class AbstractHurtingProjectileMixin {
@WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractHurtingProjectile;onHit(Lnet/minecraft/world/phys/HitResult;)V"))
private boolean onImpact(AbstractHurtingProjectile projectile, HitResult result) {
ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result);
event.sendEvent();
return !event.isCanceled();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.llamalad7.mixinextras.injector.WrapWithCondition;

import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent;
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
import net.minecraft.world.phys.HitResult;

@Mixin(FireworkRocketEntity.class)
public class FireworkRocketEntityMixin {
@WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/FireworkRocketEntity;onHit(Lnet/minecraft/world/phys/HitResult;)V"))
private boolean onImpact(FireworkRocketEntity projectile, HitResult result) {
if (result.getType() == HitResult.Type.MISS)
return true;
ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result);
event.sendEvent();
return !event.isCanceled();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import com.llamalad7.mixinextras.injector.WrapWithCondition;

import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent;
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
import net.minecraft.world.entity.projectile.FishingHook;

import net.minecraft.world.phys.HitResult;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

@Mixin(FishingHook.class)
public class FishingHookMixin {
@WrapWithCondition(method = "checkCollision", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/FishingHook;onHit(Lnet/minecraft/world/phys/HitResult;)V"))
private boolean onImpact(FishingHook projectile, HitResult result) {
if (result.getType() == HitResult.Type.MISS)
return true;
ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result);
event.sendEvent();
return !event.isCanceled();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.llamalad7.mixinextras.injector.WrapWithCondition;

import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent;
import net.minecraft.world.entity.projectile.LlamaSpit;
import net.minecraft.world.phys.HitResult;

@Mixin(LlamaSpit.class)
public class LlamaSpitMixin {
@WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/LlamaSpit;onHit(Lnet/minecraft/world/phys/HitResult;)V"))
private boolean onImpact(LlamaSpit projectile, HitResult result) {
if (result.getType() == HitResult.Type.MISS)
return true; // NeoForge prevents any misses here, however vanilla doesn't so we keep vanilla behavior
ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result);
event.sendEvent();
return !event.isCanceled();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.llamalad7.mixinextras.injector.WrapWithCondition;

import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent;
import net.minecraft.world.entity.projectile.ShulkerBullet;
import net.minecraft.world.phys.HitResult;

@Mixin(ShulkerBullet.class)
public class ShulkerBulletMixin {
@WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ShulkerBullet;onHit(Lnet/minecraft/world/phys/HitResult;)V"))
private boolean onImpact(ShulkerBullet projectile, HitResult result) {
ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result);
event.sendEvent();
return !event.isCanceled();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.fabricators_of_create.porting_lib.entity.mixin.common;

import com.llamalad7.mixinextras.injector.WrapWithCondition;

import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent;
import net.minecraft.world.entity.projectile.ShulkerBullet;
import net.minecraft.world.entity.projectile.ThrowableProjectile;

import net.minecraft.world.phys.HitResult;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

@Mixin(ThrowableProjectile.class)
public class ThrowableProjectileMixin {
@WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;onHit(Lnet/minecraft/world/phys/HitResult;)V"))
private boolean onImpact(ThrowableProjectile projectile, HitResult result) {
ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result);
event.sendEvent();
return !event.isCanceled();
}
}
7 changes: 7 additions & 0 deletions entity/src/main/resources/porting_lib_entity.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"package": "io.github.fabricators_of_create.porting_lib.entity.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"common.AbstractArrowMixin",
"common.AbstractHurtingProjectileMixin",
"common.AbstractMinecartMixin",
"common.BlockBehaviourMixin",
"common.BundlePacketMixin",
Expand All @@ -13,10 +15,13 @@
"common.EntityAccessor",
"common.EntityMixin",
"common.ExperienceOrbMixin",
"common.FireworkRocketEntityMixin",
"common.FishingHookMixin",
"common.ItemMixin",
"common.LevelMixin",
"common.LightningBoltMixin",
"common.LivingEntityMixin",
"common.LlamaSpitMixin",
"common.MobEffectMixin",
"common.MobMixin",
"common.NaturalSpawnerMixin",
Expand All @@ -32,9 +37,11 @@
"common.ServerLevelMixin",
"common.ServerPlayerGameModeMixin",
"common.ServerPlayerMixin",
"common.ShulkerBulletMixin",
"common.SlimeMixin",
"common.SpreadPlayersCommandMixin",
"common.TeleportCommandMixin",
"common.ThrowableProjectileMixin",
"common.ThrownEnderpearlMixin",
"common.TransientEntitySectionManager$CallbackMixin"
],
Expand Down

0 comments on commit 533760c

Please sign in to comment.