mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-23 02:55:47 +01:00
[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:
parent
a5dc62d4b7
commit
5599e43ca4
75
removed/Scheduler-decompile-fixes.patch
Normal file
75
removed/Scheduler-decompile-fixes.patch
Normal 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
|
||||||
|
|
@ -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
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user