diff --git a/src/main/java/org/ultramine/mods/bukkit/EventImplProgress.java b/src/main/java/org/ultramine/mods/bukkit/EventImplProgress.java index 504e1b5..4e3c427 100644 --- a/src/main/java/org/ultramine/mods/bukkit/EventImplProgress.java +++ b/src/main/java/org/ultramine/mods/bukkit/EventImplProgress.java @@ -119,7 +119,7 @@ reg(false, org.bukkit.event.entity.SheepRegrowWoolEvent.class); reg(false, org.bukkit.event.entity.SlimeSplitEvent.class); reg(false, org.bukkit.event.hanging.HangingBreakByEntityEvent.class); - reg(false, org.bukkit.event.hanging.HangingBreakEvent.class); + reg(true, org.bukkit.event.hanging.HangingBreakEvent.class); reg(false, org.bukkit.event.hanging.HangingPlaceEvent.class); reg(false, org.bukkit.event.inventory.BrewEvent.class); reg(false, org.bukkit.event.inventory.CraftItemEvent.class); @@ -137,7 +137,7 @@ reg(true, org.bukkit.event.inventory.InventoryPickupItemEvent.class); reg(false, org.bukkit.event.inventory.PrepareItemCraftEvent.class); reg(false, org.bukkit.event.painting.PaintingBreakByEntityEvent.class); - reg(false, org.bukkit.event.painting.PaintingBreakEvent.class); + reg(true, org.bukkit.event.painting.PaintingBreakEvent.class); reg(false, org.bukkit.event.painting.PaintingPlaceEvent.class); reg(true, org.bukkit.event.player.AsyncPlayerChatEvent.class); reg(false, org.bukkit.event.player.AsyncPlayerPreLoginEvent.class); diff --git a/src/main/java/org/ultramine/mods/bukkit/mixin/entity/MixinEntityHanging.java b/src/main/java/org/ultramine/mods/bukkit/mixin/entity/MixinEntityHanging.java new file mode 100644 index 0000000..a81dc49 --- /dev/null +++ b/src/main/java/org/ultramine/mods/bukkit/mixin/entity/MixinEntityHanging.java @@ -0,0 +1,103 @@ +package org.ultramine.mods.bukkit.mixin.entity; + +import net.minecraft.block.material.Material; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityHanging; +import net.minecraft.entity.item.EntityPainting; +import net.minecraft.util.DamageSource; +import net.minecraft.world.World; +import org.bukkit.Bukkit; +import org.bukkit.entity.Hanging; +import org.bukkit.entity.Painting; +import org.bukkit.event.hanging.HangingBreakEvent; +import org.bukkit.event.painting.PaintingBreakEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.ultramine.mods.bukkit.interfaces.entity.IMixinEntity; + +@Mixin(EntityHanging.class) +public abstract class MixinEntityHanging extends Entity +{ + public MixinEntityHanging(World p_i1582_1_) + { + super(p_i1582_1_); + } + + @Inject(method = "onUpdate", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityHanging;setDead()V", shift = Shift.BEFORE)) + public void onUpdateInject(CallbackInfo ci) + { + Material material = this.worldObj.getBlock((int) this.posX, (int) this.posY, (int) this.posZ).getMaterial(); + HangingBreakEvent.RemoveCause cause; + if (!material.equals(Material.air)) + { + // TODO: This feels insufficient to catch 100% of suffocation cases + cause = HangingBreakEvent.RemoveCause.OBSTRUCTION; + } + else + { + cause = HangingBreakEvent.RemoveCause.PHYSICS; + } + HangingBreakEvent event = new HangingBreakEvent((Hanging) ((IMixinEntity) this).getBukkitEntity(), cause); + Bukkit.getPluginManager().callEvent(event); + PaintingBreakEvent paintingEvent = null; + if (((EntityHanging) (Object) this) instanceof EntityPainting) + { + // Fire old painting event until it can be removed + paintingEvent = new PaintingBreakEvent((Painting) ((IMixinEntity) this).getBukkitEntity(), PaintingBreakEvent.RemoveCause.valueOf(cause.name())); + paintingEvent.setCancelled(event.isCancelled()); + Bukkit.getPluginManager().callEvent(paintingEvent); + } + if (isDead || event.isCancelled() || (paintingEvent != null && paintingEvent.isCancelled())) + ci.cancel(); + } + + @Inject(method = "attackEntityFrom", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityHanging;setDead()V", shift = Shift.BEFORE)) + public void attackEntityFromInject(DamageSource damageSource, float p_70097_2_, CallbackInfoReturnable cir) + { + HangingBreakEvent event = new HangingBreakEvent((Hanging) ((IMixinEntity) this).getBukkitEntity(), HangingBreakEvent.RemoveCause.DEFAULT); + PaintingBreakEvent paintingEvent = null; + if (damageSource.getEntity() != null) + { + event = new org.bukkit.event.hanging.HangingBreakByEntityEvent((Hanging) ((IMixinEntity) this).getBukkitEntity(), damageSource.getEntity() == null ? null : ((IMixinEntity) damageSource.getEntity()).getBukkitEntity()); + if (((EntityHanging) (Object) this) instanceof EntityPainting) + { + // Fire old painting event until it can be removed + paintingEvent = new org.bukkit.event.painting.PaintingBreakByEntityEvent((Painting) ((IMixinEntity) this).getBukkitEntity(), damageSource.getEntity() == null ? null : ((IMixinEntity) damageSource.getEntity()).getBukkitEntity()); + } + } + else if (damageSource.isExplosion()) + { + event = new HangingBreakEvent((Hanging) ((IMixinEntity) this).getBukkitEntity(), HangingBreakEvent.RemoveCause.EXPLOSION); + } + Bukkit.getPluginManager().callEvent(event); + if (paintingEvent != null) + { + paintingEvent.setCancelled(event.isCancelled()); + Bukkit.getPluginManager().callEvent(paintingEvent); + } + if (this.isDead || event.isCancelled() || (paintingEvent != null && paintingEvent.isCancelled())) + { + cir.setReturnValue(true); + cir.cancel(); + } + } + + @Inject(method = "moveEntity", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityHanging;setDead()V", shift = Shift.BEFORE)) + public void moveEntity(double x, double y, double z, CallbackInfo ci) + { + if (this.isDead) + { + ci.cancel(); + return; + } + //TODO - Does this need its own cause? Seems to only be triggered by pistons + HangingBreakEvent event = new HangingBreakEvent((Hanging) ((IMixinEntity) this).getBukkitEntity(), HangingBreakEvent.RemoveCause.PHYSICS); + Bukkit.getPluginManager().callEvent(event); + if (this.isDead || event.isCancelled()) + ci.cancel(); + } +} diff --git a/src/main/resources/mixin.umbukkitimpl.json b/src/main/resources/mixin.umbukkitimpl.json index ae37565..20bcc23 100644 --- a/src/main/resources/mixin.umbukkitimpl.json +++ b/src/main/resources/mixin.umbukkitimpl.json @@ -35,6 +35,7 @@ "entity.MixinEntityLiving", "entity.MixinEntityLivingBase", "entity.MixinEntityCreature", + "entity.MixinEntityHanging", "entity.boss.MixinEntityDragon", "entity.boss.MixinEntityWither", "entity.player.MixinPlayer",