mirror of
https://github.com/YatopiaMC/Yatopia.git
synced 2024-11-15 15:16:37 +01:00
473 lines
28 KiB
Diff
473 lines
28 KiB
Diff
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 d0259f18488e1ecf0276865e0ff7958726a40033..f0a73238612327d71cf78801df816823d80893a0 100644
|
|
--- a/pom.xml
|
|
+++ b/pom.xml
|
|
@@ -203,6 +203,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 6fd059412e07e1b3b2597b693df5a4f439ebe382..d397fc9f924b8c7947392a8385fd6074d215dfb8 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -962,6 +962,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 0b9ed4042612f5242e5b2d057b716170f22c78b1..0a2edb9ac73ed71e67833f17824d3be5909e3445 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
|
|
@@ -1372,7 +1384,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 d7f95bd32842fdee0ce53fc97d31ffb3577cdc78..e2952e889ed40b5eea3971321dc11b10840166d5 100644
|
|
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
@@ -2780,14 +2780,13 @@ public class WorldServer extends World implements GeneratorAccessSeed, NonBlocki
|
|
BlockPosition blockposition1 = blockposition.immutableCopy(); // Tuinity - oh god not for each block set
|
|
// Paper end
|
|
|
|
+ // Yatopia start - reduce scheduling overhead
|
|
+ chunkProvider.poiQueue.add(() -> {
|
|
optional.ifPresent((villageplacetype) -> {
|
|
- this.getMinecraftServer().execute(() -> {
|
|
this.y().a(blockposition1);
|
|
PacketDebug.b(this, blockposition1);
|
|
- });
|
|
});
|
|
optional1.ifPresent((villageplacetype) -> {
|
|
- this.getMinecraftServer().execute(() -> {
|
|
// Tuinity start - remove POIs before inserting, better version of paper's diff
|
|
if (!optional.isPresent() && this.getPoiStorage().test(blockposition1, com.google.common.base.Predicates.alwaysTrue())) {
|
|
this.getPoiStorage().remove(blockposition1);
|
|
@@ -2795,8 +2794,9 @@ public class WorldServer extends World implements GeneratorAccessSeed, NonBlocki
|
|
// Tuinity end - remove POIs before inserting, better version of paper's diff
|
|
this.y().a(blockposition1, villageplacetype);
|
|
PacketDebug.a(this, blockposition1);
|
|
- });
|
|
});
|
|
+ });
|
|
+ // Yatopia end
|
|
}
|
|
}
|
|
|
|
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 13983f3271d33ab6e4c7030de5865edbd7b0cd8a..4fa7ecef64effc37e9ad5ae18b32198523fc5f8d 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
|
|
@@ -843,7 +843,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();
|
|
+ }
|
|
+}
|