This commit is contained in:
Simon Gardling 2021-04-06 14:22:55 -04:00
parent 2c205e034e
commit be67395994
9 changed files with 1405 additions and 0 deletions

View File

@ -157,6 +157,7 @@ # Patches
| server | Custom Locale Support | Zoe | |
| server | Custom table implementation for blockstate state lookups | Spottedleaf | |
| server | Customizable wither health and healing | jmp | |
| server | Decompile fixes for WorldChunkManagerMultiNoise | ishland | |
| api | Default permissions | William Blake Galbreath | |
| server | Delay chunk unloads | Spottedleaf | |
| server | Despawn rate config options per projectile type | jmp | |
@ -217,6 +218,7 @@ # Patches
| server | Fix the dead lagging the server | William Blake Galbreath | |
| server | Fix vanilla command permission handler | William Blake Galbreath | |
| server | Flying squids! Oh my! | William Blake Galbreath | |
| server | Force world save | ishland | |
| server | Full netherite armor grants fire resistance | BillyGalbreath | |
| api | Full netherite armor grants fire resistance | BillyGalbreath | |
| server | Giants AI settings | William Blake Galbreath | |
@ -278,6 +280,8 @@ # Patches
| server | Movement options for armor stands | Mariell Hoversholm | |
| server | Multi-Threaded Server Ticking Vanilla | Spottedleaf | |
| server | Multi-Threaded ticking CraftBukkit | Spottedleaf | |
| server | Multi-threaded RegionFile IO | ishland | |
| server | Multi-threaded World Upgrade | ishland | |
| server | Multithreaded entity tracking | Paul Sauve | |
| server | Name craft scheduler threads according to the plugin using | Spottedleaf | |
| server | New nbt cache | Hugo Planque | ishland |
@ -395,6 +399,7 @@ # Patches
| api | Suspected plugins report | ishland | |
| server | Swap priority of checks in chunk ticking | Paul Sauve | |
| server | Swaps the predicate order of collision | ㄗㄠˋ ㄑㄧˊ | |
| server | Threaded WorldGen | ishland | |
| server | Tick fluids config | BillyGalbreath | |
| server | Time scoreboard search | Spottedleaf | |
| server | Timings stuff | William Blake Galbreath | |
@ -422,11 +427,14 @@ # Patches
| server | Zombie horse naturally spawn | William Blake Galbreath | |
| server | add config for logging login location | Simon Gardling | |
| server | dont load chunks for physics | Aikar | |
| server | fixup! Threaded WorldGen | ishland | |
| server | fixup! Threaded WorldGen | ishland | |
| server | lithium DataTrackerMixin | JellySquid | tr7zw |
| server | lithium HashedList | JellySquid | |
| server | lithium MixinBox | JellySquid | |
| server | lithium MixinDirection | JellySquid | |
| server | lithium MixinGoalSelector | JellySquid | |
| server | lithium MultiNoiseBiomeSourceMixin | SuperCoder7979 | |
| server | lithium NoiseChunkGeneratorMixin | JellySquid | |
| server | lithium PerlinNoiseSamplerMixin | JellySquid | Bud Gidiere |
| server | lithium VoronoiBiomeAccessTypeMixin | JellySquid | |

View File

