From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ivan Pekov <ivan@mrivanplays.com>
Date: Thu, 27 Aug 2020 10:46:17 +0300
Subject: [PATCH] Highly optimize VillagePlace filtering

Replaced all streams I could. I expect this to be dropped in the next
major release and reimplemented again if mojang changes stuff with
villagers again.

diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/Producer.java b/src/main/java/me/jellysquid/mods/lithium/common/util/Producer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e647624f4c9afe8bc603792ad88c807ed9f01250
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/util/Producer.java
@@ -0,0 +1,53 @@
+package me.jellysquid.mods.lithium.common.util;
+
+import java.util.List;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import org.yatopiamc.yatopia.server.util.HoldingConsumer;
+
+public interface Producer<T> {
+    /**
+     * Computes the next sequence of values in a collection. If a null value is passed for {@param consumer}, then
+     * the producer will only return whether or not elements existed.
+     *
+     * @param consumer The (nullable) consumer which will accept the computed values during this run.
+     * @return True if the producer produced any values, otherwise false
+     */
+    boolean computeNext(Consumer<? super T> consumer);
+
+    default <U> Producer<U> map(Function<T, U> mapper) {
+        return consumer -> {
+            Consumer<? super T> con = (t) -> consumer.accept(mapper.apply(t));
+            return Producer.this.computeNext(con);
+        };
+    }
+
+    static <T> Stream<T> asStream(Producer<T> producer) {
+        return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.NONNULL) {
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                return producer.computeNext(action);
+            }
+        }, false);
+    }
+
+    static <T> void fillList(Producer<T> producer, List<T> list) {
+        HoldingConsumer<T> consumer = new HoldingConsumer<>();
+        while (producer.computeNext(consumer)) {
+            T value = consumer.getValue();
+            if (value == null || list.contains(value)) { continue; }
+            list.add(value);
+        }
+    }
+
+    Producer<?> EMPTY_PRODUCER = consumer -> false;
+
+    @SuppressWarnings("unchecked")
+    static <T> Producer<T> empty() {
+        return (Producer<T>) EMPTY_PRODUCER;
+    }
+}
diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java
index bc61aaff65a7dc1e7534452b285953b83adb7000..7fddef0afbcf1f9f391c540b8fce1bebf8faa452 100644
--- a/src/main/java/net/minecraft/server/BlockPosition.java
+++ b/src/main/java/net/minecraft/server/BlockPosition.java
@@ -341,6 +341,16 @@ public class BlockPosition extends BaseBlockPosition {
         return a(MathHelper.floor(axisalignedbb.minX), MathHelper.floor(axisalignedbb.minY), MathHelper.floor(axisalignedbb.minZ), MathHelper.floor(axisalignedbb.maxX), MathHelper.floor(axisalignedbb.maxY), MathHelper.floor(axisalignedbb.maxZ));
     }
 
+    // Yatopia start
+    public static java.util.List<BlockPosition> getPositions(int i, int j, int k, int l, int i1, int j1) {
+        java.util.List<BlockPosition> ret = new java.util.ArrayList<>();
+        Iterable<BlockPosition> iterable = b(i, j, k, l, i1, j1);
+        org.yatopiamc.yatopia.server.util.HoldingConsumer<BlockPosition> consumer = new org.yatopiamc.yatopia.server.util.HoldingConsumer<>();
+        java.util.Spliterator<BlockPosition> spliterator = iterable.spliterator();
+        while (spliterator.tryAdvance(consumer)) ret.add(consumer.getValue());
+        return ret;
+    }
+    // Yatopia end
     public static Stream<BlockPosition> a(int i, int j, int k, int l, int i1, int j1) {
         return StreamSupport.stream(b(i, j, k, l, i1, j1).spliterator(), false);
     }
diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
index 271fddbbf73ca5c0e4e2722d7246c14b778d6072..860943989b10a4f65c0de345a56aaa00f0959214 100644
--- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
+++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
@@ -118,6 +118,15 @@ public class ChunkCoordIntPair {
         return a(new ChunkCoordIntPair(chunkcoordintpair.x - i, chunkcoordintpair.z - i), new ChunkCoordIntPair(chunkcoordintpair.x + i, chunkcoordintpair.z + i));
     }
 
