--- a/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -68,7 +68,8 @@
     private static final int GATEWAY_DISTANCE = 96;
     public static final int DRAGON_SPAWN_Y = 128;
     private static final Predicate<Entity> VALID_PLAYER = EntitySelector.ENTITY_STILL_ALIVE.and(EntitySelector.withinDistance(0.0D, 128.0D, 0.0D, 192.0D));
-    public final ServerBossEvent dragonEvent = (ServerBossEvent)(new ServerBossEvent(Component.translatable("entity.minecraft.ender_dragon"), BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS)).setPlayBossMusic(true).setCreateWorldFog(true);
+    private static final Component DEFAULT_BOSS_EVENT_NAME = Component.translatable("entity.minecraft.ender_dragon"); // Paper
+    public final ServerBossEvent dragonEvent = (ServerBossEvent)(new ServerBossEvent(DEFAULT_BOSS_EVENT_NAME, BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS)).setPlayBossMusic(true).setCreateWorldFog(true); // Paper
     public final ServerLevel level;
     private final ObjectArrayList<Integer> gateways = new ObjectArrayList<>();
     private final BlockPattern exitPortalPattern;
@@ -90,6 +91,10 @@
     private List<EndCrystal> respawnCrystals;
 
     public EndDragonFight(ServerLevel world, long gatewaysSeed, CompoundTag nbt) {
+        // Paper start
+        this.needsStateScanning = world.paperConfig().entities.spawning.scanForLegacyEnderDragon;
+        if (!this.needsStateScanning) this.dragonKilled = true;
+        // Paper end
         this.level = world;
         if (nbt.contains("NeedsStateScanning")) {
             this.needsStateScanning = nbt.getBoolean("NeedsStateScanning");
@@ -109,9 +114,11 @@
             if (nbt.contains("ExitPortalLocation", 10)) {
                 this.portalLocation = NbtUtils.readBlockPos(nbt.getCompound("ExitPortalLocation"));
             }
-        } else {
-            this.dragonKilled = true;
-            this.previouslyKilled = true;
+            // Paper start - Killed statuses should be false for newly created worlds
+            // } else {
+            //     this.dragonKilled = true;
+            //     this.previouslyKilled = true;
+            // Paper end
         }
 
         if (nbt.contains("Gateways", 9)) {
@@ -214,7 +221,7 @@
             this.dragonUUID = enderDragon.getUUID();
             LOGGER.info("Found that there's a dragon still alive ({})", (Object)enderDragon);
             this.dragonKilled = false;
-            if (!bl) {
+            if (!bl && this.level.paperConfig().entities.behavior.shouldRemoveDragon) {
                 LOGGER.info("But we didn't have a portal, let's remove it.");
                 enderDragon.discard();
                 this.dragonUUID = null;
@@ -366,9 +373,23 @@
             this.dragonEvent.setVisible(false);
             this.spawnExitPortal(true);
             this.spawnNewGateway();
-            if (!this.previouslyKilled) {
-                this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.END_PODIUM_LOCATION), Blocks.DRAGON_EGG.defaultBlockState());
+            // Paper start - DragonEggFormEvent
+            BlockPos eggPosition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.END_PODIUM_LOCATION);
+            org.bukkit.craftbukkit.v1_19_R2.block.CraftBlockState eggState = org.bukkit.craftbukkit.v1_19_R2.block.CraftBlockStates.getBlockState(this.level, eggPosition);
+            eggState.setData(Blocks.DRAGON_EGG.defaultBlockState());
+            io.papermc.paper.event.block.DragonEggFormEvent eggEvent = new io.papermc.paper.event.block.DragonEggFormEvent(org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock.at(this.level, eggPosition), eggState,
+                new org.bukkit.craftbukkit.v1_19_R2.boss.CraftDragonBattle(this));
+            // Paper end - DragonEggFormEvent
+            if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - always place dragon egg
+                // Paper start - DragonEggFormEvent
+                //this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.END_PODIUM_LOCATION), Blocks.DRAGON_EGG.defaultBlockState());
+            } else {
+                eggEvent.setCancelled(true);
+            }
+            if (eggEvent.callEvent()) {
+                eggEvent.getNewState().update(true);
             }
+            // Paper end - DragonEggFormEvent
 
             this.previouslyKilled = true;
             this.dragonKilled = true;
@@ -401,6 +422,11 @@
             }
         }
 
+        // Paper start - Prevent "softlocked" exit portal generation
+        if (this.portalLocation.getY() <= this.level.getMinBuildHeight()) {
+            this.portalLocation = this.portalLocation.atY(this.level.getMinBuildHeight() + 1);
+        }
+        // Paper end
         endPodiumFeature.place(FeatureConfiguration.NONE, this.level, this.level.getChunkSource().getGenerator(), RandomSource.create(), this.portalLocation);
     }
 
@@ -413,6 +439,7 @@
             enderDragon.moveTo(0.0D, 128.0D, 0.0D, this.level.random.nextFloat() * 360.0F, 0.0F);
             this.level.addFreshEntity(enderDragon);
             this.dragonUUID = enderDragon.getUUID();
+            this.resetSpikeCrystals(); // Paper
         }
 
         return enderDragon;
@@ -424,6 +451,10 @@
             this.ticksSinceDragonSeen = 0;
             if (dragon.hasCustomName()) {
                 this.dragonEvent.setName(dragon.getDisplayName());
+                // Paper start - reset to default name
+            } else {
+                this.dragonEvent.setName(DEFAULT_BOSS_EVENT_NAME);
+                // Paper end
             }
         }
 
