--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
+++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
@@ -18,11 +18,17 @@
 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.v1_19_R2.event.CraftEventFactory;
+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<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);
@@ -42,18 +48,34 @@
 
     @Override
     protected void defineSynchedData() {
-        this.getEntityData().define(DATA_BEAM_TARGET, Optional.empty());
-        this.getEntityData().define(DATA_SHOW_BOTTOM, true);
+        this.getEntityData().define(EndCrystal.DATA_BEAM_TARGET, Optional.empty());
+        this.getEntityData().define(EndCrystal.DATA_SHOW_BOTTOM, true);
     }
 
     @Override
     public void tick() {
         ++this.time;
         if (this.level instanceof ServerLevel) {
-            BlockPos blockPos = this.blockPosition();
-            if (((ServerLevel)this.level).dragonFight() != null && this.level.getBlockState(blockPos).isAir()) {
-                this.level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level, blockPos));
+            BlockPos blockposition = this.blockPosition();
+
+            if (((ServerLevel) this.level).dragonFight() != 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).dragonFight() == null
+                    || ((ServerLevel) this.level).dragonFight().respawnStage == null
+                    || ((ServerLevel) this.level).dragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnAnimation.SUMMONING_DRAGON.ordinal()) {
+                    this.setInvulnerable(false);
+                    this.setBeamTarget(null);
+                }
+            }
+            // Paper end
         }
 
     }
@@ -65,6 +87,7 @@
         }
 
         nbt.putBoolean("ShowBottom", this.showsBottom());
+        if (this.generatedByDragonFight) nbt.putBoolean("Paper.GeneratedByDragonFight", this.generatedByDragonFight); // Paper - Fix invulnerable end crystals
     }
 
     @Override
@@ -76,6 +99,7 @@
         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
 
     }
 
@@ -92,10 +116,24 @@
             return false;
         } else {
             if (!this.isRemoved() && !this.level.isClientSide) {
+                // CraftBukkit start - All non-living entities need this
+                if (CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount, false)) {
+                    return false;
+                }
+                // CraftBukkit end
                 this.remove(Entity.RemovalReason.KILLED);
                 if (!source.isExplosion()) {
-                    DamageSource damageSource = source.getEntity() != null ? DamageSource.explosion(this, source.getEntity()) : null;
-                    this.level.explode(this, damageSource, (ExplosionDamageCalculator)null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK);
+                    DamageSource damagesource1 = source.getEntity() != null ? DamageSource.explosion(this, source.getEntity()) : null;
+
+                    // CraftBukkit start
+                    ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 6.0F, false);
+                    this.level.getCraftServer().getPluginManager().callEvent(event);
+                    if (event.isCancelled()) {
+                        this.unsetRemoved();
+                        return false;
+                    }
+                    this.level.explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK);
+                    // CraftBukkit end
                 }
 
                 this.onDestroyedBy(source);
@@ -113,29 +151,30 @@
 
     private void onDestroyedBy(DamageSource source) {
         if (this.level instanceof ServerLevel) {
-            EndDragonFight endDragonFight = ((ServerLevel)this.level).dragonFight();
-            if (endDragonFight != null) {
-                endDragonFight.onCrystalDestroyed(this, source);
+            EndDragonFight enderdragonbattle = ((ServerLevel) this.level).dragonFight();
+
+            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((BlockPos)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
