--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
+++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
@@ -15,16 +15,22 @@
 import net.minecraft.world.entity.EntityType;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.Items;
+import net.minecraft.world.level.ExplosionDamageCalculator;
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.block.BaseFireBlock;
 import net.minecraft.world.level.dimension.end.EndDragonFight;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.entity.ExplosionPrimeEvent;
+// CraftBukkit end
 
 public class EndCrystal extends Entity {
-    private static final EntityDataAccessor<Optional<BlockPos>> DATA_BEAM_TARGET = SynchedEntityData.defineId(
-        EndCrystal.class, EntityDataSerializers.OPTIONAL_BLOCK_POS
-    );
+
+    private static final EntityDataAccessor<Optional<BlockPos>> DATA_BEAM_TARGET = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.OPTIONAL_BLOCK_POS);
     private static final EntityDataAccessor<Boolean> DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN);
     public int time;
+    public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals
 
     public EndCrystal(EntityType<? extends EndCrystal> type, Level world) {
         super(type, world);
@@ -44,21 +50,38 @@
 
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
-        builder.define(DATA_BEAM_TARGET, Optional.empty());
-        builder.define(DATA_SHOW_BOTTOM, true);
+        builder.define(EndCrystal.DATA_BEAM_TARGET, Optional.empty());
+        builder.define(EndCrystal.DATA_SHOW_BOTTOM, true);
     }
 
     @Override
     public void tick() {
-        this.time++;
+        ++this.time;
         this.checkInsideBlocks();
         this.handlePortal();
         if (this.level() instanceof ServerLevel) {
-            BlockPos blockPos = this.blockPosition();
-            if (((ServerLevel)this.level()).getDragonFight() != null && this.level().getBlockState(blockPos).isAir()) {
-                this.level().setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level(), blockPos));
+            BlockPos blockposition = this.blockPosition();
+
+            if (((ServerLevel) this.level()).getDragonFight() != null && this.level().getBlockState(blockposition).isAir()) {
+                // CraftBukkit start
+                if (!CraftEventFactory.callBlockIgniteEvent(this.level(), blockposition, this).isCancelled()) {
+                    this.level().setBlockAndUpdate(blockposition, BaseFireBlock.getState(this.level(), blockposition));
+                }
+                // CraftBukkit end
+            }
+            // Paper start - Fix invulnerable end crystals
+            if (this.level().paperConfig().unsupportedSettings.fixInvulnerableEndCrystalExploit && this.generatedByDragonFight && this.isInvulnerable()) {
+                if (!java.util.Objects.equals(((ServerLevel) this.level()).uuid, this.getOriginWorld())
+                    || ((ServerLevel) this.level()).getDragonFight() == null
+                    || ((ServerLevel) this.level()).getDragonFight().respawnStage == null
+                    || ((ServerLevel) this.level()).getDragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnAnimation.SUMMONING_DRAGON.ordinal()) {
+                    this.setInvulnerable(false);
+                    this.setBeamTarget(null);
+                }
             }
+            // Paper end - Fix invulnerable end crystals
         }
+
     }
 
     @Override
@@ -68,6 +91,7 @@
         }
 
         nbt.putBoolean("ShowBottom", this.showsBottom());
+        if (this.generatedByDragonFight) nbt.putBoolean("Paper.GeneratedByDragonFight", this.generatedByDragonFight); // Paper - Fix invulnerable end crystals
     }
 
     @Override
@@ -76,6 +100,8 @@
         if (nbt.contains("ShowBottom", 1)) {
             this.setShowBottom(nbt.getBoolean("ShowBottom"));
         }
+        if (nbt.contains("Paper.GeneratedByDragonFight", 1)) this.generatedByDragonFight = nbt.getBoolean("Paper.GeneratedByDragonFight"); // Paper - Fix invulnerable end crystals
+
     }
 
     @Override
@@ -91,11 +117,26 @@
             return false;
         } else {
             if (!this.isRemoved() && !this.level().isClientSide) {
-                this.remove(Entity.RemovalReason.KILLED);
+                // CraftBukkit start - All non-living entities need this
+                if (CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount, false)) {
+                    return false;
+                }
+                // CraftBukkit end
                 if (!source.is(DamageTypeTags.IS_EXPLOSION)) {
-                    DamageSource damageSource = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null;
-                    this.level().explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK);
+                    DamageSource damagesource1 = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null;
+
+                    // CraftBukkit start
+                    ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false);
+                    if (event.isCancelled()) {
+                        return false;
+                    }
+
+                    this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
+                    this.level().explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK);
+                } else {
+                    this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
                 }
+                // CraftBukkit end
 
                 this.onDestroyedBy(source);
             }
@@ -112,28 +153,30 @@
 
     private void onDestroyedBy(DamageSource source) {
         if (this.level() instanceof ServerLevel) {
-            EndDragonFight endDragonFight = ((ServerLevel)this.level()).getDragonFight();
-            if (endDragonFight != null) {
-                endDragonFight.onCrystalDestroyed(this, source);
+            EndDragonFight enderdragonbattle = ((ServerLevel) this.level()).getDragonFight();
+
+            if (enderdragonbattle != null) {
+                enderdragonbattle.onCrystalDestroyed(this, source);
             }
         }
+
     }
 
     public void setBeamTarget(@Nullable BlockPos beamTarget) {
-        this.getEntityData().set(DATA_BEAM_TARGET, Optional.ofNullable(beamTarget));
+        this.getEntityData().set(EndCrystal.DATA_BEAM_TARGET, Optional.ofNullable(beamTarget));
     }
 
     @Nullable
     public BlockPos getBeamTarget() {
-        return this.getEntityData().get(DATA_BEAM_TARGET).orElse(null);
+        return (BlockPos) ((Optional) this.getEntityData().get(EndCrystal.DATA_BEAM_TARGET)).orElse((Object) null);
     }
 
     public void setShowBottom(boolean showBottom) {
-        this.getEntityData().set(DATA_SHOW_BOTTOM, showBottom);
+        this.getEntityData().set(EndCrystal.DATA_SHOW_BOTTOM, showBottom);
     }
 
     public boolean showsBottom() {
-        return this.getEntityData().get(DATA_SHOW_BOTTOM);
+        return (Boolean) this.getEntityData().get(EndCrystal.DATA_SHOW_BOTTOM);
     }
 
     @Override
