Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
- index 1f50004cb..1fdc2ac6e 100644
- --- a/src/main/java/net/minecraft/server/Chunk.java
- +++ b/src/main/java/net/minecraft/server/Chunk.java
- @@ -1386,7 +1386,7 @@ public class Chunk implements IChunkAccess {
- throw new RuntimeException("Error while adding chunk to cache. Too many neighbors");
- } else {
- if (this.K()) {
- - ((IAsyncTaskHandler) this.world).postToMainThread(this::E);
- + MCUtil.ensureMain(this::E); // Paper - use processQueue instead of the other queue
- }
- }
- diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
- index 7f83ed51d..f70b92555 100644
- --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
- +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
- @@ -47,7 +47,7 @@ public class ChunkProviderServer implements IChunkProvider {
- this.world = worldserver;
- this.chunkLoader = ichunkloader;
- this.chunkGenerator = chunkgenerator;
- - this.f = new ChunkTaskScheduler(0, worldserver, chunkgenerator, ichunkloader, iasynctaskhandler); // CraftBukkit - very buggy, broken in lots of __subtle__ ways. Same goes for async chunk loading. Also Bukkit API / plugins can't handle async events at all anyway.
- + this.f = new ChunkTaskScheduler(2, worldserver, chunkgenerator, ichunkloader, iasynctaskhandler); // CraftBukkit - very buggy, broken in lots of __subtle__ ways. Same goes for async chunk loading. Also Bukkit API / plugins can't handle async events at all anyway. // Paper
- this.g = new SchedulerBatch(this.f);
- }
- @@ -108,12 +108,38 @@ public class ChunkProviderServer implements IChunkProvider {
- @Nullable
- public Chunk getOrLoadChunkAt(int i, int j) {
- - Long2ObjectMap long2objectmap = this.chunks;
- -
- - synchronized (this.chunks) {
- + // Paper start
- + return getOrLoadChunkAt(i, j, null);
- + }
- + public Chunk getOrLoadChunkAtOrig(int i, int j, Runnable runnable) {
- + synchronized (this.chunkLoader) {
- + Chunk chunk = getChunkIfLoaded(i, j);
- + return chunk != null ? chunk : loadChunkAt(i, j);
- + }
- + }
- + public Chunk getOrLoadChunkAt(int i, int j, Runnable runnable) {
- + synchronized (this.chunkLoader) {
- Chunk chunk = world.paperConfig.allowPermaChunkLoaders ? getLoadedChunkAt(i, j) : getChunkIfLoaded(i, j); // Paper - Configurable perma chunk loaders
- -
- - return chunk != null ? chunk : this.loadChunkAt(i, j);
- + if (!this.chunkLoader.chunkExists(i, j)) {
- + return null;
- + }
- + long key = ChunkCoordIntPair.asLong(i, j);
- + CompletableFuture<Chunk> pending = pendingGenerates.get(key);
- + if (pending != null) {
- + return null; // get getChunkAt handle it
- + }
- + if (chunk == null && runnable != null) {
- + ChunkIOExecutor.queueChunkLoad(world, (ChunkRegionLoader) this.chunkLoader, this, i, j, runnable);
- + return null;
- + }
- + if (chunk == null) {
- + chunk = ChunkIOExecutor.syncChunkLoad(world, (ChunkRegionLoader) chunkLoader, this, i, j);
- + }
- + if (chunk != null && runnable != null) {
- + runnable.run();
- + }
- + return chunk;
- + // Paper end
- }
- }
- @@ -123,21 +149,67 @@ public class ChunkProviderServer implements IChunkProvider {
- }
- // CraftBukkit end
- + // Paper sart
- + private final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<CompletableFuture<Chunk>> pendingGenerates = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
- + public CompletableFuture<Chunk> generateChunk(int i, int j) { // Incase something else calls this
- + return generateChunk(i, j, null);
- + }
- +
- + private CompletableFuture<Chunk> postChunkgenMain(ProtoChunk proto) {
- + CompletableFuture<Chunk> pending = new CompletableFuture<>();
- + MCUtil.ensureMain(() -> {
- + try {
- + pending.complete(this.finishChunkgen(proto));
- + } catch (Exception e) {
- + pending.completeExceptionally(e);
- + }
- + });
- + return pending;
- + }
- + public synchronized CompletableFuture<Chunk> generateChunk(int i, int j, Consumer<Chunk> consumer) {
- + long key = ChunkCoordIntPair.asLong(i, j);
- + CompletableFuture<Chunk> pending = pendingGenerates.get(key);
- + if (pending == null) {
- + pending = this.generateChunk0(i, j);
- + pendingGenerates.put(key, pending);
- + pending.thenAccept(unused -> {
- + synchronized (pendingGenerates) {
- + pendingGenerates.remove(key);
- + }
- + });
- + }
- +
- + if (consumer != null) {
- + pending.thenAccept(chunk -> MCUtil.ensureMain(() -> consumer.accept(chunk)));
- + }
- + return pending;
- + }
- +
- public Chunk getChunkAt(int i, int j) {
- - Chunk chunk = this.getOrLoadChunkAt(i, j);
- + return getChunkAt(i, j, null, true);
- + }
- + public Chunk getChunkAt(int i, int j, Runnable runnable) {
- + return getChunkAt(i, j, runnable, true);
- + }
- + public Chunk getChunkAt(int i, int j, Runnable runnable, boolean generate) {
- + // Paper end
- + Chunk chunk = this.getOrLoadChunkAt(i, j, runnable);
- if (chunk != null) {
- return chunk;
- - } else {
- + } else if (generate) { // Paper
- try {
- world.timings.syncChunkLoadTimer.startTiming(); // Spigot
- - chunk = (Chunk) this.generateChunk(i, j).get();
- - return chunk;
- - } catch (ExecutionException | InterruptedException interruptedexception) {
- + // Paper start
- + CompletableFuture<Chunk> pending = generateChunk(i, j, runnable != null ? unused -> runnable.run() : null);
- + return runnable != null ? null : MCUtil.processQueueWhileWaiting(pending);
- + } catch (Exception interruptedexception) {
- + // Paper end
- throw this.a(i, j, (Throwable) interruptedexception);
- }
- finally { world.timings.syncChunkLoadTimer.stopTiming(); } // Spigot
- }
- + return null; // Paper
- }
- public IChunkAccess d(int i, int j) {
- @@ -161,19 +233,23 @@ public class ChunkProviderServer implements IChunkProvider {
- if (chunk != null) {
- consumer.accept(chunk);
- } else {
- - this.g.a(chunkcoordintpair).thenApply(this::a).thenAccept(consumer);
- + this.g.a(chunkcoordintpair).thenApply(proto -> postChunkgenMain(proto).thenAccept(consumer)); // Paper
- }
- }
- return this.g.c();
- }
- - public CompletableFuture<Chunk> generateChunk(int i, int j) {
- + private CompletableFuture<Chunk> generateChunk0(int i, int j) { // Paper - make private, change name
- this.g.b();
- this.g.a(new ChunkCoordIntPair(i, j));
- CompletableFuture<ProtoChunk> completablefuture = this.g.c(); // CraftBukkit - decompile error
- - return completablefuture.thenApply(this::a);
- + // Paper start
- + CompletableFuture<Chunk> pending = new CompletableFuture<>();
- + completablefuture.thenApply(proto -> postChunkgenMain(proto).thenAccept(pending::complete));
- + return pending;
- + // Paper end
- }
- private ReportedException a(int i, int j, Throwable throwable) {
- @@ -186,7 +262,7 @@ public class ChunkProviderServer implements IChunkProvider {
- return new ReportedException(crashreport);
- }
- - private Chunk a(IChunkAccess ichunkaccess) {
- + private Chunk finishChunkgen(IChunkAccess ichunkaccess) { // Paper - rename method - Anything that accesses this should ensure it goes through process to ensure it is on main thread
- ChunkCoordIntPair chunkcoordintpair = ichunkaccess.getPos();
- int i = chunkcoordintpair.x;
- int j = chunkcoordintpair.z;
- diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
- index de2231bb0..ef4cdbcf5 100644
- --- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
- +++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
- @@ -62,15 +62,21 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
- }
- @Nullable
- - private synchronized NBTTagCompound a(GeneratorAccess generatoraccess, int i, int j) throws IOException {
- - NBTTagCompound nbttagcompound = SupplierUtils.getIfExists(this.b.get(new ChunkCoordIntPair(i, j))); // Spigot
- + // Paper start - remove synchronized, manually sync on the map
- + private NBTTagCompound a(GeneratorAccess generatoraccess, int i, int j) throws IOException {
- + Supplier<NBTTagCompound> supplier;
- + synchronized (this) {
- + supplier = this.b.get(new ChunkCoordIntPair(i, j));
- + }
- + NBTTagCompound nbttagcompound = SupplierUtils.getIfExists(supplier); // Spigot
- + // Paper end
- return nbttagcompound != null ? nbttagcompound : this.b(generatoraccess, i, j);
- }
- // CraftBukkit start
- private boolean check(ChunkProviderServer cps, int x, int z) throws IOException {
- - com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread");
- + //com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); // Paper
- if (cps.isLoaded(x, z)) {
- return true;
- @@ -162,7 +168,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
- return null;
- }
- - public synchronized Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException {
- + public Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException { // Paper - remove synchronize
- // CraftBukkit end
- NBTTagCompound nbttagcompound = this.a(generatoraccess, i, j);
- diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
- index fcd9f5491..04939db83 100644
- --- a/src/main/java/net/minecraft/server/PlayerChunk.java
- +++ b/src/main/java/net/minecraft/server/PlayerChunk.java
- @@ -32,7 +32,7 @@ public class PlayerChunk {
- private boolean loadInProgress = false;
- private Runnable loadedRunnable = new Runnable() {
- public void run() {
- - loadInProgress = false;
- + loadInProgress = false; // Paper
- PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(location.x, location.z);
- markChunkUsed(); // Paper - delay chunk unloads
- }
- @@ -49,7 +49,8 @@ public class PlayerChunk {
- public PlayerChunk(PlayerChunkMap playerchunkmap, int i, int j) {
- this.playerChunkMap = playerchunkmap;
- this.location = new ChunkCoordIntPair(i, j);
- - this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getOrLoadChunkAt(i, j);
- + loadInProgress = true;
- + this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getOrLoadChunkAt(i, j, loadedRunnable); // Paper
- this.chunkExists = this.chunk != null || ChunkIOExecutor.hasQueuedChunkLoad(playerChunkMap.getWorld(), i, j); // Paper
- markChunkUsed(); // Paper - delay chunk unloads
- }
- @@ -82,6 +83,7 @@ public class PlayerChunk {
- this.c.remove(entityplayer);
- if (this.c.isEmpty()) {
- + if (!this.done) ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.getWorld(), this.location.x, this.location.z, this.loadedRunnable); // Paper
- this.playerChunkMap.b(this);
- }
- @@ -92,12 +94,14 @@ public class PlayerChunk {
- if (this.chunk != null) {
- return true;
- } else {
- - if (flag) {
- - this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z);
- - } else {
- - this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(this.location.x, this.location.z);
- + // Paper start
- + if (!loadInProgress) {
- + loadInProgress = true;
- + this.chunk = playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, loadedRunnable, flag);
- markChunkUsed(); // Paper - delay chunk unloads
- }
- + // Paper end
- +
- return this.chunk != null;
- }
- diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
- index 995e02f1d..a3e5c9830 100644
- --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
- +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
- @@ -159,13 +159,7 @@ public class CraftWorld implements World {
- // Paper start - Async chunk load API
- public void getChunkAtAsync(final int x, final int z, final ChunkLoadCallback callback) {
- final ChunkProviderServer cps = this.world.getChunkProviderServer();
- - callback.onLoad(cps.getChunkAt(x, z).bukkitChunk); // TODO: Add back async variant
- - /*cps.getChunkAt(x, z, new Runnable() {
- - @Override
- - public void run() {
- - callback.onLoad(cps.getChunkAt(x, z).bukkitChunk);
- - }
- - });*/
- + cps.getChunkAt(x, z, () -> callback.onLoad(cps.getChunkAt(x, z).bukkitChunk));
- }
- public void getChunkAtAsync(Block block, ChunkLoadCallback callback) {
- @@ -266,7 +260,7 @@ public class CraftWorld implements World {
- net.minecraft.server.Chunk chunk = null;
- - chunk = Futures.getUnchecked(world.getChunkProviderServer().generateChunk(x, z));
- + chunk = MCUtil.processQueueWhileWaiting(world.getChunkProviderServer().generateChunk(x, z)); // Paper
- PlayerChunk playerChunk = world.getPlayerChunkMap().getChunk(x, z);
- if (playerChunk != null) {
- playerChunk.chunk = chunk;
- diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
- index 2bbd5a7e2..0b833ccae 100644
- --- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
- +++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
- @@ -6,11 +6,15 @@ import co.aikar.timings.Timing;
- import net.minecraft.server.Chunk;
- import net.minecraft.server.ChunkCoordIntPair;
- import net.minecraft.server.ChunkRegionLoader;
- +import net.minecraft.server.MCUtil;
- +import net.minecraft.server.MinecraftServer;
- import net.minecraft.server.NBTTagCompound;
- import org.bukkit.Server;
- import org.bukkit.craftbukkit.util.AsynchronousExecutor;
- +import java.util.concurrent.CompletableFuture;
- +import java.util.concurrent.ExecutionException;
- import java.util.concurrent.atomic.AtomicInteger;
- class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChunk, Chunk, Runnable, RuntimeException> {
- @@ -21,13 +25,23 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
- try (Timing ignored = queuedChunk.provider.world.timings.chunkIOStage1.startTimingIfSync()) { // Paper
- ChunkRegionLoader loader = queuedChunk.loader;
- Object[] data = loader.loadChunk(queuedChunk.world, queuedChunk.x, queuedChunk.z, (chunk) -> {});
- -
- +
- if (data != null) {
- queuedChunk.compound = (NBTTagCompound) data[1];
- return (Chunk) data[0];
- + } else {
- + // Paper start
- + CompletableFuture<Chunk> chunkReady = new CompletableFuture<>();
- + MCUtil.ensureMain(() -> {
- + try {
- + queuedChunk.provider.generateChunk(queuedChunk.x, queuedChunk.z, chunkReady::complete);
- + } catch (Exception e) {
- + chunkReady.completeExceptionally(e);
- + }
- + });
- + return MCUtil.processQueueWhileWaiting(chunkReady);
- + // Paper end
- }
- -
- - return null;
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
Add Comment
Please, Sign In to add comment