[CI-SKIP] Move removed patches back down a level

We shouldn't ever be dropping API anyways.
Dropped Async Chunk load v1 since its useless now
Added scheduler decompile fixes incase we do end up needing them
This commit is contained in:
Aikar 2018-09-01 15:38:34 -04:00
parent a5dc62d4b7
commit 5599e43ca4
No known key found for this signature in database
GPG Key ID: 401ADFC9891FAAFE
11 changed files with 75 additions and 564 deletions

View File

@ -0,0 +1,75 @@
From 5b7fa8b79798a56e956c7b5011c3298bc0de2a3c Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 1 Sep 2018 12:19:19 -0400
Subject: [PATCH 1/2] scheduler decompile fox
---
.../java/net/minecraft/server/Scheduler.java | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/main/java/net/minecraft/server/Scheduler.java b/src/main/java/net/minecraft/server/Scheduler.java
index ed155c8b30..1c327c58e7 100644
--- a/src/main/java/net/minecraft/server/Scheduler.java
+++ b/src/main/java/net/minecraft/server/Scheduler.java
@@ -27,8 +27,8 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
private final ExecutorService c;
private final AtomicInteger d = new AtomicInteger(1);
private final List<CompletableFuture<R>> e = Lists.newArrayList();
- private CompletableFuture<R> f = CompletableFuture.completedFuture((Object)null);
- private CompletableFuture<R> g = CompletableFuture.completedFuture((Object)null);
+ private CompletableFuture<R> f = CompletableFuture.completedFuture(null); // Paper - decompile fix
+ private CompletableFuture<R> g = CompletableFuture.completedFuture(null); // Paper - decompile fix
private final Supplier<Map<T, CompletableFuture<R>>> h;
private final Supplier<Map<T, CompletableFuture<Void>>> i;
private final T j;
@@ -121,12 +121,12 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
private final K c;
private final R d;
- public a(Object object, Object object1, SchedulerTask schedulertask) {
+ public a(Object object, Object object1, T schedulertask) { // Paper - decompile fix
this.b = (Map)Scheduler.this.h.get();
this.c = (K)object;
for(this.d = (R)object1; schedulertask != null; schedulertask = schedulertask.a()) {
- this.b.put(schedulertask, CompletableFuture.completedFuture(object1));
+ this.b.put(schedulertask, CompletableFuture.completedFuture((R)object1));// Paper - decompile fix
}
}
@@ -136,18 +136,18 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
}
private CompletableFuture<R> a(CompletableFuture<R> completablefuture, T schedulertask) {
- ConcurrentHashMap concurrenthashmap = new ConcurrentHashMap();
- return (CompletableFuture)this.b.computeIfAbsent(schedulertask, (var4) -> {
+ ConcurrentHashMap<K, CompletableFuture<R>> concurrenthashmap = new ConcurrentHashMap(); // Paper - decompile fix
+ return (CompletableFuture<R>)this.b.computeIfAbsent(schedulertask, (var4) -> { // Paper - decompile fix
if (schedulertask.a() == null) {
return CompletableFuture.completedFuture(this.d);
} else {
schedulertask.a(this.c, (object, schedulertask2) -> {
- CompletableFuture completablefuture4 = (CompletableFuture)concurrenthashmap.put(object, Scheduler.this.a(object, Scheduler.this.b(object)).a(completablefuture, schedulertask2));
+ CompletableFuture<R> completablefuture4 = (CompletableFuture)concurrenthashmap.put(object, Scheduler.this.a(object, Scheduler.this.b(object)).a(completablefuture, schedulertask2)); // Paper - decompile fix
});
- CompletableFuture[] acompletablefuture = (CompletableFuture[])Streams.concat(new Stream[]{Stream.of(completablefuture), concurrenthashmap.values().stream()}).toArray((i) -> {
+ CompletableFuture<R>[] acompletablefuture = (CompletableFuture[])Streams.concat(new Stream[]{Stream.of(completablefuture), concurrenthashmap.values().stream()}).toArray((i) -> { // Paper - decompile fix
return new CompletableFuture[i];
});
- CompletableFuture completablefuture2 = CompletableFuture.allOf(acompletablefuture).thenApplyAsync((var3) -> {
+ CompletableFuture<R> completablefuture2 = CompletableFuture.allOf(acompletablefuture).thenApplyAsync((var3) -> { // Paper - decompile fix
return Scheduler.this.a(this.c, schedulertask, Maps.transformValues(concurrenthashmap, (completablefuture3) -> {
try {
return completablefuture3.get();
@@ -156,7 +156,7 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
}
}));
}, Scheduler.this.c).thenApplyAsync((object) -> {
- for(Object object1 : concurrenthashmap.keySet()) {
+ for(K object1 : concurrenthashmap.keySet()) { // Paper - decompile fix
Scheduler.this.b(object1, Scheduler.this.b(object1));
}
--
2.18.0

View File

@ -1,564 +0,0 @@
From c47e8c9505057b7a6f429a5c36065be1c783cfda Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 26 Jul 2018 01:28:00 -0400
Subject: [PATCH] Async Chunk Load
Current unfinished, not working progress
---
.../minecraft/server/ChunkProviderServer.java | 118 +++++++++++++++---
.../minecraft/server/ChunkRegionLoader.java | 14 ++-
.../java/net/minecraft/server/MCUtil.java | 35 ++++--
.../net/minecraft/server/MinecraftServer.java | 1 +
.../net/minecraft/server/PlayerChunk.java | 14 ++-
.../org/bukkit/craftbukkit/CraftWorld.java | 10 +-
.../craftbukkit/chunkio/ChunkIOProvider.java | 42 +++++--
.../craftbukkit/chunkio/QueuedChunk.java | 8 ++
.../util/AsynchronousExecutor.java | 6 +-
9 files changed, 191 insertions(+), 57 deletions(-)
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 0e0c7b1abe..e72f43e2c8 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -108,13 +108,33 @@ public class ChunkProviderServer implements IChunkProvider {
@Nullable
public Chunk getOrLoadChunkAt(int i, int j) {
- Long2ObjectMap long2objectmap = this.chunks;
-
- synchronized (this.chunks) {
- Chunk chunk = world.paperConfig.allowPermaChunkLoaders ? getLoadedChunkAt(i, j) : getChunkIfLoaded(i, j); // Paper - Configurable perma chunk loaders
+ // Paper start
+ return getOrLoadChunkAt(i, j, null);
+ }
+ public Chunk getOrLoadChunkAt(int i, int j, Runnable runnable) {
+ // Paper - remove synchronized
+ Chunk chunk = world.paperConfig.allowPermaChunkLoaders ? getLoadedChunkAt(i, j) : getChunkIfLoaded(i, j); // Paper - Configurable perma chunk loaders
+ if (!this.chunkLoader.chunkExists(i, j)) {
+ return null;
+ }
+ long key = ChunkCoordIntPair.asLong(i, j);
+ synchronized (pendingGenerates) {
+ if (pendingGenerates.containsKey(key)) {
+ return null; // let getChunkAt handle it
+ }
+ }
- return chunk != null ? chunk : this.loadChunkAt(i, j);
+ 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;
}
// CraftBukkit start
@@ -123,20 +143,74 @@ 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.ensureChunkMain(() -> {
+ try {
+ pending.complete(this.finishChunkgen(proto));
+ } catch (Exception e) {
+ pending.completeExceptionally(e);
+ }
+ });
+ return pending;
+ }
+ public CompletableFuture<Chunk> generateChunk(int i, int j, Consumer<Chunk> consumer) {
+ long key = ChunkCoordIntPair.asLong(i, j);
+ CompletableFuture<Chunk> pending;
+ boolean generate = false;
+ synchronized (pendingGenerates) {
+ pending = pendingGenerates.get(key);
+ if (pending == null) {
+ pending = new CompletableFuture<>();
+ pendingGenerates.put(key, pending);
+ generate = true;
+ }
+ }
+ if (generate) {
+ this.generateChunk0(i, j).thenApply(chunk -> {
+ synchronized (pendingGenerates) {
+ pendingGenerates.remove(key);
+ }
+ return chunk;
+ }).thenAccept(pending::complete);
+ }
+
+ 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
+ //calling into self and blocking?
+ Chunk chunk = this.getOrLoadChunkAt(i, j, runnable);
if (chunk != null) {
return chunk;
- } else {
+ } else if (generate) {
try (co.aikar.timings.Timing timing = world.timings.chunkGeneration.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.processChunkQueueWhileWaiting(pending);
+ } catch (Exception interruptedexception) {
+ // Paper end
throw this.a(i, j, (Throwable) interruptedexception);
}
}
+ return null; // Paper
}
public IChunkAccess d(int i, int j) {
@@ -160,7 +234,7 @@ 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
}
}
@@ -168,11 +242,13 @@ public class ChunkProviderServer implements IChunkProvider {
}
// CraftBukkit start
- public CompletableFuture<Chunk> generateChunk(int i, int j) {
- return this.generateChunk(i, j, false);
+ // Paper start - change name, make private
+ private CompletableFuture<Chunk> generateChunk0(int i, int j) {
+ return this.generateChunk0(i, j, false);
}
- public CompletableFuture<Chunk> generateChunk(int i, int j, boolean force) {
+ private CompletableFuture<Chunk> generateChunk0(int i, int j, boolean force) {
+ // Paper end
this.g.b();
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
@@ -183,7 +259,11 @@ public class ChunkProviderServer implements IChunkProvider {
// CraftBukkit end
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) {
@@ -196,7 +276,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;
@@ -204,7 +284,7 @@ public class ChunkProviderServer implements IChunkProvider {
Long2ObjectMap long2objectmap = this.chunks;
Chunk chunk;
- synchronized (this.chunks) {
+ //synchronized (this.chunks) { // Paper
Chunk chunk1 = (Chunk) this.chunks.get(k);
if (chunk1 != null) {
@@ -222,7 +302,7 @@ public class ChunkProviderServer implements IChunkProvider {
}
this.chunks.put(k, chunk);
- }
+ //} // Paper
chunk.addEntities();
return chunk;
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index bd52bf6561..e4447ecf58 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -62,8 +62,14 @@ 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.a(generatoraccess.o().getDimensionManager(), generatoraccess.s_(), i, j, generatoraccess); // CraftBukkit
}
@@ -71,7 +77,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
// CraftBukkit start
private boolean check(ChunkProviderServer cps, int x, int z) throws IOException {
if (cps != null) {
- 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/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
index 80927de08b..d936709b47 100644
--- a/src/main/java/net/minecraft/server/MCUtil.java
+++ b/src/main/java/net/minecraft/server/MCUtil.java
@@ -7,6 +7,7 @@ import com.mojang.authlib.GameProfile;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
import org.bukkit.craftbukkit.util.Waitable;
import org.spigotmc.AsyncCatcher;
@@ -14,13 +15,13 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
-import java.util.regex.Pattern;
public final class MCUtil {
private static final Executor asyncExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Paper Async Task Handler Thread - %1$d").build());
@@ -76,10 +77,14 @@ public final class MCUtil {
MinecraftServer.getServer().postToMainThread(new DelayedRunnable(ticks, runnable));
}
- public static void processQueue() {
+
+ private static final Queue<Runnable> chunkMainQueue = new ConcurrentLinkedQueue<>();
+ public static void processChunkMainQueue() {
+ if (!isMainThread()) {
+ return;
+ }
Runnable runnable;
- Queue<Runnable> processQueue = getProcessQueue();
- while ((runnable = processQueue.poll()) != null) {
+ while ((runnable = chunkMainQueue.poll()) != null) {
try {
runnable.run();
} catch (Exception e) {
@@ -87,14 +92,15 @@ public final class MCUtil {
}
}
}
- public static <T> T processQueueWhileWaiting(CompletableFuture <T> future) {
+ public static <T> T processChunkQueueWhileWaiting(CompletableFuture <T> future) {
try {
if (isMainThread()) {
while (!future.isDone()) {
try {
- return future.get(1, TimeUnit.MILLISECONDS);
+ return future.get(10000, TimeUnit.NANOSECONDS);
} catch (TimeoutException ignored) {
- processQueue();
+ processChunkMainQueue();
+ ChunkIOExecutor.tick();
}
}
}
@@ -103,6 +109,13 @@ public final class MCUtil {
throw new RuntimeException(e);
}
}
+ public static void ensureChunkMain(Runnable run) {
+ if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().primaryThread) {
+ chunkMainQueue.add(run);
+ } else {
+ run.run();
+ }
+ }
public static void ensureMain(Runnable run) {
ensureMain(null, run);
@@ -118,16 +131,12 @@ public final class MCUtil {
if (reason != null) {
new IllegalStateException("Asynchronous " + reason + "!").printStackTrace();
}
- getProcessQueue().add(run);
+ MinecraftServer.getServer().processQueue.add(run);
return;
}
run.run();
}
- private static Queue<Runnable> getProcessQueue() {
- return MinecraftServer.getServer().processQueue;
- }
-
public static <T> T ensureMain(Supplier<T> run) {
return ensureMain(null, run);
}
@@ -149,7 +158,7 @@ public final class MCUtil {
return run.get();
}
};
- getProcessQueue().add(wait);
+ MinecraftServer.getServer().processQueue.add(wait);
try {
return wait.get();
} catch (InterruptedException | ExecutionException e) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 90b1871196..390ecb4093 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -996,6 +996,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
// CraftBukkit start
// Run tasks that are waiting on processing
MinecraftTimings.processQueueTimer.startTiming(); // Spigot
+ MCUtil.processChunkMainQueue(); // Paper
while (!processQueue.isEmpty()) {
processQueue.remove().run();
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index fcd9f5491f..4c67e7d0cf 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -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; // Paper
+ 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 f4dc7e4ac6..c1324515af 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, true));
+ chunk = MCUtil.processChunkQueueWhileWaiting(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 2bbd5a7e2a..40b86c4334 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,21 @@ 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> pending = new CompletableFuture<>();
+ MCUtil.ensureChunkMain(() -> {
+ System.out.println("GENERATING SEMI ASYNC" + queuedChunk);
+ queuedChunk.provider.generateChunk(queuedChunk.x, queuedChunk.z).thenApply(pending::complete);
+ });
+ MCUtil.processChunkQueueWhileWaiting(pending);
+ return null; // We still need to return null so the code below doesn't use result which is already in the world now
+ // Paper end
}
-
- return null;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
@@ -35,12 +47,28 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
// sync stuff
public void callStage2(QueuedChunk queuedChunk, Chunk chunk) throws RuntimeException {
- if (chunk == null || queuedChunk.provider.chunks.containsKey(ChunkCoordIntPair.a(queuedChunk.x, queuedChunk.z))) { // Paper - also call original if it was already loaded
- // If the chunk loading failed just do it synchronously (may generate)
- queuedChunk.provider.getChunkAt(queuedChunk.x, queuedChunk.z); // Paper - actually call original if it was already loaded
+ try (Timing ignored = queuedChunk.provider.world.timings.chunkIOStage2.startTimingIfSync()) { // Paper
+ if (queuedChunk.provider.chunks.containsKey(ChunkCoordIntPair.a(queuedChunk.x, queuedChunk.z))) { // Paper - also call original if it was already loaded
return;
+ } else if (chunk == null) {
+ // Retry the load
+ ChunkRegionLoader loader = queuedChunk.loader;
+ try {
+ Object[] data = loader.loadChunk(queuedChunk.world, queuedChunk.x, queuedChunk.z, unused -> {});
+ if (data != null && data[0] != null) {
+ System.out.println("LOADED AFTER NULL" + queuedChunk);
+ queuedChunk.compound = (NBTTagCompound) data[1];
+ chunk = (Chunk) data[0];
+ } else {
+ System.out.println("GENERATING" + queuedChunk);
+ // Ok failed again, generate
+ MCUtil.processChunkQueueWhileWaiting(queuedChunk.provider.generateChunk(queuedChunk.x, queuedChunk.z, null));
+ return;
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
}
- try (Timing ignored = queuedChunk.provider.world.timings.chunkIOStage2.startTimingIfSync()) { // Paper
queuedChunk.loader.loadEntities(queuedChunk.compound.getCompound("Level"), chunk);
chunk.setLastSaved(queuedChunk.provider.world.getTime());
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java b/src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java
index 842d424f6a..c8f4db79f7 100644
--- a/src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java
@@ -35,4 +35,12 @@ class QueuedChunk {
return false;
}
+
+ @Override
+ public String toString() {
+ return "QueuedChunk{" +
+ "x=" + x +
+ ", z=" + z +
+ '}';
+ }
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/AsynchronousExecutor.java b/src/main/java/org/bukkit/craftbukkit/util/AsynchronousExecutor.java
index cf1258c559..b18c27060e 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/AsynchronousExecutor.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/AsynchronousExecutor.java
@@ -10,8 +10,10 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import net.minecraft.server.MCUtil;
import org.apache.commons.lang.Validate;
/**
@@ -129,7 +131,8 @@ public final class AsynchronousExecutor<P, T, C, E extends Throwable> {
// We are the first into the lock
while (state != STAGE_1_COMPLETE) {
try {
- this.wait();
+ this.wait(0, 10000); // Paper
+ MCUtil.processChunkMainQueue(); // Paper
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Unable to handle interruption on " + parameter, e);
@@ -185,6 +188,7 @@ public final class AsynchronousExecutor<P, T, C, E extends Throwable> {
final P parameter = this.parameter;
final T object = this.object;
+ MCUtil.processChunkMainQueue(); // We may have an async chunk gen ready to be added to main first
provider.callStage2(parameter, object);
for (C callback : callbacks) {
if (callback == this) {
--
2.18.0