Update leaf's asynch chunk io patch

This commit is contained in:
William Blake Galbreath
2019-07-13 18:37:16 -05:00
parent 5cbe985984
commit 031c21038d
4 changed files with 1140 additions and 498 deletions

View File

@@ -1,244 +0,0 @@
From d7a653379c6a6446a42907cd03e9d1348844f893 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 8 Jul 2019 03:24:59 -0700
Subject: [PATCH] Asynchronous chunk loading api
---
.../minecraft/server/ChunkProviderServer.java | 134 ++++++++++++++++++
.../net/minecraft/server/ChunkStatus.java | 1 +
.../java/net/minecraft/server/MCUtil.java | 5 +
.../java/net/minecraft/server/RegionFile.java | 2 +-
.../java/net/minecraft/server/TicketType.java | 1 +
.../org/bukkit/craftbukkit/CraftWorld.java | 19 +--
6 files changed, 152 insertions(+), 10 deletions(-)
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index db9113994e..b46285ecdc 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -147,6 +147,140 @@ public class ChunkProviderServer extends IChunkProvider {
return playerChunk.getAvailableChunkNow();
}
+
+ private long asyncLoadSeqCounter;
+
+ public void getChunkAtAsynchronously(int x, int z, boolean gen, java.util.function.Consumer<Chunk> onComplete) {
+ if (Thread.currentThread() != this.serverThread) {
+ this.serverThreadQueue.execute(() -> {
+ this.getChunkAtAsynchronously(x, z, gen, onComplete);
+ });
+ return;
+ }
+
+ long k = ChunkCoordIntPair.pair(x, z);
+ ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(x, z);
+
+ IChunkAccess ichunkaccess;
+
+ // try cache
+ for (int l = 0; l < 4; ++l) {
+ if (k == this.cachePos[l] && ChunkStatus.FULL == this.cacheStatus[l]) {
+ ichunkaccess = this.cacheChunk[l];
+ if (ichunkaccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime
+
+ // move to first in cache
+
+ for (int i1 = 3; i1 > 0; --i1) {
+ this.cachePos[i1] = this.cachePos[i1 - 1];
+ this.cacheStatus[i1] = this.cacheStatus[i1 - 1];
+ this.cacheChunk[i1] = this.cacheChunk[i1 - 1];
+ }
+
+ this.cachePos[0] = k;
+ this.cacheStatus[0] = ChunkStatus.FULL;
+ this.cacheChunk[0] = ichunkaccess;
+
+ onComplete.accept((Chunk)ichunkaccess);
+
+ return;
+ }
+ }
+ }
+
+ if (gen) {
+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete);
+ return;
+ }
+
+ IChunkAccess current = this.getChunkAtImmediately(x, z); // we want to bypass ticket restrictions
+ if (current != null) {
+ if (!(current instanceof ProtoChunkExtension) && !(current instanceof net.minecraft.server.Chunk)) {
+ onComplete.accept(null); // the chunk is not gen'd
+ return;
+ }
+ // we know the chunk is at full status here (either in read-only mode or the real thing)
+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete);
+ return;
+ } else {
+ RegionFile file;
+
+ try {
+ file = this.world.getChunkProvider().playerChunkMap.getRegionFile(chunkPos, false);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ ChunkStatus status;
+ if (!file.chunkExists(chunkPos) || ((status = file.getStatusIfCached(x, z)) != null && status != ChunkStatus.FULL)) {
+ onComplete.accept(null); // cached status says not generated, or data does not exist on disk
+ return;
+ }
+
+
+ if (status == ChunkStatus.FULL) {
+ // at this stage we know it is fully generated, but is on disk
+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete);
+ return;
+ }
+
+ // at this stage we don't know what status the chunk is in
+ }
+
+ // here we don't know what status it is and we're not supposed to generate
+ // so we asynchronously load empty status
+
+ this.bringToStatusAsync(x, z, chunkPos, ChunkStatus.EMPTY, (IChunkAccess chunk) -> {
+ if (!(chunk instanceof ProtoChunkExtension) && !(chunk instanceof net.minecraft.server.Chunk)) {
+ // the chunk on disk was not a full status chunk
+ onComplete.accept(null);
+ return;
+ }
+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete); // bring to full status if required
+ });
+ }
+
+ private void bringToFullStatusAsync(int x, int z, ChunkCoordIntPair chunkPos, java.util.function.Consumer<Chunk> onComplete) {
+ this.bringToStatusAsync(x, z, chunkPos, ChunkStatus.FULL, (java.util.function.Consumer)onComplete);
+ }
+
+
+ private void bringToStatusAsync(int x, int z, ChunkCoordIntPair chunkPos, ChunkStatus status, java.util.function.Consumer<IChunkAccess> onComplete) {
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> future = this.getChunkFutureMainThread(x, z, status, true);
+ long identifier = this.asyncLoadSeqCounter++;
+ int ticketLevel = MCUtil.getTicketLevelFor(status);
+ this.addTicketAtLevel(TicketType.ASYNC_LOAD, chunkPos, ticketLevel, identifier);
+
+ future.whenCompleteAsync((Either<IChunkAccess, PlayerChunk.Failure> either, Throwable throwable) -> {
+ // either left -> success
+ // either right -> failure
+
+ if (throwable != null) {
+ throw new RuntimeException(throwable);
+ }
+
+ this.removeTicketAtLevel(TicketType.ASYNC_LOAD, chunkPos, ticketLevel, identifier);
+ this.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos); // allow unloading
+
+ Optional<PlayerChunk.Failure> failure = either.right();
+
+ if (failure.isPresent()) {
+ // failure
+ throw new IllegalStateException("Chunk failed to load: " + failure.get().toString());
+ }
+
+ onComplete.accept(either.left().get());
+
+ }, this.serverThreadQueue);
+ }
+
+ public <T> void addTicketAtLevel(TicketType<T> ticketType, ChunkCoordIntPair chunkPos, int ticketLevel, T identifier) {
+ this.chunkMapDistance.addTicketAtLevel(ticketType, chunkPos, ticketLevel, identifier);
+ }
+
+ public <T> void removeTicketAtLevel(TicketType<T> ticketType, ChunkCoordIntPair chunkPos, int ticketLevel, T identifier) {
+ this.chunkMapDistance.removeTicketAtLevel(ticketType, chunkPos, ticketLevel, identifier);
+ }
// Paper end
@Nullable
diff --git a/src/main/java/net/minecraft/server/ChunkStatus.java b/src/main/java/net/minecraft/server/ChunkStatus.java
index e324989b46..abb0d69d2f 100644
--- a/src/main/java/net/minecraft/server/ChunkStatus.java
+++ b/src/main/java/net/minecraft/server/ChunkStatus.java
@@ -153,6 +153,7 @@ public class ChunkStatus {
return ChunkStatus.q.size();
}
+ public static int getTicketLevelOffset(ChunkStatus status) { return ChunkStatus.a(status); } // Paper - OBFHELPER
public static int a(ChunkStatus chunkstatus) {
return ChunkStatus.r.getInt(chunkstatus.c());
}
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
index 23d1935dd5..14f8b61042 100644
--- a/src/main/java/net/minecraft/server/MCUtil.java
+++ b/src/main/java/net/minecraft/server/MCUtil.java
@@ -530,4 +530,9 @@ public final class MCUtil {
out.print(fileData);
}
}
+
+ public static int getTicketLevelFor(ChunkStatus status) {
+ // TODO make sure the constant `33` is correct on future updates. See getChunkAt(int, int, ChunkStatus, boolean)
+ return 33 + ChunkStatus.getTicketLevelOffset(status);
+ }
}
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
index 66c8b0307f..3e80f6c53e 100644
--- a/src/main/java/net/minecraft/server/RegionFile.java
+++ b/src/main/java/net/minecraft/server/RegionFile.java
@@ -310,7 +310,7 @@ public class RegionFile implements AutoCloseable {
return this.c[this.f(chunkcoordintpair)];
}
- public final boolean chunkExists(ChunkCoordIntPair chunkPos) { return this.d(chunkPos); } // Paper - OBFHELPER
+ public boolean chunkExists(ChunkCoordIntPair chunkPos) { return this.d(chunkPos); } // Paper - OBFHELPER
public boolean d(ChunkCoordIntPair chunkcoordintpair) {
return this.getOffset(chunkcoordintpair) != 0;
}
diff --git a/src/main/java/net/minecraft/server/TicketType.java b/src/main/java/net/minecraft/server/TicketType.java
index 5acb0732c3..0ed2d2fbf9 100644
--- a/src/main/java/net/minecraft/server/TicketType.java
+++ b/src/main/java/net/minecraft/server/TicketType.java
@@ -22,6 +22,7 @@ public class TicketType<T> {
public static final TicketType<Unit> PLUGIN = a("plugin", (a, b) -> 0); // CraftBukkit
public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = a("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // Craftbukkit
public static final TicketType<Integer> ANTIXRAY = a("antixray", Integer::compareTo); // Paper - Anti-Xray
+ public static final TicketType<Long> ASYNC_LOAD = a("async_load", Long::compareTo); // Paper
public static <T> TicketType<T> a(String s, Comparator<T> comparator) {
return new TicketType<>(s, comparator, 0L);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index c5321c5076..7691f23316 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -2323,16 +2323,17 @@ public class CraftWorld implements World {
@Override
public CompletableFuture<Chunk> getChunkAtAsync(int x, int z, boolean gen) {
- // TODO placeholder
- if (Bukkit.isPrimaryThread()) {
- return CompletableFuture.completedFuture(getChunkAtGen(x, z, gen));
- } else {
- CompletableFuture<Chunk> ret = new CompletableFuture<>();
- net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
- ret.complete(getChunkAtGen(x, z, gen));
- });
- return ret;
+ net.minecraft.server.Chunk immediate = this.world.getChunkProvider().getChunkAtIfLoadedImmediately(x, z);
+ if (immediate != null) {
+ return CompletableFuture.completedFuture(immediate.bukkitChunk);
}
+
+ CompletableFuture<Chunk> ret = new CompletableFuture<>();
+ this.world.getChunkProvider().getChunkAtAsynchronously(x, z, gen, (net.minecraft.server.Chunk chunk) -> {
+ ret.complete(chunk == null ? null : chunk.bukkitChunk);
+ });
+
+ return ret;
}
// Paper end
--
2.20.1

View File

@@ -1,4 +1,4 @@
From 854429ab6cd52dfd88f48b40206055b8790085f0 Mon Sep 17 00:00:00 2001 From 3ff085046cf1d3efc53b2dec884c4d5b75cd0df3 Mon Sep 17 00:00:00 2001
From: kickash32 <kickash32@gmail.com> From: kickash32 <kickash32@gmail.com>
Date: Tue, 11 Jun 2019 22:22:16 -0400 Date: Tue, 11 Jun 2019 22:22:16 -0400
Subject: [PATCH] Implement optional per player mob spawns Subject: [PATCH] Implement optional per player mob spawns
@@ -29,10 +29,10 @@ index ff520d9e86..5ed02f6485 100644
public boolean asynchronous; public boolean asynchronous;
public EngineMode engineMode; public EngineMode engineMode;
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index f6a6421140..770ee018fe 100644 index 4f7c442264..9f6c362dd1 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -586,9 +586,21 @@ public class ChunkProviderServer extends IChunkProvider { @@ -582,9 +582,21 @@ public class ChunkProviderServer extends IChunkProvider {
// Paper start - only allow spawns upto the limit per chunk and update count afterwards // Paper start - only allow spawns upto the limit per chunk and update count afterwards
int currEntityCount = object2intmap.getInt(enumcreaturetype); int currEntityCount = object2intmap.getInt(enumcreaturetype);
int difference = k1 - currEntityCount; int difference = k1 - currEntityCount;
@@ -57,7 +57,7 @@ index f6a6421140..770ee018fe 100644
} }
} }
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 6ca98b7ad5..56e60e0ce1 100644 index f25ca782b9..a235df4185 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -105,6 +105,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { @@ -105,6 +105,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -68,7 +68,7 @@ index 6ca98b7ad5..56e60e0ce1 100644
private static double a(ChunkCoordIntPair chunkcoordintpair, Entity entity) { private static double a(ChunkCoordIntPair chunkcoordintpair, Entity entity) {
double d0 = (double) (chunkcoordintpair.x * 16 + 8); double d0 = (double) (chunkcoordintpair.x * 16 + 8);
double d1 = (double) (chunkcoordintpair.z * 16 + 8); double d1 = (double) (chunkcoordintpair.z * 16 + 8);
@@ -1131,6 +1132,15 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { @@ -1157,6 +1158,15 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
} }
@@ -167,7 +167,7 @@ index af397dd1f7..5e001733a9 100644
@Nullable @Nullable
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index f0380c5df4..0c4fd5ca4d 100644 index f7597d499f..2410db3353 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java --- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -17,6 +17,9 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -17,6 +17,9 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
@@ -188,7 +188,7 @@ index f0380c5df4..0c4fd5ca4d 100644
// CraftBukkit start // CraftBukkit start
private int tickPosition; private int tickPosition;
@@ -930,6 +934,7 @@ public class WorldServer extends World { @@ -932,6 +936,7 @@ public class WorldServer extends World {
} }
public Object2IntMap<EnumCreatureType> l() { public Object2IntMap<EnumCreatureType> l() {
@@ -196,7 +196,7 @@ index f0380c5df4..0c4fd5ca4d 100644
Object2IntMap<EnumCreatureType> object2intmap = new Object2IntOpenHashMap(); Object2IntMap<EnumCreatureType> object2intmap = new Object2IntOpenHashMap();
ObjectIterator objectiterator = this.entitiesById.values().iterator(); ObjectIterator objectiterator = this.entitiesById.values().iterator();
@@ -957,13 +962,47 @@ public class WorldServer extends World { @@ -959,13 +964,47 @@ public class WorldServer extends World {
} }
// Paper end // Paper end
object2intmap.mergeInt(enumcreaturetype, 1, Integer::sum); object2intmap.mergeInt(enumcreaturetype, 1, Integer::sum);

View File

@@ -1,4 +1,4 @@
From 4c6e788cb3b1158e8955dccd8434939ebe1a026a Mon Sep 17 00:00:00 2001 From dc255f32785831cfa041105a377ea880926762f8 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com> From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Sat, 13 Jul 2019 15:56:22 -0500 Date: Sat, 13 Jul 2019 15:56:22 -0500
Subject: [PATCH] Tulips change fox type Subject: [PATCH] Tulips change fox type