From 274fe387da499557a8c432a0f028ea76baa3599a Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 29 Mar 2019 02:02:53 -0400 Subject: [PATCH] Fix a concurrency issue with legacy structure data loading This code could get hit by many threads at once, causing multiple chunk loads to convert legacy data, leading to all sorts of fun. Additionally, go ahead and preload it async on world load. --- .../Async-Chunk-Loading-and-Generation.patch | 36 +++++++++++++++---- .../Entity-getEntitySpawnReason.patch | 4 +-- ...mit-lightning-strike-effect-distance.patch | 4 +-- .../Use-EntityTypes-for-living-entities.patch | 4 +-- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch b/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch index 312df2dbe3..725ac93b79 100644 --- a/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch +++ b/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch @@ -713,7 +713,7 @@ index 186cfda7e..781e06877 100644 } diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java -index d938eb374..51df075b4 100644 +index d938eb374..7734712af 100644 --- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java +++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java @@ -0,0 +0,0 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { @@ -725,6 +725,21 @@ index d938eb374..51df075b4 100644 if (cps.isLoaded(x, z)) { return true; } +@@ -0,0 +0,0 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { + } + } + ++ private final Object legacyStructureLock = new Object(); // Paper ++ public void getPersistentStructureLegacy(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection) { this.a(dimensionmanager, persistentcollection); } // Paper + public void a(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection) { + if (this.e == null) { ++ synchronized (legacyStructureLock){ if (this.e == null) { // Paper + this.e = PersistentStructureLegacy.a(dimensionmanager, persistentcollection); +- } ++ } } } // Paper + + } + @@ -0,0 +0,0 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { } }; @@ -947,13 +962,14 @@ index be555f82d..3e81ebdb8 100644 this.aJ = Sets.newHashSet(); this.aL = new double[] { 0.0D, 0.0D, 0.0D}; diff --git a/src/main/java/net/minecraft/server/IChunkLoader.java b/src/main/java/net/minecraft/server/IChunkLoader.java -index 4698ee99f..dfb45cc4e 100644 +index 4698ee99f..431f4ab18 100644 --- a/src/main/java/net/minecraft/server/IChunkLoader.java +++ b/src/main/java/net/minecraft/server/IChunkLoader.java @@ -0,0 +0,0 @@ import javax.annotation.Nullable; public interface IChunkLoader { ++ void getPersistentStructureLegacy(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection); // Paper + void loadEntities(NBTTagCompound nbttagcompound, Chunk chunk); // Paper - Async Chunks + Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer consumer) throws IOException; // Paper - Async Chunks @Nullable @@ -2056,7 +2072,7 @@ index 284e96710..8b08efe1f 100644 } diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index a7302b39c..739fbecac 100644 +index 4c971ddfb..1c66c833b 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +0,0 @@ import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; @@ -2306,9 +2322,17 @@ index 69d8a25bd..d0eaa9e9f 100644 } } diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 0ff3fe03d..9b5509dce 100644 +index 0ff3fe03d..e71a40580 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java +@@ -0,0 +0,0 @@ public class WorldServer extends World implements IAsyncTaskHandler { + this.P(); + this.Q(); + this.getWorldBorder().a(minecraftserver.au()); ++ MCUtil.scheduleAsyncTask(() -> this.getChunkProvider().chunkLoader.getPersistentStructureLegacy(dimensionmanager, worldMaps)); // Paper + } + + public WorldServer i_() { @@ -0,0 +0,0 @@ public class WorldServer extends World implements IAsyncTaskHandler { gen = new org.bukkit.craftbukkit.generator.NormalChunkGenerator(this, this.getSeed()); } @@ -2347,7 +2371,7 @@ index fac42f8e5..59b1628e5 100644 } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 95fe3a91b..b5a87cfaf 100644 +index 0e4455d66..eacecccfd 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -0,0 +0,0 @@ public class CraftWorld implements World { @@ -2385,7 +2409,7 @@ index 95fe3a91b..b5a87cfaf 100644 if (isChunkLoaded(chunkCoordX + x, chunkCoordZ + z)) { unloadChunk(chunkCoordX + x, chunkCoordZ + z); diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 054ebc82b..2e0b4de83 100644 +index 68e30185a..7905420ca 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -0,0 +0,0 @@ public class CraftEventFactory { diff --git a/Spigot-Server-Patches/Entity-getEntitySpawnReason.patch b/Spigot-Server-Patches/Entity-getEntitySpawnReason.patch index cc45b7a2ff..2a5a27e05a 100644 --- a/Spigot-Server-Patches/Entity-getEntitySpawnReason.patch +++ b/Spigot-Server-Patches/Entity-getEntitySpawnReason.patch @@ -10,7 +10,7 @@ persistenting Living Entity, SPAWNER for spawners, or DEFAULT since data was not stored. diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java -index 51df075b4..53ae5d509 100644 +index 7734712af..dce52ac0f 100644 --- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java +++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java @@ -0,0 +0,0 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver { @@ -98,7 +98,7 @@ index b1630137e..df416e3b5 100644 if (entity != null) { UUID uuid = nbttagcompound1.a("Attach"); diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 0624848cc..9faed9303 100644 +index 5b4bce464..2d436feab 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 IEntityAccess, GeneratorAccess, IIBlockAc diff --git a/Spigot-Server-Patches/Limit-lightning-strike-effect-distance.patch b/Spigot-Server-Patches/Limit-lightning-strike-effect-distance.patch index 3f45e0450a..6318b1e5b1 100644 --- a/Spigot-Server-Patches/Limit-lightning-strike-effect-distance.patch +++ b/Spigot-Server-Patches/Limit-lightning-strike-effect-distance.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Limit lightning strike effect distance diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0b54b7d78..d723868fc 100644 +index e04204055..30985cdfc 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 { @@ -69,7 +69,7 @@ index 7781babf5..50f620009 100644 --this.lifeTicks; diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 9b5509dce..409b50744 100644 +index e71a40580..53e7834cc 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -0,0 +0,0 @@ public class WorldServer extends World implements IAsyncTaskHandler { diff --git a/Spigot-Server-Patches/Use-EntityTypes-for-living-entities.patch b/Spigot-Server-Patches/Use-EntityTypes-for-living-entities.patch index 60856f2c3c..6bfc2730dd 100644 --- a/Spigot-Server-Patches/Use-EntityTypes-for-living-entities.patch +++ b/Spigot-Server-Patches/Use-EntityTypes-for-living-entities.patch @@ -639,7 +639,7 @@ index 11010d8e1..4eb746ebb 100644 entityvindicator.setPositionRotation(blockposition, 0.0F, 0.0F); entityvindicator.prepare(generatoraccess.getDamageScaler(new BlockPosition(entityvindicator)), (GroupDataEntity) null, (NBTTagCompound) null); diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 409b50744..a4fc1e5e2 100644 +index 53e7834cc..5c2421ac3 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -0,0 +0,0 @@ public class WorldServer extends World implements IAsyncTaskHandler { @@ -652,7 +652,7 @@ index 409b50744..a4fc1e5e2 100644 entityhorseskeleton.s(true); entityhorseskeleton.setAgeRaw(0); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index e33135ada..6ed7c9355 100644 +index 7c0a53053..40ee34675 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -0,0 +0,0 @@ public class CraftWorld implements World {