--- a/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
+++ b/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
@@ -18,6 +18,15 @@
 import net.minecraft.world.phys.Vec3D;
 import org.slf4j.Logger;
 
+// CraftBukkit start
+import net.minecraft.tags.DamageTypeTags;
+import net.minecraft.world.level.block.state.IBlockData;
+import org.bukkit.entity.Hanging;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.hanging.HangingBreakByEntityEvent;
+import org.bukkit.event.hanging.HangingBreakEvent;
+// CraftBukkit end
+
 public abstract class BlockAttachedEntity extends Entity {
 
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -44,7 +53,25 @@
             if (this.checkInterval++ == 100) {
                 this.checkInterval = 0;
                 if (!this.isRemoved() && !this.survives()) {
-                    this.discard();
+                    // CraftBukkit start - fire break events
+                    IBlockData material = this.level().getBlockState(this.blockPosition());
+                    HangingBreakEvent.RemoveCause cause;
+
+                    if (!material.isAir()) {
+                        // TODO: This feels insufficient to catch 100% of suffocation cases
+                        cause = HangingBreakEvent.RemoveCause.OBSTRUCTION;
+                    } else {
+                        cause = HangingBreakEvent.RemoveCause.PHYSICS;
+                    }
+
+                    HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), cause);
+                    this.level().getCraftServer().getPluginManager().callEvent(event);
+
+                    if (this.isRemoved() || event.isCancelled()) {
+                        return;
+                    }
+                    // CraftBukkit end
+                    this.discard(EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause
                     this.dropItem(worldserver, (Entity) null);
                 }
             }
@@ -81,6 +108,22 @@
             return false;
         } else {
             if (!this.isRemoved()) {
+                // CraftBukkit start - fire break events
+                Entity damager = (damagesource.isDirect()) ? damagesource.getDirectEntity() : damagesource.getEntity();
+                HangingBreakEvent event;
+                if (damager != null) {
+                    event = new HangingBreakByEntityEvent((Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), damagesource.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.ENTITY);
+                } else {
+                    event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), damagesource.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.DEFAULT);
+                }
+
+                this.level().getCraftServer().getPluginManager().callEvent(event);
+
+                if (this.isRemoved() || event.isCancelled()) {
+                    return true;
+                }
+                // CraftBukkit end
+
                 this.kill(worldserver);
                 this.markHurt();
                 this.dropItem(worldserver, damagesource.getEntity());
@@ -101,6 +144,16 @@
 
         if (world instanceof WorldServer worldserver) {
             if (!this.isRemoved() && vec3d.lengthSqr() > 0.0D) {
+                // CraftBukkit start - fire break events
+                // TODO - Does this need its own cause? Seems to only be triggered by pistons
+                HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), HangingBreakEvent.RemoveCause.PHYSICS);
+                this.level().getCraftServer().getPluginManager().callEvent(event);
+
+                if (this.isRemoved() || event.isCancelled()) {
+                    return;
+                }
+                // CraftBukkit end
+
                 this.kill(worldserver);
                 this.dropItem(worldserver, (Entity) null);
             }
@@ -113,7 +166,7 @@
         World world = this.level();
 
         if (world instanceof WorldServer worldserver) {
-            if (!this.isRemoved() && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) {
+            if (false && !this.isRemoved() && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) { // CraftBukkit - not needed
                 this.kill(worldserver);
                 this.dropItem(worldserver, (Entity) null);
             }
@@ -121,6 +174,15 @@
 
     }
 
+    // CraftBukkit start - selectively save tile position
+    @Override
+    public void addAdditionalSaveData(NBTTagCompound nbttagcompound, boolean includeAll) {
+        if (includeAll) {
+            addAdditionalSaveData(nbttagcompound);
+        }
+    }
+    // CraftBukkit end
+
     @Override
     public void addAdditionalSaveData(NBTTagCompound nbttagcompound) {
         BlockPosition blockposition = this.getPos();
