From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Fri, 24 May 2019 07:53:16 +0100
Subject: [PATCH] Fix some generation concurrency issues


diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index ee08cdcffc9237ee4154b7c756ba032b7723bd1f..74709dff3f87e929f1583be524d4e53ad3be6728 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -86,6 +86,23 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
     private int tileTickPosition;
     public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
     public java.util.ArrayDeque<BlockRedstoneTorch.RedstoneUpdateInfo> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
+    // Paper start - yes this is hacky as shit
+    RegionLimitedWorldAccess regionLimited;
+    World originalWorld;
+    public World regionLimited(RegionLimitedWorldAccess limitedWorldAccess) {
+        try {
+            World clone = (World) super.clone();
+            clone.regionLimited = limitedWorldAccess;
+            clone.originalWorld = this;
+            return clone;
+        } catch (CloneNotSupportedException e1) {
+        }
+        return null;
+    }
+    ChunkCoordIntPair[] strongholdCoords;
+    List<StructureStart> strongholdStuctures = Lists.newArrayList();
+    final java.lang.Object stuctureLock = new Object();
+    // Paper end
 
     public CraftWorld getWorld() {
         return this.world;
diff --git a/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java b/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java
index 22e14fe1e98c8439f8db74c9464137a497fdaf7c..e2af6d43b2eafeecad8fd070fc70195c7b0bb93f 100644
--- a/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java
+++ b/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java
@@ -23,18 +23,18 @@ public class WorldGenFeatureStateProviderWeighted extends WorldGenFeatureStatePr
         this(new WeightedList<>(dynamic.get("entries").orElseEmptyList(), IBlockData::a));
     }
 
