From a9122ec448cacab56aaaeab5ce3eb0e4f4c7858d Mon Sep 17 00:00:00 2001
From: Martijn <martijnmuijsers@live.nl>
Date: Sat, 26 Aug 2023 22:23:31 +0200
Subject: [PATCH] Do crystal-portal proximity check before entity lookup
 (#9611)

---
 ...l-proximity-check-before-entity-look.patch | 75 +++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 patches/server/Do-crystal-portal-proximity-check-before-entity-look.patch

diff --git a/patches/server/Do-crystal-portal-proximity-check-before-entity-look.patch b/patches/server/Do-crystal-portal-proximity-check-before-entity-look.patch
new file mode 100644
index 0000000000..275c5c9c7d
--- /dev/null
+++ b/patches/server/Do-crystal-portal-proximity-check-before-entity-look.patch
@@ -0,0 +1,75 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Martijn Muijsers <martijnmuijsers@live.nl>
+Date: Tue, 15 Aug 2023 21:04:55 +0200
+Subject: [PATCH] Do crystal-portal proximity check before entity lookup
+
+This adds a very cheap distance check when an end crystal is placed.
+
+Attempting to respawn the dragon, which involves looking up the end crystal
+entities near the portal, every time an end crystal is placed, can be slow on
+some servers that have players placing end crystals as a style of combat.
+
+The very cheap distance check prevents running the entity lookup every time.
+
+diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java
++++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java
+@@ -0,0 +0,0 @@ public class EndCrystalItem extends Item {
+         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;
+@@ -0,0 +0,0 @@ public class EndCrystalItem extends Item {
+                         EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight();
+ 
+                         if (enderdragonbattle != null) {
+-                            enderdragonbattle.tryRespawn();
++                            enderdragonbattle.tryRespawn(aboveBlockPosition); // Paper - pass placed end crystal position to pre-check proximity to portal
+                         }
+                     }
+ 
+diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
++++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
+@@ -0,0 +0,0 @@ public class EndDragonFight {
+     }
+ 
+     public boolean tryRespawn() { // CraftBukkit - return boolean
++        // Paper start - pass null (indicating no placed end crystal involved) by default
++        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
+         if (this.dragonKilled && this.respawnStage == null) {
+             BlockPos blockposition = this.portalLocation;
+ 
+@@ -0,0 +0,0 @@ public class EndDragonFight {
+                 blockposition = this.portalLocation;
+             }
+ 
++            // Paper start - check placed end crystal to portal proximity before attempting to respawn dragon
++            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
++
+             List<EndCrystal> list = Lists.newArrayList();
+             BlockPos blockposition1 = blockposition.above(1);
+             Iterator iterator = Direction.Plane.HORIZONTAL.iterator();