diff --git a/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch
index ba84da3813..89844fdef2 100644
--- a/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch
@@ -1,6 +1,15 @@
 --- a/net/minecraft/world/item/EndCrystalItem.java
 +++ b/net/minecraft/world/item/EndCrystalItem.java
-@@ -47,6 +47,12 @@
+@@ -30,7 +30,7 @@
+         if (!iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) {
+             return InteractionResult.FAIL;
+         } else {
+-            BlockPos blockposition1 = blockposition.above();
++            BlockPos blockposition1 = blockposition.above(); final BlockPos aboveBlockPosition = blockposition1; // Paper - OBFHELPER
+ 
+             if (!world.isEmptyBlock(blockposition1)) {
+                 return InteractionResult.FAIL;
+@@ -47,12 +47,18 @@
                          EndCrystal entityendercrystal = new EndCrystal(world, d0 + 0.5D, d1, d2 + 0.5D);
  
                          entityendercrystal.setShowBottom(false);
@@ -13,3 +22,10 @@
                          world.addFreshEntity(entityendercrystal);
                          world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.ENTITY_PLACE, blockposition1);
                          EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight();
+ 
+                         if (enderdragonbattle != null) {
+-                            enderdragonbattle.tryRespawn();
++                            enderdragonbattle.tryRespawn(aboveBlockPosition); // Paper - Perf: Do crystal-portal proximity check before entity lookup
+                         }
+                     }
+ 
diff --git a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch
index b0ef43a495..5514be96df 100644
--- a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch
@@ -78,7 +78,7 @@
  
              this.previouslyKilled = true;
              this.dragonKilled = true;
-@@ -419,8 +440,26 @@
+@@ -419,7 +440,25 @@
      @VisibleForTesting
      public void removeAllGateways() {
          this.gateways.clear();
@@ -91,20 +91,19 @@
 +            return true;
 +        }
 +        return false;
-     }
- 
++    }
++
 +    public List<EndCrystal> getSpikeCrystals() {
 +        final List<EndCrystal> endCrystals = new java.util.ArrayList<>();
 +        for (final SpikeFeature.EndSpike spike : SpikeFeature.getSpikesForLevel(this.level)) {
 +            endCrystals.addAll(this.level.getEntitiesOfClass(EndCrystal.class, spike.getTopBoundingBox()));
 +        }
 +        return endCrystals;
-+    }
+     }
 +    // Paper end - More DragonBattle API
-+
+ 
      private void spawnNewGateway() {
          if (!this.gateways.isEmpty()) {
-             int i = (Integer) this.gateways.remove(this.gateways.size() - 1);
 @@ -449,6 +488,11 @@
              }
          }
@@ -136,16 +135,45 @@
              }
          }
  
-@@ -513,7 +562,7 @@
+@@ -513,7 +562,13 @@
          return this.previouslyKilled;
      }
  
 -    public void tryRespawn() {
 +    public boolean tryRespawn() { // CraftBukkit - return boolean
++        // Paper start - Perf: Do crystal-portal proximity check before entity lookup
++        return this.tryRespawn(null);
++    }
++
++    public boolean tryRespawn(@Nullable BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal
++        // Paper end - Perf: Do crystal-portal proximity check before entity lookup
          if (this.dragonKilled && this.respawnStage == null) {
              BlockPos blockposition = this.portalLocation;
  
-@@ -540,19 +589,19 @@
+@@ -531,6 +586,22 @@
+                 blockposition = this.portalLocation;
+             }
+ 
++            // Paper start - Perf: Do crystal-portal proximity check before entity lookup
++            if (placedEndCrystalPos != null) {
++                // The end crystal must be 0 or 1 higher than the portal origin
++                int dy = placedEndCrystalPos.getY() - blockposition.getY();
++                if (dy != 0 && dy != 1) {
++                    return false;
++                }
++                // The end crystal must be within a distance of 1 in one planar direction, and 3 in the other
++                int dx = placedEndCrystalPos.getX() - blockposition.getX();
++                int dz = placedEndCrystalPos.getZ() - blockposition.getZ();
++                if (!((dx >= -1 && dx <= 1 && dz >= -3 && dz <= 3) || (dx >= -3 && dx <= 3 && dz >= -1 && dz <= 1))) {
++                    return false;
++                }
++            }
++            // Paper end - Perf: Do crystal-portal proximity check before entity lookup
++
+             List<EndCrystal> list = Lists.newArrayList();
+             BlockPos blockposition1 = blockposition.above(1);
+             Iterator iterator = Direction.Plane.HORIZONTAL.iterator();
+@@ -540,19 +611,19 @@
                  List<EndCrystal> list1 = this.level.getEntitiesOfClass(EndCrystal.class, new AABB(blockposition1.relative(enumdirection, 2)));
  
                  if (list1.isEmpty()) {
@@ -169,7 +197,7 @@
          if (this.dragonKilled && this.respawnStage == null) {
              for (BlockPattern.BlockPatternMatch shapedetector_shapedetectorcollection = this.findExitPortal(); shapedetector_shapedetectorcollection != null; shapedetector_shapedetectorcollection = this.findExitPortal()) {
                  for (int i = 0; i < this.exitPortalPattern.getWidth(); ++i) {
-@@ -571,9 +620,10 @@
+@@ -571,9 +642,10 @@
              this.respawnStage = DragonRespawnAnimation.START;
              this.respawnTime = 0;
              this.spawnExitPortal(false);