+    // Yatopia start
+    public static java.util.List<ChunkCoordIntPair> streamList(ChunkCoordIntPair center, int radius) {
+        return streamList(new ChunkCoordIntPair(center.x - radius, center.z - radius), new ChunkCoordIntPair(center.x + radius, center.z + radius));
+    }
+    public static java.util.List<ChunkCoordIntPair> streamList(ChunkCoordIntPair pos1, ChunkCoordIntPair pos2) {
+        return org.yatopiamc.yatopia.server.YatopiaChunkPos.asList(pos1, pos2);
+    }
+    // Yatopia end
+
     public static Stream<ChunkCoordIntPair> a(final ChunkCoordIntPair chunkcoordintpair, final ChunkCoordIntPair chunkcoordintpair1) {
         int i = Math.abs(chunkcoordintpair.x - chunkcoordintpair1.x) + 1;
         int j = Math.abs(chunkcoordintpair.z - chunkcoordintpair1.z) + 1;
diff --git a/src/main/java/net/minecraft/server/EntityBee.java b/src/main/java/net/minecraft/server/EntityBee.java
index bef806bfc60792a990209b57f3cd4b9da0c24acc..6aee58fb0c6b9c1ae4ac6157e02a5050cd835536 100644
--- a/src/main/java/net/minecraft/server/EntityBee.java
+++ b/src/main/java/net/minecraft/server/EntityBee.java
@@ -781,15 +781,19 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB
         private List<BlockPosition> j() {
             BlockPosition blockposition = EntityBee.this.getChunkCoordinates();
             VillagePlace villageplace = ((WorldServer) EntityBee.this.world).y();
-            Stream<VillagePlaceRecord> stream = villageplace.c((villageplacetype) -> {
+            List<BlockPosition> stream = villageplace.cListPositions((villageplacetype) -> { // Yatopia
                 return villageplacetype == VillagePlaceType.t || villageplacetype == VillagePlaceType.u;
-            }, blockposition, 20, VillagePlace.Occupancy.ANY);
-
+            }, (record) -> i(record.getPosition()), blockposition, 20, VillagePlace.Occupancy.ANY); // Yatopia
+            // Yatopia start
+            stream.sort(Comparator.comparingDouble((pos1) -> pos1.distanceSquared(blockposition)));
+            return stream;
+            /*
             return (List) stream.map(VillagePlaceRecord::f).filter((blockposition1) -> {
                 return EntityBee.this.i(blockposition1);
             }).sorted(Comparator.comparingDouble((blockposition1) -> {
                 return blockposition1.j(blockposition);
             })).collect(Collectors.toList());
+             */ // Yatopia end
         }
     }
 