@ -0,0 +1,477 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Sat, 9 Jan 2021 19:21:16 +0800
Subject: [PATCH] Threaded WorldGen
A massive improvement to world generation.
This patch actually schedules chunk status upgrade later rather than doing it right away.
diff --git a/pom.xml b/pom.xml
index 734885f97eabffab6f76051b41f94d0dd16b4263..b8f376c015ae373252fd0e4f54cc921bae67b92a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -196,6 +196,12 @@
<artifactId>commons-rng-core</artifactId>
<version>1.3</version>
</dependency>
+ <!-- https://mvnrepository.com/artifact/com.ibm.async/asyncutil -->
+ <dependency>
+ <groupId>com.ibm.async</groupId>
+ <artifactId>asyncutil</artifactId>
+ <version>0.1.0</version>
+ </dependency>
</dependencies>
<repositories>
diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
index dc641664abe8ff6b36c69c7d21a3200d160ff1b6..c8f2ea95b4ea6e5629ef0b852dd08d45cb127b93 100644
--- a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
+++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
@@ -64,6 +64,20 @@ public final class ChunkTaskManager {
public String toString() {
return "[( " + this.chunkX + "," + this.chunkZ + ") in '" + this.world.getWorld().getName() + "']";
}
+ // Yatopia start
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ChunkInfo chunkInfo = (ChunkInfo) o;
+ return chunkX == chunkInfo.chunkX && chunkZ == chunkInfo.chunkZ && java.util.Objects.equals(world, chunkInfo.world);
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(chunkX, chunkZ, world);
+ }
+ // Yatopia end
}
public static void pushChunkWait(final WorldServer world, final int chunkX, final int chunkZ) {
@@ -77,7 +91,13 @@ public final class ChunkTaskManager {
WAITING_CHUNKS.pop();
}
}
-
+ // Yatopia start
+ public static boolean hasChunkWait(final WorldServer world, final int chunkX, final int chunkZ) {
+ synchronized (WAITING_CHUNKS) {
+ return WAITING_CHUNKS.contains(new ChunkInfo(chunkX, chunkZ, world));
+ }
+ }
+ // Yatopia end
private static ChunkInfo[] getChunkInfos() {
ChunkInfo[] chunks;
synchronized (WAITING_CHUNKS) {
diff --git a/src/main/java/net/minecraft/SystemUtils.java b/src/main/java/net/minecraft/SystemUtils.java
index ce440ae5cc843fc6101dd11fd45d9089795411e4..06de830c859f3fa04b8542a238f24aa872585e92 100644
--- a/src/main/java/net/minecraft/SystemUtils.java
+++ b/src/main/java/net/minecraft/SystemUtils.java
@@ -122,6 +122,7 @@ public class SystemUtils {
return SystemUtils.d;
}
+ public static Executor getMainThreadExecutor() { return f(); } // Yatopia - OBFHELPER
public static Executor f() {
return SystemUtils.e;
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 97bb17236a00dd6ecd4d5926826815bb928bfe9e..b21c09f5b1cde7f7a710fe8960face8cb21040c4 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -953,6 +953,8 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
// Spigot end
// Paper start - move final shutdown items here
LOGGER.info("Flushing Chunk IO");
+ net.minecraft.server.level.PlayerChunkMap.shutdownScheduler(); // Yatopia
+ net.minecraft.world.level.chunk.ChunkStatus.shutdownExecutors(); // Yatopia
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper
LOGGER.info("Closing Thread Pool");
SystemUtils.shutdownServerThreadPool(); // Paper
diff --git a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
index 424cd048f905cd0ed3f7a4545a26ffde8da1f91f..194321b7183d3aaa8031608a979dde71006e2fab 100644
--- a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
@@ -11,6 +11,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@@ -53,6 +54,10 @@ import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
// Tuinity end
+import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
+import it.unimi.dsi.fastutil.objects.ObjectSet;
+import it.unimi.dsi.fastutil.objects.ObjectSets;
+
public class ChunkProviderServer extends IChunkProvider {
private static final List<ChunkStatus> b = ChunkStatus.a(); public static final List<ChunkStatus> getPossibleChunkStatuses() { return ChunkProviderServer.b; } // Paper - OBFHELPER
@@ -834,10 +839,27 @@ public class ChunkProviderServer extends IChunkProvider {
return this.world;
}
- public boolean runTasks() {
- return this.serverThreadQueue.executeNext();
+ // Yatopia start - reduce scheduling overhead
+ final ConcurrentLinkedQueue<Runnable> poiQueue = new ConcurrentLinkedQueue<>();
+ private boolean runPoiQueueNext() { // TODO flush poi queue?
+ try {
+ final Runnable runnable = poiQueue.poll();
+ if (runnable != null)
+ runnable.run();
+ return runnable != null;
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return false;
}
+ public boolean runTasks() {
+ boolean b = this.serverThreadQueue.executeNext();
+ if(runPoiQueueNext())
+ b = true;
+ return b;
+ } // Yatopia end
+
public boolean tickDistanceManager() { // Paper - private -> public
if (chunkMapDistance.delayDistanceManagerTick) return false; // Paper
if (this.playerChunkMap.unloadingPlayerChunk) { MinecraftServer.LOGGER.fatal("Cannot tick distance manager while unloading playerchunks", new Throwable()); throw new IllegalStateException("Cannot tick distance manager while unloading playerchunks"); } // Tuinity
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
index 58d2f1a10186e889bdd2249724a7f21f3a0a6a6e..b9d38413da1adbffd21df301f03cf181d4cd5cdc 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
@@ -113,6 +113,18 @@ import org.spigotmc.AsyncCatcher;
public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
+ // Yatopia start
+ static final java.util.concurrent.ExecutorService worldGenScheduler = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("Yatopia Async Chunks Scheduler").setDaemon(true).setPriority(Thread.NORM_PRIORITY - 1).build());
+ public static void shutdownScheduler() {
+ worldGenScheduler.shutdown();
+ while (!worldGenScheduler.isTerminated()) {
+ try {
+ worldGenScheduler.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+ // Yatopia end
private static final Logger LOGGER = LogManager.getLogger();
public static final int GOLDEN_TICKET = 33 + ChunkStatus.b();
// Paper start - faster copying
@@ -1407,7 +1419,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return;
}
// Paper end
- this.mailboxWorldGen.a(ChunkTaskQueueSorter.a(playerchunk, runnable));
+ worldGenScheduler.execute(runnable); // Yatopia
}).thenComposeAsync((either) -> { // Tuinity start - force competion on the main thread
return CompletableFuture.completedFuture(either);
}, this.mainInvokingExecutor);
diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
index 8ea7ad63c0f091102f793b3c1f90b4121c4d74e0..f1ae11648bab299c3b17ddcee75e7b7d7054d157 100644
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
@@ -2773,28 +2773,26 @@ public class WorldServer extends World implements GeneratorAccessSeed {
// Paper start
BlockPosition blockposition1 = blockposition.immutableCopy();
- this.getMinecraftServer().execute(() -> {
+ // Yatopia start - reduce scheduling overhead
+ chunkProvider.poiQueue.add(() -> {
if (!optional.isPresent() && this.getPoiStorage().test(blockposition1, com.google.common.base.Predicates.alwaysTrue())) {
this.getPoiStorage().remove(blockposition1);
}
- });
if (!Objects.equals(optional, optional1)) {
//BlockPosition blockposition1 = blockposition.immutableCopy();
// Paper end
optional.ifPresent((villageplacetype) -> {
- this.getMinecraftServer().execute(() -> {
this.y().a(blockposition1);
PacketDebug.b(this, blockposition1);
- });
});
optional1.ifPresent((villageplacetype) -> {
- this.getMinecraftServer().execute(() -> {
this.y().a(blockposition1, villageplacetype);
PacketDebug.a(this, blockposition1);
- });
});
}
+ });
+ // Yatopia end
}
public final VillagePlace getPoiStorage() { return this.y(); } // Paper - OBFHELPER
diff --git a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerOverworld.java b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerOverworld.java
index 28b2c69ef1ad7938b09dd39e34008956f4922483..0505fd4d6882bfaa63805464a056f66ad060930e 100644
--- a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerOverworld.java
+++ b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerOverworld.java
@@ -24,7 +24,7 @@ public class WorldChunkManagerOverworld extends WorldChunkManager {
return worldchunkmanageroverworld.k;
})).apply(instance, instance.stable(WorldChunkManagerOverworld::new));
});
- private final GenLayer f;
+ private final ThreadLocal<GenLayer> f; // Yatopia
private static final List<ResourceKey<BiomeBase>> g = ImmutableList.of(Biomes.OCEAN, Biomes.PLAINS, Biomes.DESERT, Biomes.MOUNTAINS, Biomes.FOREST, Biomes.TAIGA, Biomes.SWAMP, Biomes.RIVER, Biomes.FROZEN_OCEAN, Biomes.FROZEN_RIVER, Biomes.SNOWY_TUNDRA, Biomes.SNOWY_MOUNTAINS, new ResourceKey[]{Biomes.MUSHROOM_FIELDS, Biomes.MUSHROOM_FIELD_SHORE, Biomes.BEACH, Biomes.DESERT_HILLS, Biomes.WOODED_HILLS, Biomes.TAIGA_HILLS, Biomes.MOUNTAIN_EDGE, Biomes.JUNGLE, Biomes.JUNGLE_HILLS, Biomes.JUNGLE_EDGE, Biomes.DEEP_OCEAN, Biomes.STONE_SHORE, Biomes.SNOWY_BEACH, Biomes.BIRCH_FOREST, Biomes.BIRCH_FOREST_HILLS, Biomes.DARK_FOREST, Biomes.SNOWY_TAIGA, Biomes.SNOWY_TAIGA_HILLS, Biomes.GIANT_TREE_TAIGA, Biomes.GIANT_TREE_TAIGA_HILLS, Biomes.WOODED_MOUNTAINS, Biomes.SAVANNA, Biomes.SAVANNA_PLATEAU, Biomes.BADLANDS, Biomes.WOODED_BADLANDS_PLATEAU, Biomes.BADLANDS_PLATEAU, Biomes.WARM_OCEAN, Biomes.LUKEWARM_OCEAN, Biomes.COLD_OCEAN, Biomes.DEEP_WARM_OCEAN, Biomes.DEEP_LUKEWARM_OCEAN, Biomes.DEEP_COLD_OCEAN, Biomes.DEEP_FROZEN_OCEAN, Biomes.SUNFLOWER_PLAINS, Biomes.DESERT_LAKES, Biomes.GRAVELLY_MOUNTAINS, Biomes.FLOWER_FOREST, Biomes.TAIGA_MOUNTAINS, Biomes.SWAMP_HILLS, Biomes.ICE_SPIKES, Biomes.MODIFIED_JUNGLE, Biomes.MODIFIED_JUNGLE_EDGE, Biomes.TALL_BIRCH_FOREST, Biomes.TALL_BIRCH_HILLS, Biomes.DARK_FOREST_HILLS, Biomes.SNOWY_TAIGA_MOUNTAINS, Biomes.GIANT_SPRUCE_TAIGA, Biomes.GIANT_SPRUCE_TAIGA_HILLS, Biomes.MODIFIED_GRAVELLY_MOUNTAINS, Biomes.SHATTERED_SAVANNA, Biomes.SHATTERED_SAVANNA_PLATEAU, Biomes.ERODED_BADLANDS, Biomes.MODIFIED_WOODED_BADLANDS_PLATEAU, Biomes.MODIFIED_BADLANDS_PLATEAU});
private final long h;
private final boolean i;
@@ -41,7 +41,7 @@ public class WorldChunkManagerOverworld extends WorldChunkManager {
this.i = flag;
this.j = flag1;
this.k = iregistry;
- this.f = GenLayers.a(i, flag, flag1 ? 6 : 4, 4);
+ this.f = GenLayers.genLayerThreadLocal(i, flag, flag1 ? 6 : 4, 4); // Yatopia
}
@Override
@@ -51,6 +51,6 @@ public class WorldChunkManagerOverworld extends WorldChunkManager {
@Override
public BiomeBase getBiome(int i, int j, int k) {
- return this.f.a(this.k, i, k);
+ return this.f.get().a(this.k, i, k); // Yatopia
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
index ff98335155c86803b98d8c67f0b40b8d65214890..6f6a52bb2e445795f96ffbafaeed63c3d1f15b7e 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -56,6 +56,7 @@ public abstract class ChunkGenerator {
private final StructureSettings structureSettings;
private final long e;
private final List<ChunkCoordIntPair> f;
+ public final com.ibm.asyncutil.locks.AsyncLock featureGenLock = com.ibm.asyncutil.locks.AsyncLock.createFair(); // Yatopia - threaded WorldGen
public ChunkGenerator(WorldChunkManager worldchunkmanager, StructureSettings structuresettings) {
this(worldchunkmanager, worldchunkmanager, structuresettings, 0L);
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
index f4a4d63a2e21b08580023cf0dcd15a68d192cf14..a01d6dfe147383242e514d2807558bf94ff8865a 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
@@ -22,9 +22,51 @@ import net.minecraft.world.level.levelgen.HeightMap;
import net.minecraft.world.level.levelgen.WorldGenStage;
import net.minecraft.world.level.levelgen.structure.templatesystem.DefinedStructureManager;
import net.minecraft.world.level.lighting.LightEngine;
+// Yatopia start
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+// Yatopia end
public class ChunkStatus {
+ // Yatopia start - threaded WorldGen
+ private static final ThreadPoolExecutor featureGenExecutor = new ThreadPoolExecutor(
+ org.yatopiamc.yatopia.server.YatopiaConfig.featureGenExecutorSize == -1 ? Math.min(Runtime.getRuntime().availableProcessors(), 3) : org.yatopiamc.yatopia.server.YatopiaConfig.featureGenExecutorSize,
+ org.yatopiamc.yatopia.server.YatopiaConfig.featureGenExecutorSize == -1 ? Math.min(Runtime.getRuntime().availableProcessors(), 3) : org.yatopiamc.yatopia.server.YatopiaConfig.featureGenExecutorSize,
+ 0,
+ TimeUnit.SECONDS,
+ new PriorityBlockingQueue<>(),
+ new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Yatopia Async Chunks FeatureGen Worker #%d").build()
+ );
+ private static final ThreadPoolExecutor worldGenExecutor = new ThreadPoolExecutor(
+ org.yatopiamc.yatopia.server.YatopiaConfig.worldGenExecutorSize == -1 ? Math.min(Runtime.getRuntime().availableProcessors(), 8) : org.yatopiamc.yatopia.server.YatopiaConfig.worldGenExecutorSize,
+ org.yatopiamc.yatopia.server.YatopiaConfig.worldGenExecutorSize == -1 ? Math.min(Runtime.getRuntime().availableProcessors(), 8) : org.yatopiamc.yatopia.server.YatopiaConfig.worldGenExecutorSize,
+ 0,
+ TimeUnit.SECONDS,
+ new PriorityBlockingQueue<>(),
+ new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Yatopia Async Chunks WorldGen Worker #%d").build()
+ );
+
+ public static void shutdownExecutors() {
+ featureGenExecutor.shutdown();
+ worldGenExecutor.shutdown();
+ while (!featureGenExecutor.isTerminated()) {
+ try {
+ featureGenExecutor.awaitTermination(30, TimeUnit.SECONDS);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ while (!worldGenExecutor.isTerminated()) {
+ try {
+ worldGenExecutor.awaitTermination(30, TimeUnit.SECONDS);
+ } catch (InterruptedException ignored) {
+ }
+ }
+
+ }
+ // Yatopia end
+
private static final EnumSet<HeightMap.Type> n = EnumSet.of(HeightMap.Type.OCEAN_FLOOR_WG, HeightMap.Type.WORLD_SURFACE_WG);
private static final EnumSet<HeightMap.Type> o = EnumSet.of(HeightMap.Type.OCEAN_FLOOR, HeightMap.Type.WORLD_SURFACE, HeightMap.Type.MOTION_BLOCKING, HeightMap.Type.MOTION_BLOCKING_NO_LEAVES);
private static final ChunkStatus.c p = (chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess) -> {
@@ -37,17 +79,20 @@ public class ChunkStatus {
public static final ChunkStatus EMPTY = a("empty", (ChunkStatus) null, -1, ChunkStatus.n, ChunkStatus.Type.PROTOCHUNK, (worldserver, chunkgenerator, list, ichunkaccess) -> {
});
public static final ChunkStatus STRUCTURE_STARTS = a("structure_starts", ChunkStatus.EMPTY, 0, ChunkStatus.n, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess) -> {
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> result = CompletableFuture.completedFuture(Either.left(ichunkaccess));
if (!ichunkaccess.getChunkStatus().b(chunkstatus)) {
if (worldserver.worldDataServer.getGeneratorSettings().shouldGenerateMapFeatures()) { // CraftBukkit
- chunkgenerator.createStructures(worldserver.r(), worldserver.getStructureManager(), ichunkaccess, definedstructuremanager, worldserver.getSeed());
+ result = CompletableFuture.supplyAsync(() -> {
+ chunkgenerator.createStructures(worldserver.r(), worldserver.getStructureManager(), ichunkaccess, definedstructuremanager, worldserver.getSeed());
+ return Either.left(ichunkaccess);
+ }, command -> worldGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : 0, command)));
}
-
if (ichunkaccess instanceof ProtoChunk) {
- ((ProtoChunk) ichunkaccess).a(chunkstatus);
+ result.thenRun(() -> ((ProtoChunk) ichunkaccess).a(chunkstatus));
}
}
- return CompletableFuture.completedFuture(Either.left(ichunkaccess));
+ return result;
});
public static final ChunkStatus STRUCTURE_REFERENCES = a("structure_references", ChunkStatus.STRUCTURE_STARTS, 8, ChunkStatus.n, ChunkStatus.Type.PROTOCHUNK, (worldserver, chunkgenerator, list, ichunkaccess) -> {
RegionLimitedWorldAccess regionlimitedworldaccess = new RegionLimitedWorldAccess(worldserver, list);
@@ -72,6 +117,9 @@ public class ChunkStatus {
chunkgenerator.doCarving(worldserver.getSeed(), worldserver.d(), ichunkaccess, WorldGenStage.Features.LIQUID);
});
public static final ChunkStatus FEATURES = a("features", ChunkStatus.LIQUID_CARVERS, 8, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess) -> {
+ // Yatopia start - threaded WorldGen
+ return chunkgenerator.featureGenLock.acquireLock().toCompletableFuture().thenComposeAsync(token -> {
+ try {
ProtoChunk protochunk = (ProtoChunk) ichunkaccess;
protochunk.a((LightEngine) lightenginethreaded);
@@ -82,8 +130,13 @@ public class ChunkStatus {
chunkgenerator.addDecorations(regionlimitedworldaccess, worldserver.getStructureManager().a(regionlimitedworldaccess));
protochunk.a(chunkstatus);
}
+ } finally {
+ token.releaseLock();
+ }
return CompletableFuture.completedFuture(Either.left(ichunkaccess));
+ }, command -> featureGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : 0, command)));
+ // Yatopia end
});
public static final ChunkStatus LIGHT = a("light", ChunkStatus.FEATURES, 1, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess) -> {
return a(chunkstatus, lightenginethreaded, ichunkaccess);
@@ -256,14 +309,18 @@ public class ChunkStatus {
@Override
default CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list, IChunkAccess ichunkaccess) {
+ // Yatopia start - threaded worldGen
+ return CompletableFuture.supplyAsync(() -> {
if (!ichunkaccess.getChunkStatus().b(chunkstatus)) {
this.doWork(worldserver, chunkgenerator, list, ichunkaccess);
if (ichunkaccess instanceof ProtoChunk) {
((ProtoChunk) ichunkaccess).a(chunkstatus);
}
}
+ return Either.left(ichunkaccess);
+ }, command -> worldGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : 0, command)));
- return CompletableFuture.completedFuture(Either.left(ichunkaccess));
+ // Yatopia end
}
void doWork(WorldServer worldserver, ChunkGenerator chunkgenerator, List<IChunkAccess> list, IChunkAccess ichunkaccess);
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
index 9b82ff37faaafc3a799413f6949fb88a993aa9a0..ce8fce0794c92bc4b28c410f42807a17ee3852a3 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
@@ -837,7 +837,7 @@ public class DefinedStructure {
private final Map<Block, List<DefinedStructure.BlockInfo>> b;
private a(List<DefinedStructure.BlockInfo> list) {
- this.b = Maps.newHashMap();
+ this.b = new java.util.concurrent.ConcurrentHashMap<>(); // Yatopia
this.a = list;
}
diff --git a/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java b/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java
index 5bbd71f2cf6db34dd01e8e209809a4661505aaf1..7000c3a26d0eaf94e33b68b7a56d5d5413e36a6f 100644
--- a/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java
+++ b/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java
@@ -13,7 +13,7 @@ import net.minecraft.world.level.newbiome.layer.traits.AreaTransformer2;
public class GenLayers {
- private static final Int2IntMap a = (Int2IntMap) SystemUtils.a((Object) (new Int2IntOpenHashMap()), (int2intopenhashmap) -> {
+ private static final Int2IntMap a = (Int2IntMap) SystemUtils.a((new Int2IntOpenHashMap()), (int2intopenhashmap) -> { // Yatopia - decompile fix
a(int2intopenhashmap, GenLayers.Type.BEACH, 16);
a(int2intopenhashmap, GenLayers.Type.BEACH, 26);
a(int2intopenhashmap, GenLayers.Type.DESERT, 2);
@@ -161,6 +161,11 @@ public class GenLayers {
return new GenLayer(areafactory);
}
+ // Yatopia start
+ public static ThreadLocal<GenLayer> genLayerThreadLocal(long i, boolean flag, int j, int k) {
+ return ThreadLocal.withInitial(() -> new GenLayer(a(flag, j, k, (l) -> new WorldGenContextArea(25, i, l))));
+ }
+ // Yatopia end
public static boolean a(int i, int j) {
return i == j ? true : GenLayers.a.get(i) == GenLayers.a.get(j);
}
diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
index 15e2fa125bc293b954cceb5b1fbcec7fade3e4db..7d8e04a5792283a27c044758fb4bc12567b289cb 100644
--- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
+++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
@@ -1,5 +1,6 @@
package org.yatopiamc.yatopia.server;
+import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import java.io.File;
import java.io.IOException;
@@ -276,4 +277,13 @@ public class YatopiaConfig {
fixProtocolLib = getBoolean("settings.fix-protocollib", fixProtocolLib);
}
+ public static int featureGenExecutorSize = -1;
+ public static int worldGenExecutorSize = -1;
+ private static void multiThreadedWorldGen() {
+ featureGenExecutorSize = getInt("settings.threads.featuregen", -1);
+ Preconditions.checkArgument(featureGenExecutorSize == -1 || featureGenExecutorSize > 0, "Invalid settings.threads.featuregen in yatopia.yml");
+ worldGenExecutorSize = getInt("settings.threads.worldgen", -1);
+ Preconditions.checkArgument(worldGenExecutorSize == -1 || worldGenExecutorSize > 0, "Invalid settings.threads.worldgen in yatopia.yml");
+ }
+
}
diff --git a/src/main/java/org/yatopiamc/yatopia/server/executors/PrioritizedRunnable.java b/src/main/java/org/yatopiamc/yatopia/server/executors/PrioritizedRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..51dff59bbd9057c4cb249349cd8bb22a8267c237
--- /dev/null
+++ b/src/main/java/org/yatopiamc/yatopia/server/executors/PrioritizedRunnable.java
@@ -0,0 +1,29 @@
+package org.yatopiamc.yatopia.server.executors;
+
+import javax.annotation.Nonnull;
+import java.util.function.Supplier;
+
+public class PrioritizedRunnable implements Runnable, Comparable<PrioritizedRunnable> {
+
+ private final Supplier<Integer> prioritySupplier;
+ private final Runnable runnable;
+
+ public PrioritizedRunnable(Supplier<Integer> prioritySupplier, Runnable runnable) {
+ this.prioritySupplier = prioritySupplier;
+ this.runnable = runnable;
+ }
+
+ @Override
+ public int compareTo(@Nonnull PrioritizedRunnable o) {
+ return Integer.compare(this.getPriority(), o.getPriority());
+ }
+
+ public int getPriority() {
+ return prioritySupplier.get();
+ }
+
+ @Override
+ public void run() {
+ runnable.run();
+ }
+}

View File

@ -0,0 +1,298 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Sun, 15 Nov 2020 10:42:27 +0800
Subject: [PATCH] Multi-threaded RegionFile IO
diff --git a/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
index 9fe91f9512ee8c2589fc8da76bda5f6d70c9fac4..8b81119cfdef81665a302d96cfada5bb43bc1077 100644
--- a/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
+++ b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
@@ -35,7 +35,7 @@ import java.util.function.Function;
* @see #scheduleSave(WorldServer, int, int, NBTTagCompound, NBTTagCompound, int)
* @see #loadChunkDataAsync(WorldServer, int, int, int, Consumer, boolean, boolean, boolean)
*/
-public final class PaperFileIOThread extends QueueExecutorThread {
+public final class PaperFileIOThread { // Yatopia
public static final Logger LOGGER = MinecraftServer.LOGGER;
public static final NBTTagCompound FAILURE_VALUE = new NBTTagCompound();
@@ -44,23 +44,84 @@ public final class PaperFileIOThread extends QueueExecutorThread {
public static final PaperFileIOThread INSTANCE = new PaperFileIOThread();
+ /* Yatopia
static {
INSTANCE.start();
}
+ */
}
private final AtomicLong writeCounter = new AtomicLong();
+ // Yatopia start - multi-threaded RegionFile IO
+ private final com.ibm.asyncutil.locks.AsyncNamedLock<RegionFileCoord> regionFileLock = com.ibm.asyncutil.locks.AsyncNamedLock.createFair();
+ private final PrioritizedTaskQueue<PrioritizedTaskQueue.PrioritizedTask> queue;
+ private final PaperFileIOThread.FileIOExecutorThread receiver;
+ private final java.util.Set<Thread> executorThreads = com.google.common.collect.Sets.newConcurrentHashSet();
+ private final java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newFixedThreadPool(
+ org.yatopiamc.yatopia.server.YatopiaConfig.regionFileIOThreadPoolSize == -1 ? Math.min(Runtime.getRuntime().availableProcessors(), Integer.getInteger("paper.maxChunkThreads", 8)) : org.yatopiamc.yatopia.server.YatopiaConfig.regionFileIOThreadPoolSize,
+ new com.google.common.util.concurrent.ThreadFactoryBuilder()
+ .setNameFormat("Paper RegionFile IO Worker #%d")
+ .setPriority(Thread.NORM_PRIORITY - 1)
+ .setDaemon(true)
+ .setThreadFactory(r -> {
+ Thread thr = new Thread(r);
+ executorThreads.add(thr);
+ return thr;
+ })
+ .setUncaughtExceptionHandler((t, e) -> {
+ LOGGER.fatal("Uncaught exception thrown from " + t.getName() + ", report this!", e);
+ executorThreads.remove(t);
+ })
+ .build()
+ );
private PaperFileIOThread() {
- super(new PrioritizedTaskQueue<>(), (int)(1.0e6)); // 1.0ms spinwait time
- this.setName("Paper RegionFile IO Thread");
- this.setPriority(Thread.NORM_PRIORITY - 1); // we keep priority close to normal because threads can wait on us
- this.setUncaughtExceptionHandler((final Thread unused, final Throwable thr) -> {
- LOGGER.fatal("Uncaught exception thrown from IO thread, report this!", thr);
+ queue = new PrioritizedTaskQueue<>();
+ receiver = new PaperFileIOThread.FileIOExecutorThread(queue, (int) (1.0e6)); // 1.0ms spinwait time
+ receiver.setName("Paper RegionFile IO Task Receiver");
+ receiver.setPriority(Thread.NORM_PRIORITY - 1); // we keep priority close to normal because threads can wait on us
+ receiver.setUncaughtExceptionHandler((final Thread thread, final Throwable thr) -> {
+ LOGGER.fatal("Uncaught exception thrown from " + thread.getName() + ", report this!", thr);
});
+ receiver.start();
+
+ }
+
+ public void flush() {
+ receiver.flush();
+ final java.util.Set<CompletableFuture<?>> runningTasks = new java.util.HashSet<>(receiver.runningTasks);
+ LOGGER.debug("Flushing Chunk IO: Waiting for {} futures", runningTasks.size());
+ for(CompletableFuture<?> future: runningTasks) {
+ try {
+ future.join();
+ } catch (Throwable ignored) {
+ }
+ }
+ }
+
+ private void queueTask(PrioritizedTaskQueue.PrioritizedTask newTask) {
+ queue.add(newTask);
+ receiver.notifyTasks();
+ }
+
+ public void close(final boolean wait) {
+ receiver.close(wait, true);
+ this.flush();
+ executor.shutdown();
+ while (wait && !executor.isTerminated()) {
+ try {
+ executor.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ public boolean isOnWorkerThread() {
+ return executorThreads.contains(Thread.currentThread());
}
- /* run() is implemented by superclass */
+ // Yatopia end
/*
*
@@ -394,6 +455,85 @@ public final class PaperFileIOThread extends QueueExecutorThread {
this.queueTask(new GeneralTask(priority, runnable));
}
+ // Yatopia start
+ public static final class RegionFileCoord {
+
+ public final int x;
+ public final int z;
+
+ public RegionFileCoord(int x, int z) {
+ this.x = x;
+ this.z = z;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RegionFileCoord that = (RegionFileCoord) o;
+ return x == that.x && z == that.z;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(x, z);
+ }
+ }
+
+ final class FileIOExecutorThread<T extends PrioritizedTaskQueue.PrioritizedTask & Runnable> extends QueueExecutorThread<T> {
+ private final java.util.Set<CompletableFuture<?>> runningTasks = com.google.common.collect.Sets.newConcurrentHashSet();
+
+ public FileIOExecutorThread(PrioritizedTaskQueue<T> queue, long spinWaitTime) {
+ super(queue, spinWaitTime);
+ }
+
+ @Override
+ protected void preMainLoop() {
+ runningTasks.removeIf(CompletableFuture::isDone);
+ }
+
+ @Override
+ protected boolean pollTasks(boolean flushTasks) {
+ Runnable task;
+ boolean ret = false;
+
+ while ((task = this.queue.poll()) != null) {
+ ret = true;
+ if (task instanceof ChunkDataTask) {
+ ChunkDataTask chunkDataTask = (ChunkDataTask) task;
+ runningTasks.add(regionFileLock.acquireLock(new RegionFileCoord(chunkDataTask.x >> 5, chunkDataTask.z >> 5))
+ .thenApplyAsync(lockToken -> {
+ try {
+ chunkDataTask.run();
+ } finally {
+ lockToken.releaseLock();
+ }
+ return null;
+ }, executor)
+ .exceptionally(throwable -> {
+ LOGGER.fatal("Exception thrown from prioritized runnable task in thread '" + Thread.currentThread().getName() + "': " + IOUtil.genericToString(chunkDataTask), throwable);
+ return null;
+ }).toCompletableFuture());
+ } else {
+ Runnable finalTask = task;
+ runningTasks.add(CompletableFuture.supplyAsync(() -> {
+ finalTask.run();
+ return null;
+ }).exceptionally(throwable -> {
+ LOGGER.fatal("Exception thrown from prioritized runnable task in thread '" + Thread.currentThread().getName() + "': " + IOUtil.genericToString(finalTask), throwable);
+ return null;
+ }));
+ }
+ }
+
+ if (flushTasks) {
+ this.handleFlushThreads(false);
+ }
+
+ return ret;
+ }
+ }
+ // Yatopia end
static final class GeneralTask extends PrioritizedTaskQueue.PrioritizedTask implements Runnable {
private final Runnable run;
diff --git a/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java b/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
index ee906b594b306906c170180a29a8b61997d05168..7e348fcb813707fee830082b826932e0bbba1c49 100644
--- a/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
+++ b/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
@@ -35,6 +35,7 @@ public class QueueExecutorThread<T extends PrioritizedTaskQueue.PrioritizedTask
final long spinWaitTime = this.spinWaitTime;
main_loop:
for (;;) {
+ preMainLoop(); // Yatopia
this.pollTasks(true);
// spinwait
@@ -81,11 +82,17 @@ public class QueueExecutorThread<T extends PrioritizedTaskQueue.PrioritizedTask
// LockSupport.park() can fail for any reason
do {
Thread.interrupted();
- LockSupport.park("Waiting on tasks");
+ LockSupport.parkNanos("Waiting on tasks", 1_000_000_000); // Yatopia - prevent dead lock
} while (this.parked.get());
}
}
+ // Yatopia start
+ protected void preMainLoop() {
+ // Used for PaperFileIOThread
+ }
+ // Yatopia end
+
protected boolean handleClose() {
if (this.closed) {
this.pollTasks(true); // this ensures we've emptied the queue
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index b21c09f5b1cde7f7a710fe8960face8cb21040c4..2c2c299f261685cff2866e4714ec0a251205ed9d 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -955,7 +955,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
LOGGER.info("Flushing Chunk IO");
net.minecraft.server.level.PlayerChunkMap.shutdownScheduler(); // Yatopia
net.minecraft.world.level.chunk.ChunkStatus.shutdownExecutors(); // Yatopia
- com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper
+ com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true); // Paper // Yatopia
LOGGER.info("Closing Thread Pool");
SystemUtils.shutdownServerThreadPool(); // Paper
LOGGER.info("Closing Server");
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
index b9d38413da1adbffd21df301f03cf181d4cd5cdc..7b1157de77d4e24a7540c070d922b49f2a06a319 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
@@ -1772,7 +1772,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@Nullable
@Override
public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException {
- if (Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (!com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
NBTTagCompound ret = com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE
.loadChunkDataAsyncFuture(this.world, chunkcoordintpair.x, chunkcoordintpair.z, com.destroystokyo.paper.io.IOUtil.getPriorityForCurrentThread(),
false, true, true).join().chunkData;
@@ -1787,7 +1787,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@Override
public void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException {
- if (Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (!com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(
this.world, chunkcoordintpair.x, chunkcoordintpair.z, null, nbttagcompound,
com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); // Tuinity - writes are async, no need for priority
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
index 29cd71efe86eea2227f373c15c39dc530e9e8199..55d497f4305de50e58c7e0788724576f81128138 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
@@ -504,7 +504,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
@javax.annotation.Nullable
@Override
public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws java.io.IOException {
- if (this.world != null && Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (this.world != null && !com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
NBTTagCompound ret = com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE
.loadChunkDataAsyncFuture(this.world, chunkcoordintpair.x, chunkcoordintpair.z, com.destroystokyo.paper.io.IOUtil.getPriorityForCurrentThread(),
true, false, true).join().poiData;
@@ -519,7 +519,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
@Override
public void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws java.io.IOException {
- if (this.world != null && Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (this.world != null && !com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(
this.world, chunkcoordintpair.x, chunkcoordintpair.z, nbttagcompound, null,
com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); // Tuinity - writes are async, no need for priority
diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
index 7d8e04a5792283a27c044758fb4bc12567b289cb..fa16608b24cd68e4195e72143d39db38702dba40 100644
--- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
+++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
@@ -286,4 +286,9 @@ public class YatopiaConfig {
Preconditions.checkArgument(worldGenExecutorSize == -1 || worldGenExecutorSize > 0, "Invalid settings.threads.worldgen in yatopia.yml");
}
+ public static int regionFileIOThreadPoolSize = -1;
+ private static void multiThreadedRegionFile() {
+ regionFileIOThreadPoolSize = getInt("settings.threads.regionfile", -1);
+ Preconditions.checkArgument(regionFileIOThreadPoolSize == -1 || regionFileIOThreadPoolSize > 0, "Invalid settings.threads.regionfile in yatopia.yml");
+ }
}

View File

@ -0,0 +1,144 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Fri, 5 Feb 2021 19:34:00 +0800
Subject: [PATCH] Multi-threaded World Upgrade
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 6818f8496ab76ee6ffc747bd6848b43830ec8914..1fe2610ed0ddab1e203e273914c9325aec74e7c2 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -281,6 +281,8 @@ public class Main {
WorldUpgrader worldupgrader = new WorldUpgrader(convertable_conversionsession, datafixer, immutableset, flag);
IChatBaseComponent ichatbasecomponent = null;
+ long lastLocation = 0L; // Yatopia
+ long lastTime = System.nanoTime(); // Yatopia
while (!worldupgrader.b()) {
IChatBaseComponent ichatbasecomponent1 = worldupgrader.h();
@@ -289,13 +291,16 @@ public class Main {
Main.LOGGER.info(worldupgrader.h().getString());
}
- int i = worldupgrader.e();
-
- if (i > 0) {
- int j = worldupgrader.f() + worldupgrader.g();
-
- Main.LOGGER.info("{}% completed ({} / {} chunks)...", MathHelper.d((float) j / (float) i * 100.0F), j, i);
- }
+ // Yatopia start
+ long totalChunkCount = worldupgrader.getTotalChunkCount();
+ if (totalChunkCount > 0) {
+ long processedCount = worldupgrader.getUpgradedChunkCount() + worldupgrader.getSkippedChunkCount();
+ long currentTime = System.nanoTime();
+ String speedRate = String.format("%.1f", (processedCount - lastLocation) / ((currentTime - lastTime) / 1_000_000_000.0));
+ Main.LOGGER.info("{}% completed ({} / {} chunks) at {}cps...", MathHelper.d((float) processedCount / (float) totalChunkCount * 100.0F), processedCount, totalChunkCount, speedRate);
+ lastLocation = processedCount;
+ lastTime = currentTime;
+ } // Yatopia end
if (!booleansupplier.getAsBoolean()) {
worldupgrader.a();
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
index 6725b31a5183d5af7f8f7566ed21eb61797ef4c9..f13e16aca89f5013ef316e7dbf3d4c67885e6f3e 100644
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -33,6 +33,13 @@ import net.minecraft.world.level.storage.Convertable;
import net.minecraft.world.level.storage.WorldPersistentData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+// Yatopia start
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+// Yatopia end
// CraftBukkit start
import net.minecraft.world.level.dimension.DimensionManager;
@@ -50,9 +57,9 @@ public class WorldUpgrader {
private volatile boolean h = true;
private volatile boolean i;
private volatile float j;
- private volatile int k;
- private volatile int l;
- private volatile int m;
+ private volatile long k; // Yatopia - int -> long
+ private volatile long l; // Yatopia - int -> long
+ private volatile long m; // Yatopia - int -> long
private final Object2FloatMap<ResourceKey<DimensionManager>> n = Object2FloatMaps.synchronize(new Object2FloatOpenCustomHashMap(SystemUtils.k())); // CraftBukkit
private volatile IChatBaseComponent o = new ChatMessage("optimizeWorld.stage.counting");
private static final Pattern p = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
@@ -117,6 +124,11 @@ public class WorldUpgrader {
this.o = new ChatMessage("optimizeWorld.stage.upgrading");
+ // Yatopia start
+ final ExecutorService upgradeExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setDaemon(true).setPriority(Thread.NORM_PRIORITY - 1).setNameFormat("WorldUpgrader Worker #%d").build());
+ final Set<CompletableFuture<Void>> futures = new ObjectOpenHashSet<>();
+ final com.ibm.asyncutil.locks.AsyncNamedLock<Integer> regionFileLocks = com.ibm.asyncutil.locks.AsyncNamedLock.createFair();
+ // Yatopia end
while (this.h) {
boolean flag = false;
float f1 = 0.0F;
@@ -130,6 +142,11 @@ public class WorldUpgrader {
if (listiterator.hasNext()) {
ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) listiterator.next();
+ // Yatopia start
+ flag = true;
+ futures.add(regionFileLocks.acquireLock(String.format("%d %d", chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()).hashCode()).toCompletableFuture().thenAcceptAsync(lockToken -> {
+ try {
+ // Yatopia end
boolean flag1 = false;
try {
@@ -179,7 +196,12 @@ public class WorldUpgrader {
++this.m;
}
- flag = true;
+ // Yatopia start
+ } finally {
+ lockToken.releaseLock();
+ }
+ }, upgradeExecutor));
+ // Yatopia end
}
f2 = (float) listiterator.nextIndex() / f;
@@ -192,6 +214,8 @@ public class WorldUpgrader {
}
}
+ CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // Yatopia
+ upgradeExecutor.shutdown(); // Yatopia
this.o = new ChatMessage("optimizeWorld.stage.finished");
UnmodifiableIterator unmodifiableiterator3 = immutablemap1.values().iterator();
@@ -280,16 +304,19 @@ public class WorldUpgrader {
}
public int e() {
- return this.k;
+ return (int) this.k; // Yatopia
}
+ public long getTotalChunkCount() { return this.k; } // Yatopia
public int f() {
- return this.l;
+ return (int) this.l; // Yatopia
}
+ public long getUpgradedChunkCount() { return this.l; } // Yatopia
public int g() {
- return this.m;
+ return (int) this.m; // Yatopia
}
+ public long getSkippedChunkCount() { return this.m; } // Yatopia
public IChatBaseComponent h() {
return this.o;

View File

@ -0,0 +1,147 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Wed, 3 Feb 2021 23:00:18 +0800
Subject: [PATCH] Decompile fixes for WorldChunkManagerMultiNoise
who knows what duplex is doing
diff --git a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
index c4fb051739c1c186c1574185e0653f513755987d..e9993fa0f3af9e3ecd01f91ef5c14e528bdb33b5 100644
--- a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
+++ b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
@@ -52,6 +52,13 @@ import org.apache.logging.log4j.Logger;
public final class BiomeBase {
public static final Logger LOGGER = LogManager.getLogger();
+ // Yatopia start
+ static class cProxy extends BiomeBase.c {
+ public cProxy(float f, float f1, float f2, float f3, float f4) {
+ super(f, f1, f2, f3, f4);
+ }
+ }
+ // Yatopia end
// Paper start
private static class dProxy extends BiomeBase.d {
private dProxy(Precipitation biomebase_precipitation, float f, TemperatureModifier biomebase_temperaturemodifier, float f1) {
diff --git a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
index 5287aec4c384c6cea76334ae1d8dc99070e8f43e..92d1e771c2f896fb3b363a57aa59c04c3f466bea 100644
--- a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
+++ b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Function3;
+import com.mojang.datafixers.util.Function6; // Yatopia - decompile fix
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
@@ -27,26 +28,43 @@ import net.minecraft.world.level.levelgen.synth.NoiseGeneratorNormal;
public class WorldChunkManagerMultiNoise extends WorldChunkManager {
+ // Yatopia start - decompile fix
+ private static class aProxy extends WorldChunkManagerMultiNoise.a {
+ public aProxy(int i, List<Double> list) {
+ super(i, list);
+ }
+ }
+ private static class bProxy extends WorldChunkManagerMultiNoise.b {
+ public bProxy(MinecraftKey minecraftkey, Function3<WorldChunkManagerMultiNoise.b, IRegistry<BiomeBase>, Long, WorldChunkManagerMultiNoise> function3) {
+ super(minecraftkey, function3);
+ }
+ }
+ private static class cProxy extends WorldChunkManagerMultiNoise.c {
+ private cProxy(WorldChunkManagerMultiNoise.b worldchunkmanagermultinoise_b, IRegistry<BiomeBase> iregistry, long i) {
+ super(worldchunkmanagermultinoise_b, iregistry, i);
+ }
+ }
+ // Yatopia end
private static final WorldChunkManagerMultiNoise.a g = new WorldChunkManagerMultiNoise.a(-7, ImmutableList.of(1.0D, 1.0D));
public static final MapCodec<WorldChunkManagerMultiNoise> e = RecordCodecBuilder.mapCodec((instance) -> {
return instance.group(Codec.LONG.fieldOf("seed").forGetter((worldchunkmanagermultinoise) -> {
return worldchunkmanagermultinoise.r;
}), RecordCodecBuilder.create((instance1) -> {
- return instance1.group(BiomeBase.c.a.fieldOf("parameters").forGetter(Pair::getFirst), BiomeBase.d.fieldOf("biome").forGetter(Pair::getSecond)).apply(instance1, Pair::of);
- }).listOf().fieldOf("biomes").forGetter((worldchunkmanagermultinoise) -> {
- return worldchunkmanagermultinoise.p;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("temperature_noise").forGetter((worldchunkmanagermultinoise) -> {
+ return instance1.group(BiomeBase.cProxy.a.fieldOf("parameters").forGetter((java.util.function.Function) t -> ((Pair) t).getFirst()), BiomeBase.d.fieldOf("biome").forGetter(t1 -> (Supplier<BiomeBase>) ((Pair) t1).getSecond())).apply(instance1, Pair::of); // Yatopia - decompile fix
+ }).listOf().fieldOf("biomes").forGetter((Function) worldchunkmanagermultinoise -> { // Yatopia - decompile fix
+ return ((WorldChunkManagerMultiNoise) worldchunkmanagermultinoise).p; // Yatopia - decompile fix
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("temperature_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.h;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("humidity_noise").forGetter((worldchunkmanagermultinoise) -> {
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("humidity_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.i;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("altitude_noise").forGetter((worldchunkmanagermultinoise) -> {
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("altitude_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.j;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("weirdness_noise").forGetter((worldchunkmanagermultinoise) -> {
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("weirdness_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.k;
- })).apply(instance, WorldChunkManagerMultiNoise::new);
+ })).apply(instance, (Function6<Long, List<Pair<BiomeBase.c, Supplier<BiomeBase>>>, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise>) WorldChunkManagerMultiNoise::new); // Yatopia - decompile fix
});
- public static final Codec<WorldChunkManagerMultiNoise> f = Codec.mapEither(WorldChunkManagerMultiNoise.c.a, WorldChunkManagerMultiNoise.e).xmap((either) -> {
- return (WorldChunkManagerMultiNoise) either.map(WorldChunkManagerMultiNoise.c::d, Function.identity());
+ public static final Codec<WorldChunkManagerMultiNoise> f = Codec.mapEither(WorldChunkManagerMultiNoise.cProxy.a, WorldChunkManagerMultiNoise.e).xmap((either) -> { // Yatopia - decompile fix
+ return (WorldChunkManagerMultiNoise) either.map(c -> c.d(), Function.identity()); // Yatopia - decompile fix
}, (worldchunkmanagermultinoise) -> {
return (Either) worldchunkmanagermultinoise.d().map(Either::left).orElseGet(() -> {
return Either.right(worldchunkmanagermultinoise);
@@ -111,13 +129,13 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
}
public boolean b(long i) {
- return this.r == i && this.s.isPresent() && Objects.equals(((Pair) this.s.get()).getSecond(), WorldChunkManagerMultiNoise.b.a);
+ return this.r == i && this.s.isPresent() && Objects.equals(((Pair) this.s.get()).getSecond(), WorldChunkManagerMultiNoise.bProxy.a); // Yatopia - decompile fix
}
public static class b {
- private static final Map<MinecraftKey, WorldChunkManagerMultiNoise.b> b = Maps.newHashMap();
- public static final WorldChunkManagerMultiNoise.b a = new WorldChunkManagerMultiNoise.b(new MinecraftKey("nether"), (worldchunkmanagermultinoise_b, iregistry, olong) -> {
+ protected static final Map<MinecraftKey, WorldChunkManagerMultiNoise.b> b = Maps.newHashMap(); // Yatopia - decompile fix
+ public static final WorldChunkManagerMultiNoise.b a = new WorldChunkManagerMultiNoise.b(new MinecraftKey("nether"), (worldchunkmanagermultinoise_b, iregistry, olong) -> { // Yatopia - decompile fix
return new WorldChunkManagerMultiNoise(olong, ImmutableList.of(Pair.of(new BiomeBase.c(0.0F, 0.0F, 0.0F, 0.0F, 0.0F), () -> {
return (BiomeBase) iregistry.d(Biomes.NETHER_WASTES);
}), Pair.of(new BiomeBase.c(0.0F, -0.5F, 0.0F, 0.0F, 0.0F), () -> {
@@ -136,7 +154,7 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
public b(MinecraftKey minecraftkey, Function3<WorldChunkManagerMultiNoise.b, IRegistry<BiomeBase>, Long, WorldChunkManagerMultiNoise> function3) {
this.c = minecraftkey;
this.d = function3;
- WorldChunkManagerMultiNoise.b.b.put(minecraftkey, this);
+ WorldChunkManagerMultiNoise.bProxy.b.put(minecraftkey, this); // Yatopia - decompile fix
}
public WorldChunkManagerMultiNoise a(IRegistry<BiomeBase> iregistry, long i) {
@@ -144,16 +162,16 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
}
}
- static final class c {
+ static class c { // Yatopia - decompile fix
public static final MapCodec<WorldChunkManagerMultiNoise.c> a = RecordCodecBuilder.mapCodec((instance) -> {
return instance.group(MinecraftKey.a.flatXmap((minecraftkey) -> {
- return (DataResult) Optional.ofNullable(WorldChunkManagerMultiNoise.b.b.get(minecraftkey)).map(DataResult::success).orElseGet(() -> {
+ return (DataResult) Optional.ofNullable(bProxy.b.get(minecraftkey)).map(DataResult::success).orElseGet(() -> { // Yatopia - decompile fix
return DataResult.error("Unknown preset: " + minecraftkey);
});
}, (worldchunkmanagermultinoise_b) -> {
- return DataResult.success(worldchunkmanagermultinoise_b.c);
- }).fieldOf("preset").stable().forGetter(WorldChunkManagerMultiNoise.c::a), RegistryLookupCodec.a(IRegistry.ay).forGetter(WorldChunkManagerMultiNoise.c::b), Codec.LONG.fieldOf("seed").stable().forGetter(WorldChunkManagerMultiNoise.c::c)).apply(instance, instance.stable(WorldChunkManagerMultiNoise.c::new));
+ return DataResult.success(((WorldChunkManagerMultiNoise.b) worldchunkmanagermultinoise_b).c); // Yatopia - decompile fix
+ }).fieldOf("preset").stable().forGetter(o -> ((WorldChunkManagerMultiNoise.c) o).a()), (RecordCodecBuilder) RegistryLookupCodec.a(IRegistry.ay).forGetter((Function<WorldChunkManagerMultiNoise.c, IRegistry<BiomeBase>>) c -> c.b()), (RecordCodecBuilder) Codec.LONG.fieldOf("seed").stable().forGetter((Function<WorldChunkManagerMultiNoise.c, Long>) c -> c.c())).apply(instance, instance.stable((Function3<WorldChunkManagerMultiNoise.b, IRegistry<BiomeBase>, Long, WorldChunkManagerMultiNoise.c>) WorldChunkManagerMultiNoise.c::new)); // Yatopia - decompile fix
});
private final WorldChunkManagerMultiNoise.b b;
private final IRegistry<BiomeBase> c;
@@ -187,7 +205,7 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
private final int b;
private final DoubleList c;
public static final Codec<WorldChunkManagerMultiNoise.a> a = RecordCodecBuilder.create((instance) -> {
- return instance.group(Codec.INT.fieldOf("firstOctave").forGetter(WorldChunkManagerMultiNoise.a::a), Codec.DOUBLE.listOf().fieldOf("amplitudes").forGetter(WorldChunkManagerMultiNoise.a::b)).apply(instance, WorldChunkManagerMultiNoise.a::new);
+ return instance.group(Codec.INT.fieldOf("firstOctave").forGetter((Function<WorldChunkManagerMultiNoise.a, Integer>) a -> a.a()), Codec.DOUBLE.listOf().fieldOf("amplitudes").forGetter(a -> a.b())).apply(instance, WorldChunkManagerMultiNoise.a::new); // Yatopia - decompile fix
});
public a(int i, List<Double> list) {

View File

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: SuperCoder7979 <25208576+SuperCoder7979@users.noreply.github.com>
Date: Wed, 3 Feb 2021 16:39:27 -0600
Subject: [PATCH] lithium MultiNoiseBiomeSourceMixin
diff --git a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
index 92d1e771c2f896fb3b363a57aa59c04c3f466bea..23637d9be9f9973266c1bba699c40cdc6c5d9e6d 100644
--- a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
+++ b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
@@ -118,8 +118,44 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
});
}
+ //Yatopia - Faster Method
+ /**
+ * @reason Remove stream based code in favor of regular collections.
+ * @author SuperCoder79
+ */
@Override
public BiomeBase getBiome(int i, int j, int k) {
+ // [VanillaCopy] MultiNoiseBiomeSource#getBiomeForNoiseGen
+
+ // Get the y value for perlin noise sampling. This field is always set to false in vanilla code.
+ int l = this.q ? j : 0;
+
+ // Calculate the noise point based using 4 perlin noise samplers.
+ BiomeBase.c biomebase_c = new BiomeBase.c(
+ (float) this.l.a(i, l, k),
+ (float) this.m.a(i, l, k),
+ (float) this.n.a(i, l, k),
+ (float) this.o.a(i, l, k),
+ 0.0F);
+
+ int idx = -1;
+ float min = Float.POSITIVE_INFINITY;
+
+ // Iterate through the biome points and calculate the distance to the current noise point.
+ for (int itterator = 0; itterator < this.p.size(); itterator++) {
+ float distance = this.p.get(itterator).getFirst().a(biomebase_c);
+
+ // If the distance is less than the recorded minimum, update the minimum and set the current index.
+ if (min > distance) {
+ idx = itterator;
+ min = distance;
+ }
+ }
+
+ // Return the biome with the noise point closest to the evaluated one.
+ return this.p.get(idx).getSecond().get() == null ? BiomeRegistry.b : this.p.get(idx).getSecond().get();
+ }
+ /* //Yatopia - Replace Method
int l = this.q ? j : 0;
BiomeBase.c biomebase_c = new BiomeBase.c((float) this.l.a((double) i, (double) l, (double) k), (float) this.m.a((double) i, (double) l, (double) k), (float) this.n.a((double) i, (double) l, (double) k), (float) this.o.a((double) i, (double) l, (double) k), 0.0F);
@@ -127,6 +163,8 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
return ((BiomeBase.c) pair.getFirst()).a(biomebase_c);
})).map(Pair::getSecond).map(Supplier::get).orElse(BiomeRegistry.b);
}
+ */ //Yatopia End
+
public boolean b(long i) {
return this.r == i && this.s.isPresent() && Objects.equals(((Pair) this.s.get()).getSecond(), WorldChunkManagerMultiNoise.bProxy.a); // Yatopia - decompile fix

View File

@ -0,0 +1,188 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Fri, 5 Feb 2021 23:13:42 +0800
Subject: [PATCH] fixup! Threaded WorldGen
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunk.java b/src/main/java/net/minecraft/server/level/PlayerChunk.java
index d9b134302f739efd93f50e93c8730b474f9a8ccf..d92cbfcf5374940e3bcc7746dd68fb8171ca4df8 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunk.java
@@ -586,6 +586,7 @@ public class PlayerChunk {
return this.ticketLevel;
}
+ public int getPriority() { return k(); } // Yatopia - OBFHELPER
public int k() {
return this.n;
}
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
index 7b1157de77d4e24a7540c070d922b49f2a06a319..8bb1e4486be2860fb5642501bf1e4aaba3bbbd40 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
@@ -1280,9 +1280,9 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
if (!com.tuinity.tuinity.config.TuinityConfig.useNewLightEngine && chunkstatus == ChunkStatus.LIGHT) { // Tuinity - we use edge checks, so loading 1 radius neighbours isn't necessary
completablefuture1 = this.b(playerchunk, chunkstatus);
} else {
- completablefuture1 = chunkstatus.a(this.world, this.definedStructureManager, this.lightEngine, (ichunkaccess1) -> {
+ completablefuture1 = chunkstatus.runLoadTask(this.world, this.definedStructureManager, this.lightEngine, (ichunkaccess1) -> { // Yatopia
return this.c(playerchunk);
- }, ichunkaccess);
+ }, ichunkaccess, playerchunk.getPriority()); // Yatopia
}
this.worldLoadListener.a(chunkcoordintpair, chunkstatus);
@@ -1393,9 +1393,9 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return completablefuture.thenComposeAsync((either) -> {
return either.map((list) -> { // Paper - Shut up.
try {
- CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture1 = chunkstatus.a(this.world, this.chunkGenerator, this.definedStructureManager, this.lightEngine, (ichunkaccess) -> {
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture1 = chunkstatus.runGenerationTask(this.world, this.chunkGenerator, this.definedStructureManager, this.lightEngine, (ichunkaccess) -> {
return this.c(playerchunk);
- }, list);
+ }, list, playerchunk.getPriority());
this.worldLoadListener.a(chunkcoordintpair, chunkstatus);
return completablefuture1;
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
index a01d6dfe147383242e514d2807558bf94ff8865a..b33dd2602c592f0ed5d45d0a5a1ec87f6904aaed 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
@@ -69,7 +69,7 @@ public class ChunkStatus {
private static final EnumSet<HeightMap.Type> n = EnumSet.of(HeightMap.Type.OCEAN_FLOOR_WG, HeightMap.Type.WORLD_SURFACE_WG);
private static final EnumSet<HeightMap.Type> o = EnumSet.of(HeightMap.Type.OCEAN_FLOOR, HeightMap.Type.WORLD_SURFACE, HeightMap.Type.MOTION_BLOCKING, HeightMap.Type.MOTION_BLOCKING_NO_LEAVES);
- private static final ChunkStatus.c p = (chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess) -> {
+ private static final ChunkStatus.c p = (chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess, priority) -> { // Yatopia
if (ichunkaccess instanceof ProtoChunk && !ichunkaccess.getChunkStatus().b(chunkstatus)) {
((ProtoChunk) ichunkaccess).a(chunkstatus);
}
@@ -78,14 +78,14 @@ public class ChunkStatus {
};
public static final ChunkStatus EMPTY = a("empty", (ChunkStatus) null, -1, ChunkStatus.n, ChunkStatus.Type.PROTOCHUNK, (worldserver, chunkgenerator, list, ichunkaccess) -> {
});
- public static final ChunkStatus STRUCTURE_STARTS = a("structure_starts", ChunkStatus.EMPTY, 0, ChunkStatus.n, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess) -> {
+ public static final ChunkStatus STRUCTURE_STARTS = a("structure_starts", ChunkStatus.EMPTY, 0, ChunkStatus.n, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess, priority) -> { // Yatopia
CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> result = CompletableFuture.completedFuture(Either.left(ichunkaccess));
if (!ichunkaccess.getChunkStatus().b(chunkstatus)) {
if (worldserver.worldDataServer.getGeneratorSettings().shouldGenerateMapFeatures()) { // CraftBukkit
result = CompletableFuture.supplyAsync(() -> {
chunkgenerator.createStructures(worldserver.r(), worldserver.getStructureManager(), ichunkaccess, definedstructuremanager, worldserver.getSeed());
return Either.left(ichunkaccess);
- }, command -> worldGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : 0, command)));
+ }, command -> worldGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : priority, command)));
}
if (ichunkaccess instanceof ProtoChunk) {
result.thenRun(() -> ((ProtoChunk) ichunkaccess).a(chunkstatus));
@@ -116,7 +116,7 @@ public class ChunkStatus {
public static final ChunkStatus LIQUID_CARVERS = a("liquid_carvers", ChunkStatus.CARVERS, 0, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (worldserver, chunkgenerator, list, ichunkaccess) -> {
chunkgenerator.doCarving(worldserver.getSeed(), worldserver.d(), ichunkaccess, WorldGenStage.Features.LIQUID);
});
- public static final ChunkStatus FEATURES = a("features", ChunkStatus.LIQUID_CARVERS, 8, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess) -> {
+ public static final ChunkStatus FEATURES = a("features", ChunkStatus.LIQUID_CARVERS, 8, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess, priority) -> { // Yatopia
// Yatopia start - threaded WorldGen
return chunkgenerator.featureGenLock.acquireLock().toCompletableFuture().thenComposeAsync(token -> {
try {
@@ -135,12 +135,12 @@ public class ChunkStatus {
}
return CompletableFuture.completedFuture(Either.left(ichunkaccess));
- }, command -> featureGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : 0, command)));
+ }, command -> featureGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : priority, command)));
// Yatopia end
});
- public static final ChunkStatus LIGHT = a("light", ChunkStatus.FEATURES, 1, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess) -> {
+ public static final ChunkStatus LIGHT = a("light", ChunkStatus.FEATURES, 1, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess, priority) -> { // Yatopia
return a(chunkstatus, lightenginethreaded, ichunkaccess);
- }, (chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess) -> {
+ }, (chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess, priority) -> { // Yatopia
return a(chunkstatus, lightenginethreaded, ichunkaccess);
});
public static final ChunkStatus SPAWN = a("spawn", ChunkStatus.LIGHT, 0, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (worldserver, chunkgenerator, list, ichunkaccess) -> {
@@ -148,9 +148,9 @@ public class ChunkStatus {
});
public static final ChunkStatus HEIGHTMAPS = a("heightmaps", ChunkStatus.SPAWN, 0, ChunkStatus.o, ChunkStatus.Type.PROTOCHUNK, (worldserver, chunkgenerator, list, ichunkaccess) -> {
});
- public static final ChunkStatus FULL = a("full", ChunkStatus.HEIGHTMAPS, 0, ChunkStatus.o, ChunkStatus.Type.LEVELCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess) -> {
+ public static final ChunkStatus FULL = a("full", ChunkStatus.HEIGHTMAPS, 0, ChunkStatus.o, ChunkStatus.Type.LEVELCHUNK, (chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess, priority) -> { // Yatopia
return (CompletableFuture) function.apply(ichunkaccess);
- }, (chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess) -> {
+ }, (chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess, priority) -> { // Yatopia
return (CompletableFuture) function.apply(ichunkaccess);
});
private static final List<ChunkStatus> q = ImmutableList.of(ChunkStatus.FULL, ChunkStatus.FEATURES, ChunkStatus.LIQUID_CARVERS, ChunkStatus.STRUCTURE_STARTS, ChunkStatus.STRUCTURE_STARTS, ChunkStatus.STRUCTURE_STARTS, ChunkStatus.STRUCTURE_STARTS, ChunkStatus.STRUCTURE_STARTS, ChunkStatus.STRUCTURE_STARTS, ChunkStatus.STRUCTURE_STARTS, ChunkStatus.STRUCTURE_STARTS);
@@ -254,11 +254,23 @@ public class ChunkStatus {
}
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> a(WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list) {
- return this.v.doWork(this, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, (IChunkAccess) list.get(list.size() / 2));
+ // Yatopia start - add priority param
+ return runGenerationTask(worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, Integer.MAX_VALUE);
+ }
+
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> runGenerationTask(WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list, int priority) {
+ return this.v.doWork(this, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, (IChunkAccess) list.get(list.size() / 2), priority);
+ // Yatopia end
}
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> a(WorldServer worldserver, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, IChunkAccess ichunkaccess) {
- return this.w.doWork(this, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess);
+ // Yatopia start - add priority param
+ return runLoadTask(worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess, Integer.MAX_VALUE);
+ }
+
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> runLoadTask(WorldServer worldserver, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, IChunkAccess ichunkaccess, int priority) {
+ return this.w.doWork(this, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess, priority);
+ // Yatopia end
}
public final int getNeighborRadius() { return this.f(); } // Paper - OBFHELPER
@@ -309,6 +321,13 @@ public class ChunkStatus {
@Override
default CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list, IChunkAccess ichunkaccess) {
+ // Yatopia start - add priority param
+ return doWork(chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess, Integer.MAX_VALUE);
+ }
+
+ @Override
+ default CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list, IChunkAccess ichunkaccess, int priority) {
+ // Yatopia end
// Yatopia start - threaded worldGen
return CompletableFuture.supplyAsync(() -> {
if (!ichunkaccess.getChunkStatus().b(chunkstatus)) {
@@ -318,7 +337,7 @@ public class ChunkStatus {
}
}
return Either.left(ichunkaccess);
- }, command -> worldGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : 0, command)));
+ }, command -> worldGenExecutor.execute(new org.yatopiamc.yatopia.server.executors.PrioritizedRunnable(() -> com.destroystokyo.paper.io.chunk.ChunkTaskManager.hasChunkWait(worldserver, ichunkaccess.getPos().x, ichunkaccess.getPos().z) ? Integer.MIN_VALUE : priority, command)));
// Yatopia end
}
@@ -328,11 +347,23 @@ public class ChunkStatus {
interface c {
- CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, IChunkAccess ichunkaccess);
+ // Yatopia start - add priority param
+ default CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, IChunkAccess ichunkaccess) {
+ return this.doWork(chunkstatus, worldserver, definedstructuremanager, lightenginethreaded, function, ichunkaccess, Integer.MAX_VALUE);
+ }
+
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, IChunkAccess ichunkaccess, int priority);
+ // Yatopia end
}
interface b {
- CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list, IChunkAccess ichunkaccess);
+ // Yatopia start - add priority param
+ default CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list, IChunkAccess ichunkaccess) {
+ return doWork(chunkstatus, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, ichunkaccess, Integer.MAX_VALUE);
+ }
+
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> doWork(ChunkStatus chunkstatus, WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list, IChunkAccess ichunkaccess, int priority);
+ // Yatopia end
}
}

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Tue, 9 Feb 2021 21:42:09 +0800
Subject: [PATCH] Force world save
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
index 55d497f4305de50e58c7e0788724576f81128138..edb45dd2933b985efb29d61b2a844615f5f1cc9f 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
@@ -366,6 +366,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
}).orElse(false);
}
+ private final java.util.concurrent.atomic.AtomicBoolean hasWorked = new java.util.concurrent.atomic.AtomicBoolean(false); // Yatopia - enforce one chunk unload per tick
@Override
public void a(BooleanSupplier booleansupplier) {
// Paper start - async chunk io
@@ -373,7 +374,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
super.a(booleansupplier);
} else {
//super.a(booleansupplier); // re-implement below
- while (!((RegionFileSection)this).d.isEmpty() && booleansupplier.getAsBoolean() && !this.world.isSavingDisabled()) { // Tuinity - unload POI data - don't write to disk if saving is disabled
+ hasWorked.set(false); while (!((RegionFileSection)this).d.isEmpty() && (hasWorked.compareAndSet(false, true) || booleansupplier.getAsBoolean()) && !this.world.isSavingDisabled()) { // Tuinity - unload POI data - don't write to disk if saving is disabled // Yatopia - enforce one chunk unload per tick
ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(((RegionFileSection)this).d.firstLong()).r();
NBTTagCompound data;
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
index f70c14385c95763b5f270a6e2ce372cf047ba7bb..4454489153f7932deaaebe8aa32ecb603764f42b 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
@@ -50,8 +50,9 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
//this.b = new IOWorker(file, flag, file.getName()); // Paper - nuke IOWorker
}
+ private final java.util.concurrent.atomic.AtomicBoolean hasWorked = new java.util.concurrent.atomic.AtomicBoolean(false); // Yatopia - enforce one chunk unload per tick
protected void a(BooleanSupplier booleansupplier) {
- while (!this.d.isEmpty() && booleansupplier.getAsBoolean()) {
+ hasWorked.set(false); while (!this.d.isEmpty() && (hasWorked.compareAndSet(false, true) || booleansupplier.getAsBoolean())) { // Yatopia - enforce one chunk unload per tick
ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(this.d.firstLong()).r(); // Paper - conflict here to avoid obfhelpers
this.d(chunkcoordintpair);

View File

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Sat, 20 Feb 2021 22:39:16 +0800
Subject: [PATCH] fixup! Threaded WorldGen
diff --git a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
index 194321b7183d3aaa8031608a979dde71006e2fab..f5690544c1fec4b5e2e4535c2692c809074dca66 100644
--- a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
@@ -841,16 +841,18 @@ public class ChunkProviderServer extends IChunkProvider {
// Yatopia start - reduce scheduling overhead
final ConcurrentLinkedQueue<Runnable> poiQueue = new ConcurrentLinkedQueue<>();
- private boolean runPoiQueueNext() { // TODO flush poi queue?
- try {
- final Runnable runnable = poiQueue.poll();
- if (runnable != null)
+ private boolean runPoiQueueNext() {
+ boolean hasWork = false;
+ Runnable runnable;
+ while ((runnable = poiQueue.poll()) != null) {
+ hasWork = true;
+ try {
runnable.run();
- return runnable != null;
- } catch (Throwable t) {
- t.printStackTrace();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
}
- return false;
+ return hasWork;
}
public boolean runTasks() {