-    public WorldGenFeatureStateProviderWeighted a(IBlockData iblockdata, int i) {
+    public synchronized WorldGenFeatureStateProviderWeighted a(IBlockData iblockdata, int i) { // Paper
         this.b.a(iblockdata, i);
         return this;
     }
 
     @Override
-    public IBlockData a(Random random, BlockPosition blockposition) {
+    public synchronized IBlockData a(Random random, BlockPosition blockposition) { // Paper
         return (IBlockData) this.b.b(random);
     }
 
     @Override
-    public <T> T a(DynamicOps<T> dynamicops) {
+    public synchronized <T> T a(DynamicOps<T> dynamicops) { // Paper
         Builder<T, T> builder = ImmutableMap.builder();
 
         builder.put(dynamicops.createString("type"), dynamicops.createString(IRegistry.t.getKey(this.a).toString())).put(dynamicops.createString("entries"), this.b.a(dynamicops, (iblockdata) -> {
diff --git a/src/main/java/net/minecraft/server/WorldGenStronghold.java b/src/main/java/net/minecraft/server/WorldGenStronghold.java
index fc4348b60242e4a9d8612c3b8ce01711c32f4b1c..44be7169ffd5961df28d21a319d2cc7569662baf 100644
--- a/src/main/java/net/minecraft/server/WorldGenStronghold.java
+++ b/src/main/java/net/minecraft/server/WorldGenStronghold.java
@@ -10,10 +10,12 @@ import javax.annotation.Nullable;
 
 public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyConfiguration> {
 
+    /* // Paper start - no shared state
     private boolean a;
     private ChunkCoordIntPair[] aq;
     private final List<StructureStart> ar = Lists.newArrayList();
     private long as;
+    */
 
     public WorldGenStronghold(Function<Dynamic<?>, ? extends WorldGenFeatureEmptyConfiguration> function) {
         super(function);
@@ -21,16 +23,22 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
 
     @Override
     public boolean a(BiomeManager biomemanager, ChunkGenerator<?> chunkgenerator, Random random, int i, int j, BiomeBase biomebase) {
+        // Paper start
+        /*
         if (this.as != chunkgenerator.getSeed()) {
             this.d();
         }
+        */
+        final World world = chunkgenerator.getWorld();
 
-        if (!this.a) {
+        synchronized (world.stuctureLock) {
+        if ( world.strongholdCoords == null) {
             this.a(chunkgenerator);
-            this.a = true;
-        }
+          // this.a = true;
+        }}
+        // Paper end
 
-        ChunkCoordIntPair[] achunkcoordintpair = this.aq;
+        ChunkCoordIntPair[] achunkcoordintpair = world.strongholdCoords; // Paper
         int k = achunkcoordintpair.length;
 
         for (int l = 0; l < k; ++l) {
@@ -45,9 +53,11 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
     }
 
     private void d() {
+        /* // Paper
         this.a = false;
         this.aq = null;
         this.ar.clear();
+        */ // Paper
     }
 
     @Override
@@ -65,25 +75,32 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
         return 8;
     }
 
+
     @Nullable
     @Override
     public synchronized BlockPosition getNearestGeneratedFeature(World world, ChunkGenerator<? extends GeneratorSettingsDefault> chunkgenerator, BlockPosition blockposition, int i, boolean flag) {
         if (!chunkgenerator.getWorldChunkManager().a(this)) {
             return null;
         } else {
+            // Paper start - no shared state
+            /*
             if (this.as != world.getSeed()) {
                 this.d();
             }
+             */
 
-            if (!this.a) {
-                this.a(chunkgenerator);
-                this.a = true;
+            synchronized (world.stuctureLock) {
+                if ( world.strongholdCoords == null) {
+                    this.a(chunkgenerator);
+                    //this.a = true;
+                }
             }
+            // Paper end
 
             BlockPosition blockposition1 = null;
             BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
             double d0 = Double.MAX_VALUE;
-            ChunkCoordIntPair[] achunkcoordintpair = this.aq;
+            ChunkCoordIntPair[] achunkcoordintpair = world.strongholdCoords; // Paper
             int j = achunkcoordintpair.length;
 
             for (int k = 0; k < j; ++k) {
@@ -106,7 +123,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
     }
 
     private void a(ChunkGenerator<?> chunkgenerator) {
-        this.as = chunkgenerator.getSeed();
+        //this.as = chunkgenerator.getSeed(); // Paper
         List<BiomeBase> list = Lists.newArrayList();
         Iterator iterator = IRegistry.BIOME.iterator();
 
@@ -122,15 +139,15 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
         int j = chunkgenerator.getSettings().f();
         int k = chunkgenerator.getSettings().g();
 
-        this.aq = new ChunkCoordIntPair[j];
+        ChunkCoordIntPair[] strongholdCoords = chunkgenerator.getWorld().strongholdCoords = new ChunkCoordIntPair[j]; // Paper
         int l = 0;
-        Iterator iterator1 = this.ar.iterator();
+        Iterator iterator1 = chunkgenerator.getWorld().strongholdStuctures.iterator(); // Paper
 
         while (iterator1.hasNext()) {
             StructureStart structurestart = (StructureStart) iterator1.next();
 
-            if (l < this.aq.length) {
-                this.aq[l++] = new ChunkCoordIntPair(structurestart.f(), structurestart.g());
+            if (l < strongholdCoords.length) { // Paper
+                strongholdCoords[l++] = new ChunkCoordIntPair(structurestart.f(), structurestart.g()); // Paper
             }
         }
 
@@ -140,11 +157,11 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
         double d0 = random.nextDouble() * 3.141592653589793D * 2.0D;
         int i1 = l;
 
-        if (l < this.aq.length) {
+        if (l < strongholdCoords.length) { // Paper
             int j1 = 0;
             int k1 = 0;
 
-            for (int l1 = 0; l1 < this.aq.length; ++l1) {
+            for (int l1 = 0; l1 < strongholdCoords.length; ++l1) { // Paper
                 double d1 = (double) (4 * i + i * k1 * 6) + (random.nextDouble() - 0.5D) * (double) i * 2.5D;
                 int i2 = (int) Math.round(Math.cos(d0) * d1);
                 int j2 = (int) Math.round(Math.sin(d0) * d1);
@@ -156,7 +173,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
                 }
 
                 if (l1 >= i1) {
-                    this.aq[l1] = new ChunkCoordIntPair(i2, j2);
+                    strongholdCoords[l1] = new ChunkCoordIntPair(i2, j2); // Paper
                 }
 
                 d0 += 6.283185307179586D / (double) k;
@@ -165,7 +182,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
                     ++k1;
                     j1 = 0;
                     k += 2 * k / (k1 + 1);
-                    k = Math.min(k, this.aq.length - l1);
+                    k = Math.min(k, strongholdCoords.length - l1); // Paper
                     d0 += random.nextDouble() * 3.141592653589793D * 2.0D;
                 }
             }
@@ -207,7 +224,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
                 this.a(chunkgenerator.getSeaLevel(), this.d, 10);
             } while (this.b.isEmpty() || worldgenstrongholdpieces_worldgenstrongholdstart.b == null);
 
-            ((WorldGenStronghold) this.l()).ar.add(this);
+            chunkgenerator.getWorld().strongholdStuctures.add(this); // Paper - this worries me, this is never cleared, even in vanilla (world seed never changes "world", and that appears to be the only relevant world)
         }
     }
 }