From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Phoenix616 <mail@moep.tv>
Date: Mon, 13 Jan 2020 15:40:32 +0100
Subject: [PATCH] Seed based feature search

This fixes the issue where the server will load surrounding chunks up to
a radius of 100 chunks in order to search for features e.g. when running
the /locate command or for treasure maps (issue #2312).
This is done by using the same seed checking functionality that is used
by the server when generating these features before actually attempting
to load the chunk to check if a feature is available in it.

The only downside of this is that it breaks once the seed or generator
changes but this should usually not happen. A config option to disable
this improvement is added though in case that should ever be necessary.

diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -0,0 +0,0 @@ public class PaperWorldConfig {
         }
     }
 
+    public boolean seedBasedFeatureSearch = true;
+    private void seedBasedFeatureSearch() {
+        seedBasedFeatureSearch = getBoolean("seed-based-feature-search", seedBasedFeatureSearch);
+        log("Feature search is based on seed: " + seedBasedFeatureSearch);
+    }
+
     public int maxCollisionsPerEntity;
     private void maxEntityCollision() {
         maxCollisionsPerEntity = getInt( "max-entity-collisions", this.spigotConfig.getInt("max-entity-collisions", 8) );
diff --git a/src/main/java/net/minecraft/server/BiomeManager.java b/src/main/java/net/minecraft/server/BiomeManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/BiomeManager.java
+++ b/src/main/java/net/minecraft/server/BiomeManager.java
@@ -0,0 +0,0 @@ public class BiomeManager {
         this.c = genlayerzoomer;
     }
 
+    public BiomeManager withProvider(WorldChunkManager worldchunkmanager) { return a(worldchunkmanager); } // Paper - OBFHELPER
     public BiomeManager a(WorldChunkManager worldchunkmanager) {
         return new BiomeManager(worldchunkmanager, this.b, this.c);
     }
 
+    public BiomeBase getBiome(BlockPosition blockposition) { return a(blockposition); } // Paper - OBFHELPER
     public BiomeBase a(BlockPosition blockposition) {
         return this.c.a(this.b, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.a);
     }
diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
+++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
@@ -0,0 +0,0 @@ public class ChunkCoordIntPair {
         }
     }
 
+    public int getBlockX() { return d(); } // Paper - OBFHELPER
     public int d() {
         return this.x << 4;
     }
 
+    public int getBlockZ() { return e(); } // Paper - OBFHELPER
     public int e() {
         return this.z << 4;
     }
diff --git a/src/main/java/net/minecraft/server/StructureGenerator.java b/src/main/java/net/minecraft/server/StructureGenerator.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/StructureGenerator.java
+++ b/src/main/java/net/minecraft/server/StructureGenerator.java
@@ -0,0 +0,0 @@ public abstract class StructureGenerator<C extends WorldGenFeatureConfiguration>
                             if (flag1 || flag2) {
                                 ChunkCoordIntPair chunkcoordintpair = this.a(chunkgenerator, seededrandom, j, k, i1, j1);
                                 if (!world.getWorldBorder().isChunkInBounds(chunkcoordintpair.x, chunkcoordintpair.z)) { continue; } // Paper
+                                // Paper start - seed based feature search
+                                if (world.paperConfig.seedBasedFeatureSearch) {
+                                    BiomeManager biomeManager = world.getBiomeManager().withProvider(chunkgenerator.getWorldChunkManager());
+                                    BiomeBase biomeBase = biomeManager.getBiome(new BlockPosition(chunkcoordintpair.getBlockX() + 9, 0, chunkcoordintpair.getBlockZ() + 9));
+                                    if (!shouldGenerate(biomeManager, chunkgenerator, seededrandom, chunkcoordintpair.x, chunkcoordintpair.z, biomeBase)) {
+                                        continue;
+                                    }
+                                }
+                                // Paper end
                                 StructureStart structurestart = world.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z, ChunkStatus.STRUCTURE_STARTS).a(this.b());
 
                                 if (structurestart != null && structurestart.e()) {
@@ -0,0 +0,0 @@ public abstract class StructureGenerator<C extends WorldGenFeatureConfiguration>
         return new ChunkCoordIntPair(i + k, j + l);
     }
 
+    public boolean shouldGenerate(BiomeManager biomemanager, ChunkGenerator<?> chunkgenerator, Random random, int chunkX, int chunkZ, BiomeBase biomebase) { return a(biomemanager, chunkgenerator, random, chunkX, chunkZ, biomebase); } // Paper - OBFHELPER
     public abstract boolean a(BiomeManager biomemanager, ChunkGenerator<?> chunkgenerator, Random random, int i, int j, BiomeBase biomebase);
 
     public abstract StructureGenerator.a a();
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
         return this.methodProfiler;
     }
 
-    @Override
-    public BiomeManager d() {
+    public BiomeManager getBiomeManager() { return d(); } // Paper - OBFHELPER
+    @Override public BiomeManager d() {
         return this.biomeManager;
     }
 }