From 24c32523451a48a418f09661b1e9ebdb85f8d055 Mon Sep 17 00:00:00 2001 From: Walker Knapp Date: Sat, 1 Aug 2020 02:04:53 -0400 Subject: [PATCH] Implement ProjectileImpactEvent --- .../event/entity/ProjectileImpactEvent.java | 97 +++++++++++++++++++ .../impl/event/entity/EntityEvents.java | 21 ++++ .../MixinExplosiveProjectileEntity.java | 48 +++++++++ .../event/entity/MixinLlamaSpitEntity.java | 52 ++++++++++ .../event/entity/MixinProjectileEntity.java | 54 +++++++++++ .../entity/MixinShulkerBulletEntity.java | 48 +++++++++ .../mixin/event/entity/MixinThrownEntity.java | 48 +++++++++ .../patchwork-events-entity.mixins.json | 7 +- .../event/ForgeEventFactory.java | 21 ++++ 9 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/ProjectileImpactEvent.java create mode 100644 patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinExplosiveProjectileEntity.java create mode 100644 patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinLlamaSpitEntity.java create mode 100644 patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinProjectileEntity.java create mode 100644 patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinShulkerBulletEntity.java create mode 100644 patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinThrownEntity.java diff --git a/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/ProjectileImpactEvent.java b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/ProjectileImpactEvent.java new file mode 100644 index 00000000..f84f8807 --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/ProjectileImpactEvent.java @@ -0,0 +1,97 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.entity; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.projectile.ExplosiveProjectileEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.entity.thrown.ThrownEntity; +import net.minecraft.util.hit.HitResult; + +/** + * This event is fired when a projectile entity impacts something. + * + *

Subclasses of this event exist for more specific types of projectile.

+ * + *

This event is fired for all vanilla projectiles by Patchwork. + * Custom projectiles should fire this event via {@link net.patchworkmc.impl.event.entity.EntityEvents}, check the result, + * and cancel the impact if false.

+ * + *

This event is cancelable. When canceled, the impact will not be processed. + * Killing or other handling of the entity after event cancellation is up to the modder.

+ * + *

This event is fired on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}.

+ */ +public class ProjectileImpactEvent extends EntityEvent { + private final HitResult ray; + + public ProjectileImpactEvent(Entity entity, HitResult ray) { + super(entity); + this.ray = ray; + } + + @Override + public boolean isCancelable() { + return true; + } + + public HitResult getRayTraceResult() { + return ray; + } + + public static class Arrow extends ProjectileImpactEvent { + private final ProjectileEntity arrow; + + public Arrow(ProjectileEntity arrow, HitResult ray) { + super(arrow, ray); + this.arrow = arrow; + } + + public ProjectileEntity getArrow() { + return arrow; + } + } + + public static class Fireball extends ProjectileImpactEvent { + private final ExplosiveProjectileEntity fireball; + + public Fireball(ExplosiveProjectileEntity fireball, HitResult ray) { + super(fireball, ray); + this.fireball = fireball; + } + + public ExplosiveProjectileEntity getFireball() { + return fireball; + } + } + + public static class Throwable extends ProjectileImpactEvent { + private final ThrownEntity throwable; + + public Throwable(ThrownEntity throwable, HitResult ray) { + super(throwable, ray); + this.throwable = throwable; + } + + public ThrownEntity getThrowable() { + return throwable; + } + } +} diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/impl/event/entity/EntityEvents.java b/patchwork-events-entity/src/main/java/net/patchworkmc/impl/event/entity/EntityEvents.java index 96f57705..e2ee6208 100644 --- a/patchwork-events-entity/src/main/java/net/patchworkmc/impl/event/entity/EntityEvents.java +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/impl/event/entity/EntityEvents.java @@ -26,6 +26,7 @@ import net.minecraftforge.common.extensions.IForgeItem; import net.minecraftforge.event.entity.EntityEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.event.entity.ProjectileImpactEvent; import net.minecraftforge.event.entity.living.AnimalTameEvent; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingDamageEvent; @@ -56,10 +57,14 @@ import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.passive.AnimalEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.ExplosiveProjectileEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.entity.thrown.ThrownEntity; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import net.minecraft.util.hit.HitResult; import net.minecraft.world.IWorld; import net.minecraft.world.MobSpawnerLogic; import net.minecraft.world.World; @@ -196,6 +201,22 @@ public static boolean onAnimalTame(AnimalEntity animal, PlayerEntity tamer) { return MinecraftForge.EVENT_BUS.post(new AnimalTameEvent(animal, tamer)); } + public static boolean onProjectileImpact(Entity entity, HitResult ray) { + return MinecraftForge.EVENT_BUS.post(new ProjectileImpactEvent(entity, ray)); + } + + public static boolean onProjectileImpact(ProjectileEntity arrow, HitResult ray) { + return MinecraftForge.EVENT_BUS.post(new ProjectileImpactEvent.Arrow(arrow, ray)); + } + + public static boolean onProjectileImpact(ExplosiveProjectileEntity fireball, HitResult ray) { + return MinecraftForge.EVENT_BUS.post(new ProjectileImpactEvent.Fireball(fireball, ray)); + } + + public static boolean onProjectileImpact(ThrownEntity throwable, HitResult ray) { + return MinecraftForge.EVENT_BUS.post(new ProjectileImpactEvent.Throwable(throwable, ray)); + } + @Override public void onInitialize() { UseItemCallback.EVENT.register((player, world, hand) -> { diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinExplosiveProjectileEntity.java b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinExplosiveProjectileEntity.java new file mode 100644 index 00000000..5e08f1aa --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinExplosiveProjectileEntity.java @@ -0,0 +1,48 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin.event.entity; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.entity.projectile.ExplosiveProjectileEntity; +import net.minecraft.util.hit.HitResult; + +import net.patchworkmc.impl.event.entity.EntityEvents; + +@Mixin(ExplosiveProjectileEntity.class) +public abstract class MixinExplosiveProjectileEntity { + @Shadow + protected abstract void onCollision(HitResult hitResult); + + /** + * Mixin to the redirect the onCollision method, to call {@link net.minecraftforge.event.entity.ProjectileImpactEvent}. + * + *

Note: In future versions, the @Redirect should be replaced with a @ModifyVariable to the bl flag.

+ */ + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/projectile/ExplosiveProjectileEntity;onCollision(Lnet/minecraft/util/hit/HitResult;)V")) + private void hookTick(ExplosiveProjectileEntity entity, HitResult hitResult) { + if (!EntityEvents.onProjectileImpact(entity, hitResult)) { + this.onCollision(hitResult); + } + } +} diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinLlamaSpitEntity.java b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinLlamaSpitEntity.java new file mode 100644 index 00000000..6581436e --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinLlamaSpitEntity.java @@ -0,0 +1,52 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin.event.entity; + +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.CallbackInfo; + +import net.minecraft.entity.projectile.LlamaSpitEntity; +import net.minecraft.util.hit.HitResult; + +import net.patchworkmc.impl.event.entity.EntityEvents; + +@Mixin(LlamaSpitEntity.class) +public class MixinLlamaSpitEntity { + /** + * Mixin to the projectile hit method, to call {@link net.minecraftforge.event.entity.ProjectileImpactEvent}. + * + *

This will cancel the rest of method_7481 if the forge event pipeline requests it, but a Fabric mod with higher + * priority can still inject into its head.

+ * + *

This mixin is implemented differently from the other onProjectileImpact mixins because there is no check that + * the hit didn't miss before calling onHit, so we need to maintain calls to onHit for missed shots, but still need + * to check that it didn't miss before calling onProjectileImpact.

+ */ + @Inject(method = "method_7481", at = @At("HEAD"), cancellable = true) + private void hookHit(HitResult hitResult, CallbackInfo callback) { + LlamaSpitEntity entity = (LlamaSpitEntity) (Object) this; + + if (EntityEvents.onProjectileImpact(entity, hitResult)) { + callback.cancel(); + } + } +} diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinProjectileEntity.java b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinProjectileEntity.java new file mode 100644 index 00000000..27da7c5d --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinProjectileEntity.java @@ -0,0 +1,54 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin.event.entity; + +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.CallbackInfo; + +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.util.hit.HitResult; + +import net.patchworkmc.impl.event.entity.EntityEvents; + +@Mixin(ProjectileEntity.class) +public class MixinProjectileEntity { + /** + * Mixin to the projectile hit method, to call {@link net.minecraftforge.event.entity.ProjectileImpactEvent}. + * + *

This will cancel the rest of onHit if the event pipeline requests it, but a Fabric mod with higher + * priority can still inject into its head.

+ * + *

This mixin is implemented differently from the other onProjectileImpact mixins because there is no check that + * the hit didn't miss before calling onHit, so we need to maintain calls to onHit for missed shots, but still need + * to check that it didn't miss before calling onProjectileImpact.

+ */ + @Inject(method = "onHit(Lnet/minecraft/util/hit/HitResult;)V", at = @At("HEAD"), cancellable = true) + private void hookHit(HitResult hitResult, CallbackInfo callback) { + if (hitResult.getType() != HitResult.Type.MISS) { + ProjectileEntity entity = (ProjectileEntity) (Object) this; + + if (EntityEvents.onProjectileImpact(entity, hitResult)) { + callback.cancel(); + } + } + } +} diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinShulkerBulletEntity.java b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinShulkerBulletEntity.java new file mode 100644 index 00000000..4f9a1062 --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinShulkerBulletEntity.java @@ -0,0 +1,48 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin.event.entity; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.entity.projectile.ShulkerBulletEntity; +import net.minecraft.util.hit.HitResult; + +import net.patchworkmc.impl.event.entity.EntityEvents; + +@Mixin(ShulkerBulletEntity.class) +public abstract class MixinShulkerBulletEntity { + @Shadow + protected abstract void onHit(HitResult hitResult); + + /** + * Mixin to the redirect the ShulkerBulletEntity hit method, to call {@link net.minecraftforge.event.entity.ProjectileImpactEvent}. + * + *

Note: In future versions, the @Redirect should be replaced with a @ModifyVariable to the bl flag.

+ */ + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/projectile/ShulkerBulletEntity;onHit(Lnet/minecraft/util/hit/HitResult;)V")) + private void hookTick(ShulkerBulletEntity entity, HitResult hitResult) { + if (!EntityEvents.onProjectileImpact(entity, hitResult)) { + this.onHit(hitResult); + } + } +} diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinThrownEntity.java b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinThrownEntity.java new file mode 100644 index 00000000..bc0d7ef0 --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinThrownEntity.java @@ -0,0 +1,48 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin.event.entity; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.entity.thrown.ThrownEntity; +import net.minecraft.util.hit.HitResult; + +import net.patchworkmc.impl.event.entity.EntityEvents; + +@Mixin(ThrownEntity.class) +public abstract class MixinThrownEntity { + @Shadow + protected abstract void onCollision(HitResult hitResult); + + /** + * Mixin to the redirect the ThrownEntity hit method, to call {@link net.minecraftforge.event.entity.ProjectileImpactEvent}. + * + *

Note: In future versions, the @Redirect should be replaced with a @ModifyVariable to the bl flag.

+ */ + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/thrown/ThrownEntity;onCollision(Lnet/minecraft/util/hit/HitResult;)V")) + private void hookTick(ThrownEntity entity, HitResult hitResult) { + if (!EntityEvents.onProjectileImpact(entity, hitResult)) { + this.onCollision(hitResult); + } + } +} diff --git a/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json b/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json index 7c76cbce..55275923 100644 --- a/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json +++ b/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json @@ -8,23 +8,28 @@ "MixinEntityTrackerEntry", "MixinEntityType", "MixinExperienceOrbEntity", + "MixinExplosiveProjectileEntity", "MixinFishingBobberEntity", "MixinFurnaceOutputSlot", "MixinHorseBondWithPlayerGoal", "MixinItemEntity", "MixinLivingEntity", + "MixinLlamaSpitEntity", "MixinMobEntity", "MixinMobSpawnerLogic", "MixinPlayerEntity", "MixinPlayerManager", + "MixinProjectileEntity", "MixinServerPlayerEntity", "MixinServerWorld", + "MixinShulkerBulletEntity", "MixinSpawnHelper", + "MixinThrownEntity", "MixinWorldChunk" ], "client": [ - "MixinClientWorld", "MixinClientPlayerEntity", + "MixinClientWorld", "MixinItemStack", "MixinOtherClientPlayerEntity" ], diff --git a/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index 779dc74a..27cd34c2 100644 --- a/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -29,9 +29,14 @@ import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.passive.AnimalEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.projectile.ExplosiveProjectileEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.entity.thrown.ThrownEntity; import net.minecraft.loot.LootManager; import net.minecraft.loot.LootTable; import net.minecraft.util.Identifier; +import net.minecraft.util.hit.HitResult; import net.minecraft.world.IWorld; import net.minecraft.world.MobSpawnerLogic; import net.minecraft.world.World; @@ -87,4 +92,20 @@ public static float fireBlockHarvesting(DefaultedList drops, World wo public static boolean onAnimalTame(AnimalEntity animal, PlayerEntity tamer) { return EntityEvents.onAnimalTame(animal, tamer); } + + public static boolean onProjectileImpact(Entity entity, HitResult ray) { + return EntityEvents.onProjectileImpact(entity, ray); + } + + public static boolean onProjectileImpact(ProjectileEntity arrow, HitResult ray) { + return EntityEvents.onProjectileImpact(arrow, ray); + } + + public static boolean onProjectileImpact(ExplosiveProjectileEntity fireball, HitResult ray) { + return EntityEvents.onProjectileImpact(fireball, ray); + } + + public static boolean onProjectileImpact(ThrownEntity throwable, HitResult ray) { + return EntityEvents.onProjectileImpact(throwable, ray); + } }