diff --git a/src/main/java/net/minecraft/server/PersistentRaid.java b/src/main/java/net/minecraft/server/PersistentRaid.java
index 807910c60e6cad58b91474b0477e6fc109eaf281..f003f95aca2c9a41b548c8ca2de1194818268c80 100644
--- a/src/main/java/net/minecraft/server/PersistentRaid.java
+++ b/src/main/java/net/minecraft/server/PersistentRaid.java
@@ -80,7 +80,7 @@ public class PersistentRaid extends PersistentBase {
                 return null;
             } else {
                 BlockPosition blockposition = entityplayer.getChunkCoordinates();
-                List<VillagePlaceRecord> list = (List) this.b.y().c(VillagePlaceType.b, blockposition, 64, VillagePlace.Occupancy.IS_OCCUPIED).collect(Collectors.toList());
+                List<VillagePlaceRecord> list = this.b.y().cList(VillagePlaceType.b, blockposition, 64, VillagePlace.Occupancy.IS_OCCUPIED); // Yatopia
                 int i = 0;
                 Vec3D vec3d = Vec3D.ORIGIN;
 
diff --git a/src/main/java/net/minecraft/server/SectionPosition.java b/src/main/java/net/minecraft/server/SectionPosition.java
index 0bb3ad0bffc04eba38cd827eaf5c63e8bf2aee93..8e90fabb0681457ec140f8553799463023a7a03b 100644
--- a/src/main/java/net/minecraft/server/SectionPosition.java
+++ b/src/main/java/net/minecraft/server/SectionPosition.java
@@ -159,6 +159,7 @@ public class SectionPosition extends BaseBlockPosition {
         return this.p().b(8, 8, 8);
     }
 
+    public final ChunkCoordIntPair asChunkPos() { return r(); } // Yatopia - OBFHELPER
     public ChunkCoordIntPair r() {
         return new ChunkCoordIntPair(this.a(), this.c());
     }
@@ -173,10 +174,12 @@ public class SectionPosition extends BaseBlockPosition {
         return (((long) i & 4194303L) << 42) | (((long) j & 1048575L)) | (((long) k & 4194303L) << 20); // Paper - Simplify to reduce instruction count
     }
 
+    public final long asLong() { return s(); } // Yatopia - OBFHELPER
     public long s() {
         return (((long) getX() & 4194303L) << 42) | (((long) getY() & 1048575L)) | (((long) getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count
     }
 
+    public java.util.List<BlockPosition> tList() { return BlockPosition.getPositions(d(), e(), f(), g(), h(), i()); } // Yatopia
     public Stream<BlockPosition> t() {
         return BlockPosition.a(this.d(), this.e(), this.f(), this.g(), this.h(), this.i());
     }
@@ -189,6 +192,18 @@ public class SectionPosition extends BaseBlockPosition {
         return a(chunkcoordintpair.x - i, 0, chunkcoordintpair.z - i, chunkcoordintpair.x + i, 15, chunkcoordintpair.z + i); // Paper - simplify/inline
     }
 
+    // Yatopia start
+    public static java.util.List<SectionPosition> getPosList(SectionPosition pos, int i) {
+        return getPosList(pos.getX() - i, pos.getY() - i, pos.getZ() - i, pos.getX() + i, pos.getY() + i, pos.getZ() + i);
+    }
+    public static java.util.List<SectionPosition> getPosList(ChunkCoordIntPair chunkPos, int i) {
+        return getPosList(chunkPos.x - i, 0, chunkPos.z - i, chunkPos.x + i, 15, chunkPos.z + i);
+    }
+    public static java.util.List<SectionPosition> getPosList(int i, int j, int k, int l, int i1, int j1) {
+        return org.yatopiamc.yatopia.server.YatopiaChunkSectionPos.getChunkSectionPosList(i, j, k, l,  i1, j1);
+    }
+    // Yatopia end
+
     public static Stream<SectionPosition> a(final int i, final int j, final int k, final int l, final int i1, final int j1) {
         return StreamSupport.stream(new AbstractSpliterator<SectionPosition>((long) ((l - i + 1) * (i1 - j + 1) * (j1 - k + 1)), 64) {
             final CursorPosition a = new CursorPosition(i, j, k, l, i1, j1);
diff --git a/src/main/java/net/minecraft/server/VillagePlace.java b/src/main/java/net/minecraft/server/VillagePlace.java
index 44063d599e39e087b3eccfe204ef2fd79c3364e5..17db6fb6c8f2be2ae37be92891603a889cb7dbfd 100644
--- a/src/main/java/net/minecraft/server/VillagePlace.java
+++ b/src/main/java/net/minecraft/server/VillagePlace.java
@@ -180,7 +180,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
 
     public long count(Predicate<VillagePlaceType> predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { return a(predicate, blockposition, i, villageplace_occupancy); } // Purpur - OBFHELPER
     public long a(Predicate<VillagePlaceType> predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
-        return this.c(predicate, blockposition, i, villageplace_occupancy).count();
+        return this.cList(predicate, blockposition, i, villageplace_occupancy).size(); // Yatopia
     }
 
     public boolean a(VillagePlaceType villageplacetype, BlockPosition blockposition) {
@@ -201,6 +201,39 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
         });
     }
 
+    // Yatopia start
+    public java.util.List<VillagePlaceRecord> bList(Predicate<VillagePlaceType> filter, 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++) { // ITS THE LAW
+                this.d(SectionPosition.a(chunkPos, k).asLong()).ifPresent(section -> ret.addAll(section.aList(filter, 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<>();
+        for (VillagePlaceRecord record : this.bList(predicate, pos, i, occupancy)) {
+            if (record.getPosition().distanceSquared(pos) <= j) { ret.add(record); }
+        }
+        return ret;
+    }
+
+    public java.util.List<BlockPosition> cListPositions(Predicate<VillagePlaceType> predicate, Predicate<VillagePlaceRecord> recordFilter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) {
+        int j = i * i;
+        java.util.List<BlockPosition> ret = new java.util.ArrayList<>();
+        for (VillagePlaceRecord record : this.bList(predicate, pos, i, occupancy)) {
+            BlockPosition recordPosition = record.getPosition();
+            if (recordPosition.distanceSquared(pos) <= j && recordFilter.test(record)) { ret.add(recordPosition); }
+        }
+        return ret;
+    }
+    // Yatopia end
+
     public Stream<VillagePlaceRecord> c(Predicate<VillagePlaceType> predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
         int j = i * i;
 
@@ -217,10 +250,28 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
         });
     }
 
+    // Yatopia start
+    public java.util.List<BlockPosition> aList(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> posFilter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) {
+        java.util.List<BlockPosition> ret = new java.util.ArrayList<>();
+        int j = i * i;
+        for (VillagePlaceRecord record : this.bList(predicate, pos, i, occupancy)) {
+            BlockPosition recordPosition = record.getPosition();
+            if (recordPosition.distanceSquared(pos) <= j && posFilter.test(recordPosition)) { ret.add(recordPosition); }
+        }
+        return ret;
+    }
+    // Yatopia end
     public Stream<BlockPosition> a(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
         return this.c(predicate, blockposition, i, villageplace_occupancy).map(VillagePlaceRecord::f).filter(predicate1);
     }
 
+    // Yatopia start
+    public java.util.List<BlockPosition> bList(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> posFilter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) {
+        java.util.List<BlockPosition> ret = aList(predicate, posFilter, pos, i, occupancy);
+        ret.sort(Comparator.comparingDouble((pos1) -> pos1.distanceSquared(pos)));
+        return ret;
+    }
+    // Yatopia end
     public Stream<BlockPosition> b(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
         return this.a(predicate, predicate1, blockposition, i, villageplace_occupancy).sorted(Comparator.comparingDouble((blockposition1) -> {
             return blockposition1.j(blockposition);
@@ -228,31 +279,68 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
     }
 
     public Optional<BlockPosition> c(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
-        return this.a(predicate, predicate1, blockposition, i, villageplace_occupancy).findFirst();
+        // Yatopia start
+        for (VillagePlaceRecord record : this.cList(predicate, blockposition, i, villageplace_occupancy)) {
+            BlockPosition recordPosition = record.getPosition();
+            if (predicate1.test(recordPosition)) return Optional.of(recordPosition);
+        }
+        return Optional.empty();
+        // Yatopia end
     }
 
     public Optional<BlockPosition> d(Predicate<VillagePlaceType> predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
+        // Yatopia start
+        VillagePlaceRecord best = null;
+        for (VillagePlaceRecord record : cList(predicate, blockposition, i, villageplace_occupancy)) {
+            BlockPosition recordPos = record.getPosition();
+            if (best == null || (recordPos.distanceSquared(blockposition) < best.getPosition().distanceSquared(blockposition))) {
+                best = record;
+            }
+        }
+        return best == null ? Optional.empty() : Optional.of(best.getPosition());
+        /*
         return this.c(predicate, blockposition, i, villageplace_occupancy).map(VillagePlaceRecord::f).min(Comparator.comparingDouble((blockposition1) -> {
             return blockposition1.j(blockposition);
         }));
+         */ // Yatopia end
     }
 
     public Optional<BlockPosition> a(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> predicate1, BlockPosition blockposition, int i) {
+        // Yatopia start
+        int j = i * i;
+        for (VillagePlaceRecord record : this.bList(predicate, blockposition, i, VillagePlace.Occupancy.HAS_SPACE)) {
+            BlockPosition recordPos = record.getPosition();
+            if (recordPos.distanceSquared(blockposition) <= j && predicate1.test(recordPos)) {
+                record.b();
+                return Optional.of(recordPos);
+            }
+        }
+        return Optional.empty();
+        /*
         return this.c(predicate, blockposition, i, VillagePlace.Occupancy.HAS_SPACE).filter((villageplacerecord) -> {
             return predicate1.test(villageplacerecord.f());
         }).findFirst().map((villageplacerecord) -> {
             villageplacerecord.b();
             return villageplacerecord.f();
         });
+        */ // Yatopia end
     }
 
     public Optional<BlockPosition> a(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> predicate1, VillagePlace.Occupancy villageplace_occupancy, BlockPosition blockposition, int i, Random random) {
-        List<VillagePlaceRecord> list = (List) this.c(predicate, blockposition, i, villageplace_occupancy).collect(Collectors.toList());
+        List<VillagePlaceRecord> list = this.cList(predicate, blockposition, i, villageplace_occupancy); // Yatopia
 
         Collections.shuffle(list, random);
+        // Yatopia start - replace stream
+        for (VillagePlaceRecord record : list) {
+            BlockPosition recordPosition = record.getPosition();
+            if (predicate1.test(recordPosition)) return Optional.of(recordPosition);
+        }
+        return Optional.empty();
+        /*
         return list.stream().filter((villageplacerecord) -> {
             return predicate1.test(villageplacerecord.f());
         }).findFirst().map(VillagePlaceRecord::f);
+         */ // Yatopia end
     }
 
     public boolean b(BlockPosition blockposition) {
@@ -352,7 +440,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
     }
 
     private void a(ChunkSection chunksection, SectionPosition sectionposition, BiConsumer<BlockPosition, VillagePlaceType> biconsumer) {
-        sectionposition.t().forEach((blockposition) -> {
+        sectionposition.tList().forEach((blockposition) -> { // Yatopia
             IBlockData iblockdata = chunksection.getType(SectionPosition.b(blockposition.getX()), SectionPosition.b(blockposition.getY()), SectionPosition.b(blockposition.getZ()));
 
             VillagePlaceType.b(iblockdata).ifPresent((villageplacetype) -> {
@@ -362,6 +450,16 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
     }
 
     public void a(IWorldReader iworldreader, BlockPosition blockposition, int i) {
+        // Yatopia start - WHY?
+        java.util.List<SectionPosition> posList = SectionPosition.getPosList(new ChunkCoordIntPair(blockposition), org.apache.commons.math3.util.FastMath.floorDiv(i, 16));
+        for (SectionPosition pos : posList) {
+            boolean shouldContinue = this.d(pos.asLong()).map(VillagePlaceSection::a).orElse(false);
+            if (shouldContinue) {
+                ChunkCoordIntPair chunkPos = pos.asChunkPos();
+                if (b.add(chunkPos.pair())) { iworldreader.getChunkAt(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY); }
+            }
+        }
+        /*
         SectionPosition.b(new ChunkCoordIntPair(blockposition), Math.floorDiv(i, 16)).map((sectionposition) -> {
             return Pair.of(sectionposition, this.d(sectionposition.s()));
         }).filter((pair) -> {
@@ -373,6 +471,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
         }).forEach((chunkcoordintpair) -> {
             iworldreader.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z, ChunkStatus.EMPTY);
         });
+         */ // Yatopia end
     }
 
     final class a extends LightEngineGraphSection {
diff --git a/src/main/java/net/minecraft/server/VillagePlaceSection.java b/src/main/java/net/minecraft/server/VillagePlaceSection.java
index 943a437ff27162eae09211c28bdc0d141fa6a404..b4ae140eeddb7e31b6d530e74f3c0736529e00d4 100644
--- a/src/main/java/net/minecraft/server/VillagePlaceSection.java
+++ b/src/main/java/net/minecraft/server/VillagePlaceSection.java
@@ -5,6 +5,10 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.mojang.serialization.Codec;
 import com.mojang.serialization.codecs.RecordCodecBuilder;
+// Yatopia start
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
+// Yatopia end
 import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
 import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
 import java.util.List;
@@ -49,12 +53,23 @@ public class VillagePlaceSection {
 
     private VillagePlaceSection(Runnable runnable, boolean flag, List<VillagePlaceRecord> list) {
         this.b = new Short2ObjectOpenHashMap();
-        this.c = Maps.newHashMap();
+        this.c = new Reference2ReferenceOpenHashMap<>(); // Yatopia
         this.d = runnable;
         this.e = flag;
         list.forEach(this::a);
     }
 
+    // Yatopia start
+    public java.util.List<VillagePlaceRecord> aList(Predicate<VillagePlaceType> predicate, 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.a().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) -> {
             return predicate.test(entry.getKey());
@@ -97,7 +112,7 @@ public class VillagePlaceSection {
 
         this.b.put(short0, villageplacerecord);
         ((Set) this.c.computeIfAbsent(villageplacetype, (villageplacetype1) -> {
-            return Sets.newHashSet();
+            return new ObjectOpenHashSet<>(); // Yatopia
         })).add(villageplacerecord);
         return true;
     }
diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaChunkPos.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaChunkPos.java
new file mode 100644
index 0000000000000000000000000000000000000000..de95cf5ca20abdc8f200806287fb0ba03eec1e7c
--- /dev/null
+++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaChunkPos.java
@@ -0,0 +1,54 @@
+package org.yatopiamc.yatopia.server;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import me.jellysquid.mods.lithium.common.util.Producer;
+import net.minecraft.server.ChunkCoordIntPair;
+
+public class YatopiaChunkPos {
+
+    public static List<ChunkCoordIntPair> asList(ChunkCoordIntPair pos1, ChunkCoordIntPair pos2) {
+        List<ChunkCoordIntPair> list = new ArrayList<>();
+        Producer.fillList(getStreamProducer(pos1, pos2), list);
+        return list;
+    }
+
+    /**
+     * [VanillaCopy] but in a producer
+     *
+     * @param pos1 pos 1
+     * @param pos2 pos 2
+     * @return producer
+     */
+    private static Producer<ChunkCoordIntPair> getStreamProducer(ChunkCoordIntPair pos1, ChunkCoordIntPair pos2) {
+        final int k = pos1.x < pos2.x ? 1 : -1;
+        final int l = pos1.z < pos2.z ? 1 : -1;
+
+        return new Producer<ChunkCoordIntPair>() {
+            private ChunkCoordIntPair pair = null;
+
+            @Override
+            public boolean computeNext(Consumer<? super ChunkCoordIntPair> consumer) {
+                if (pair == null) {
+                    pair = pos1;
+                } else {
+                    int i1 = this.pair.x;
+                    int j1 = this.pair.z;
+
+                    if (i1 == pos2.x) {
+                        if (j1 == pos2.z) {
+                            return false;
+                        }
+
+                        this.pair = new ChunkCoordIntPair(pos1.x, j1 + l);
+                    } else {
+                        this.pair = new ChunkCoordIntPair(i1 + k, j1);
+                    }
+                }
+                consumer.accept(pair);
+                return true;
+            }
+        };
+    }
+}
diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaChunkSectionPos.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaChunkSectionPos.java
new file mode 100644
index 0000000000000000000000000000000000000000..d298cf985def6d7adcc6156b1476f86c085ad5e7
--- /dev/null
+++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaChunkSectionPos.java
@@ -0,0 +1,32 @@
+package org.yatopiamc.yatopia.server;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import me.jellysquid.mods.lithium.common.util.Producer;
+import net.minecraft.server.CursorPosition;
+import net.minecraft.server.SectionPosition;
+
+public class YatopiaChunkSectionPos {
+
+    public static List<SectionPosition> getChunkSectionPosList(int i, int j, int k, int l, int i1, int j1) {
+        List<SectionPosition> list = new ArrayList<>();
+        Producer.fillList(getChunkSectionPosProducer(i, j, k, l, i1, j1), list);
+        return list;
+    }
+
+    private static Producer<SectionPosition> getChunkSectionPosProducer(int i, int j, int k, int l, int i1, int j1) {
+        return new Producer<SectionPosition>() {
+            final CursorPosition cursorPos = new CursorPosition(i, j, k, l, i1, j1);
+
+            @Override
+            public boolean computeNext(Consumer<? super SectionPosition> consumer) {
+                if (cursorPos.a()) {
+                    consumer.accept(SectionPosition.a(cursorPos.b(), cursorPos.c(), cursorPos.d()));
+                    return true;
+                }
+                return false;
+            }
+        };
+    }
+}
diff --git a/src/main/java/org/yatopiamc/yatopia/server/util/HoldingConsumer.java b/src/main/java/org/yatopiamc/yatopia/server/util/HoldingConsumer.java
new file mode 100644
index 0000000000000000000000000000000000000000..adcbe5a009ef8156945b48c4d29d171ebffc4bec
--- /dev/null
+++ b/src/main/java/org/yatopiamc/yatopia/server/util/HoldingConsumer.java
@@ -0,0 +1,17 @@
+package org.yatopiamc.yatopia.server.util;
+
+import java.util.function.Consumer;
+
+public class HoldingConsumer<T> implements Consumer<T> {
+
+    private T value;
+
+    @Override
+    public void accept(T t) {
+        this.value = t;
+    }
+
+    public T getValue() {
+        return value;
+    }
+}
