From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ivan Pekov <ivan@mrivanplays.com>
Date: Sun, 15 Nov 2020 17:06:33 +0200
Subject: [PATCH] Optimise portals

Chunk preloading is being done asynchronously and the code around stuff getting filtered has been
optimised.

diff --git a/src/main/java/net/minecraft/server/PortalTravelAgent.java b/src/main/java/net/minecraft/server/PortalTravelAgent.java
index e10995ec30dd9a10d781b3c1709fd2db5a9becdd..456af55b5908f7192a63c6b15fb93a3480015ab6 100644
--- a/src/main/java/net/minecraft/server/PortalTravelAgent.java
+++ b/src/main/java/net/minecraft/server/PortalTravelAgent.java
@@ -22,6 +22,8 @@ public class PortalTravelAgent {
         // int i = flag ? 16 : 128;
         // CraftBukkit end
 
+        // Yatopia start - replace
+        /*
         villageplace.a(this.world, blockposition, i);
         Optional<VillagePlaceRecord> optional = villageplace.b((villageplacetype) -> {
             return villageplacetype == VillagePlaceType.v;
@@ -32,6 +34,24 @@ public class PortalTravelAgent {
         })).filter((villageplacerecord) -> {
             return this.world.getType(villageplacerecord.f()).b(BlockProperties.E);
         }).findFirst();
+         */
+        villageplace.preloadChunks(world.getChunkProvider(), blockposition, i);
+        java.util.List<VillagePlaceRecord> poiList = villageplace.getFilteredPoiList(
+                (placeType) -> placeType == VillagePlaceType.v,
+                (record) -> world.getType(record.getPosition()).contains(BlockProperties.E),
+                blockposition, i, VillagePlace.Occupancy.ANY);
+        Optional<VillagePlaceRecord> optional = Optional.empty();
+        if (!poiList.isEmpty()) {
+            if (poiList.size() > 1) {
+                poiList.sort(
+                        Comparator.comparingDouble(
+                                (VillagePlaceRecord record) -> record.getPosition().distanceSquared(blockposition)
+                        ).thenComparingInt((record) -> record.getPosition().getY())
+                );
+            }
+            optional = Optional.of(poiList.get(0));
+        }
+        // Yatopia end
 
         return optional.map((villageplacerecord) -> {
             BlockPosition blockposition1 = villageplacerecord.f();
diff --git a/src/main/java/net/minecraft/server/VillagePlace.java b/src/main/java/net/minecraft/server/VillagePlace.java
index 17db6fb6c8f2be2ae37be92891603a889cb7dbfd..8849336437d91022cc33c704059d8b075882bbf3 100644
--- a/src/main/java/net/minecraft/server/VillagePlace.java
+++ b/src/main/java/net/minecraft/server/VillagePlace.java
@@ -214,6 +214,18 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
         }
         return ret;
     }
+    public java.util.List<VillagePlaceRecord> getFilteredPoiList(Predicate<VillagePlaceType> filter, Predicate<VillagePlaceRecord> filterRecords, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) {
+        int j = org.apache.commons.math3.util.FastMath.floorDiv(i, 16) + 1;
+
+        java.util.List<ChunkCoordIntPair> list = ChunkCoordIntPair.streamList(new ChunkCoordIntPair(pos), j);
+        java.util.List<VillagePlaceRecord> ret = new java.util.ArrayList<>();
+        for (ChunkCoordIntPair chunkPos : list) {
+            for (int k = 0; k < 16; k++) {
+                this.d(SectionPosition.a(chunkPos, k).asLong()).ifPresent(section -> ret.addAll(section.getFilteredList(filter, filterRecords, occupancy)));
+            }
+        }
+        return ret;
+    }
     public java.util.List<VillagePlaceRecord> cList(Predicate<VillagePlaceType> predicate, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) {
         int j = i * i;
         java.util.List<VillagePlaceRecord> ret = new java.util.ArrayList<>();
@@ -474,6 +486,18 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
          */ // Yatopia end
     }
 
+    // Yatopia start - this ^ but we accept ChunkProviderServer for async :)
+    public void preloadChunks(ChunkProviderServer chunkProvider, BlockPosition pos, int radius) {
+        for (SectionPosition sectionPos : SectionPosition.getPosList(new ChunkCoordIntPair(pos), org.apache.commons.math3.util.FastMath.floorDiv(radius, 16))) {
+            boolean shouldContinue = this.d(sectionPos.asLong()).map(VillagePlaceSection::isValid).orElse(false);
+            if (shouldContinue) {
+                ChunkCoordIntPair chunkPos = sectionPos.asChunkPos();
+                if (b.add(chunkPos.pair())) { chunkProvider.getChunkAtAsynchronously(chunkPos.x, chunkPos.z, true, false); }
+            }
+        }
+    }
+    // Yatopia end
+
     final class a extends LightEngineGraphSection {
 
         private final Long2ByteMap b = new Long2ByteOpenHashMap();
diff --git a/src/main/java/net/minecraft/server/VillagePlaceSection.java b/src/main/java/net/minecraft/server/VillagePlaceSection.java
index b4ae140eeddb7e31b6d530e74f3c0736529e00d4..3333795f2bdeedb9482af96cfb0ae4ae7b92f5f8 100644
--- a/src/main/java/net/minecraft/server/VillagePlaceSection.java
+++ b/src/main/java/net/minecraft/server/VillagePlaceSection.java
@@ -69,6 +69,19 @@ public class VillagePlaceSection {
         }
         return ret;
     }
+    public java.util.List<VillagePlaceRecord> getFilteredList(Predicate<VillagePlaceType> predicate, Predicate<VillagePlaceRecord> recordFilter, VillagePlace.Occupancy occupancy) {
+        java.util.List<VillagePlaceRecord> ret = new java.util.ArrayList<>();
+        for (Map.Entry<VillagePlaceType, Set<VillagePlaceRecord>> entry : c.entrySet()) {
+            if (predicate.test(entry.getKey())) {
+                for (VillagePlaceRecord record : entry.getValue()) {
+                    if (occupancy.getPredicate().test(record) && recordFilter.test(record)) {
+                        ret.add(record);
+                    }
+                }
+            }
+        }
+        return ret;
+    }
     // Yatopia end
     public Stream<VillagePlaceRecord> a(Predicate<VillagePlaceType> predicate, VillagePlace.Occupancy villageplace_occupancy) {
         return this.c.entrySet().stream().filter((entry) -> {
@@ -180,6 +193,7 @@ public class VillagePlaceSection {
         this.c.clear();
     }
 
+    final boolean isValid() { return a(); } // Yatopia - OBFHELPER
     boolean a() {
         return this.e;
     }
