mirror of
https://github.com/PaperMC/Paper.git
synced 2025-09-03 05:43:52 -07:00
Cancel pending chunk loads when they are no longer needed
This will improve queue times by canceling chunks when a player leaves the radius of an async loading/generating chunk. This matches behavior we had pre 1.13 for loading too.
This commit is contained in:
@@ -106,7 +106,7 @@ index 912c990404..2f6d7f2976 100644
|
|||||||
}
|
}
|
||||||
diff --git a/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java b/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java
|
diff --git a/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java b/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..0a9fd5d662
|
index 0000000000..5c77b6e8e1
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java
|
+++ b/src/main/java/com/destroystokyo/paper/util/PriorityQueuedExecutor.java
|
||||||
@@ -0,0 +0,0 @@
|
@@ -0,0 +0,0 @@
|
||||||
@@ -321,6 +321,10 @@ index 0000000000..0a9fd5d662
|
|||||||
+ this.run = run;
|
+ this.run = run;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ public boolean cancel() {
|
||||||
|
+ return hasRan.compareAndSet(false, true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ @Override
|
+ @Override
|
||||||
+ public void run() {
|
+ public void run() {
|
||||||
+ if (!hasRan.compareAndSet(false, true)) {
|
+ if (!hasRan.compareAndSet(false, true)) {
|
||||||
@@ -400,7 +404,7 @@ index 9162151e2a..15a327923f 100644
|
|||||||
|
|
||||||
Iterator iterator = protochunk.s().iterator();
|
Iterator iterator = protochunk.s().iterator();
|
||||||
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 5b57ea93c8..5d5834ba7f 100644
|
index 958a4084e6..56a76e17ef 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
|
||||||
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
|
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
|
||||||
@@ -460,6 +464,21 @@ index 5b57ea93c8..5d5834ba7f 100644
|
|||||||
+ }
|
+ }
|
||||||
+ return chunk;
|
+ return chunk;
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
|
+ PaperAsyncChunkProvider.CancellableChunkRequest requestChunk(int x, int z, boolean gen, boolean priority, Consumer<Chunk> consumer) {
|
||||||
|
+ Chunk chunk = getChunkAt(x, z, gen, priority, consumer);
|
||||||
|
+ return new PaperAsyncChunkProvider.CancellableChunkRequest() {
|
||||||
|
+ @Override
|
||||||
|
+ public void cancel() {
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public Chunk getChunk() {
|
||||||
|
+ return chunk;
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+ }
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
+
|
+
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -836,7 +855,7 @@ index 98d182fdb8..487d98eb1b 100644
|
|||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java
|
diff --git a/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..1c592c7956
|
index 0000000000..7fb95330fa
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java
|
+++ b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java
|
||||||
@@ -0,0 +0,0 @@
|
@@ -0,0 +0,0 @@
|
||||||
@@ -882,6 +901,8 @@ index 0000000000..1c592c7956
|
|||||||
+import java.util.List;
|
+import java.util.List;
|
||||||
+import java.util.concurrent.CompletableFuture;
|
+import java.util.concurrent.CompletableFuture;
|
||||||
+import java.util.concurrent.ConcurrentLinkedQueue;
|
+import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
+import java.util.concurrent.atomic.AtomicInteger;
|
||||||
+import java.util.function.Consumer;
|
+import java.util.function.Consumer;
|
||||||
+
|
+
|
||||||
+@SuppressWarnings("unused")
|
+@SuppressWarnings("unused")
|
||||||
@@ -976,6 +997,10 @@ index 0000000000..1c592c7956
|
|||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private Chunk loadOrGenerateChunk(int x, int z, boolean gen, boolean priority, Consumer<Chunk> consumer) {
|
+ private Chunk loadOrGenerateChunk(int x, int z, boolean gen, boolean priority, Consumer<Chunk> consumer) {
|
||||||
|
+ return requestChunk(x, z, gen, priority, consumer).getChunk();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ PendingChunkRequest requestChunk(int x, int z, boolean gen, boolean priority, Consumer<Chunk> consumer) {
|
||||||
+ final long key = ChunkCoordIntPair.asLong(x, z);
|
+ final long key = ChunkCoordIntPair.asLong(x, z);
|
||||||
+
|
+
|
||||||
+ // Obtain a PendingChunk
|
+ // Obtain a PendingChunk
|
||||||
@@ -983,7 +1008,6 @@ index 0000000000..1c592c7956
|
|||||||
+ final boolean isBlockingMain = consumer == null && server.isMainThread();
|
+ final boolean isBlockingMain = consumer == null && server.isMainThread();
|
||||||
+ synchronized (pendingChunks) {
|
+ synchronized (pendingChunks) {
|
||||||
+ PendingChunk pendingChunk = pendingChunks.get(key);
|
+ PendingChunk pendingChunk = pendingChunks.get(key);
|
||||||
+ // DO NOT CALL ANY METHODS ON PENDING CHUNK IN THIS BLOCK - WILL DEADLOCK
|
|
||||||
+ if (pendingChunk == null) {
|
+ if (pendingChunk == null) {
|
||||||
+ pending = new PendingChunk(x, z, key, gen, priority || isBlockingMain);
|
+ pending = new PendingChunk(x, z, key, gen, priority || isBlockingMain);
|
||||||
+ pendingChunks.put(key, pending);
|
+ pendingChunks.put(key, pending);
|
||||||
@@ -1000,11 +1024,12 @@ index 0000000000..1c592c7956
|
|||||||
+ }
|
+ }
|
||||||
+ // Listen for when result is ready
|
+ // Listen for when result is ready
|
||||||
+ final CompletableFuture<Chunk> future = new CompletableFuture<>();
|
+ final CompletableFuture<Chunk> future = new CompletableFuture<>();
|
||||||
+ pending.addListener(future, gen);
|
+ PendingChunkRequest request = pending.addListener(future, gen);
|
||||||
+
|
+
|
||||||
+ if (isBlockingMain && pending.hasFinished) {
|
+ if (isBlockingMain && pending.hasFinished) {
|
||||||
+ processChunkLoads();
|
+ processChunkLoads();
|
||||||
+ return pending.postChunk();
|
+ request.initialReturnChunk = pending.postChunk();
|
||||||
|
+ return request;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (isBlockingMain) {
|
+ if (isBlockingMain) {
|
||||||
@@ -1027,15 +1052,16 @@ index 0000000000..1c592c7956
|
|||||||
+ processChunkLoads();
|
+ processChunkLoads();
|
||||||
+ }
|
+ }
|
||||||
+ // We should be done AND posted into chunk map now, return it
|
+ // We should be done AND posted into chunk map now, return it
|
||||||
+ return future.join();
|
+ request.initialReturnChunk = future.join();
|
||||||
+ }
|
+ }
|
||||||
+ } else if (consumer == null) {
|
+ } else if (consumer == null) {
|
||||||
+ // This is on another thread
|
+ // This is on another thread
|
||||||
+ return future.join();
|
+ request.initialReturnChunk = future.join();
|
||||||
+ } else {
|
+ } else {
|
||||||
+ future.thenAccept((c) -> this.asyncHandler.postToMainThread(() -> consumer.accept(c)));
|
+ future.thenAccept((c) -> this.asyncHandler.postToMainThread(() -> consumer.accept(c)));
|
||||||
+ }
|
+ }
|
||||||
+ return null;
|
+
|
||||||
|
+ return request;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ @Override
|
+ @Override
|
||||||
@@ -1093,19 +1119,59 @@ index 0000000000..1c592c7956
|
|||||||
+ /**
|
+ /**
|
||||||
+ * Fully done with this request (may or may not of loaded)
|
+ * Fully done with this request (may or may not of loaded)
|
||||||
+ */
|
+ */
|
||||||
+ DONE
|
+ DONE,
|
||||||
|
+ /**
|
||||||
|
+ * Chunk load was cancelled (no longer needed)
|
||||||
|
+ */
|
||||||
|
+ CANCELLED
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public interface CancellableChunkRequest {
|
||||||
|
+ void cancel();
|
||||||
|
+ Chunk getChunk();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static class PendingChunkRequest implements CancellableChunkRequest {
|
||||||
|
+ private final PendingChunk pending;
|
||||||
|
+ private final AtomicBoolean cancelled = new AtomicBoolean(false);
|
||||||
|
+ private volatile boolean generating;
|
||||||
|
+ private volatile Chunk initialReturnChunk;
|
||||||
|
+
|
||||||
|
+ private PendingChunkRequest(PendingChunk pending) {
|
||||||
|
+ this.pending = pending;
|
||||||
|
+ this.cancelled.set(true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private PendingChunkRequest(PendingChunk pending, boolean gen) {
|
||||||
|
+ this.pending = pending;
|
||||||
|
+ this.generating = gen;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void cancel() {
|
||||||
|
+ this.pending.cancel(this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Will be null on asynchronous loads
|
||||||
|
+ */
|
||||||
|
+ @Override @Nullable
|
||||||
|
+ public Chunk getChunk() {
|
||||||
|
+ return initialReturnChunk;
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private class PendingChunk implements Runnable {
|
+ private class PendingChunk implements Runnable {
|
||||||
+ private final int x;
|
+ private final int x;
|
||||||
+ private final int z;
|
+ private final int z;
|
||||||
+ private final long key;
|
+ private final long key;
|
||||||
+ private final PriorityQueuedExecutor.PendingTask<Void> task;
|
|
||||||
+ private final PriorityQueuedExecutor.PendingTask<Chunk> chunkGenTask;
|
|
||||||
+ private final CompletableFuture<Chunk> loadOnly = new CompletableFuture<>();
|
+ private final CompletableFuture<Chunk> loadOnly = new CompletableFuture<>();
|
||||||
+ private final CompletableFuture<Chunk> generate = new CompletableFuture<>();
|
+ private final CompletableFuture<Chunk> generate = new CompletableFuture<>();
|
||||||
|
+ private final AtomicInteger requests = new AtomicInteger(0);
|
||||||
+
|
+
|
||||||
+ private volatile PendingStatus status = PendingStatus.STARTED;
|
+ private volatile PendingStatus status = PendingStatus.STARTED;
|
||||||
|
+ private volatile PriorityQueuedExecutor.PendingTask<Void> loadTask;
|
||||||
|
+ private volatile PriorityQueuedExecutor.PendingTask<Chunk> genTask;
|
||||||
|
+ private volatile Priority taskPriority;
|
||||||
+ private volatile boolean generating;
|
+ private volatile boolean generating;
|
||||||
+ private volatile boolean canGenerate;
|
+ private volatile boolean canGenerate;
|
||||||
+ private volatile boolean isHighPriority;
|
+ private volatile boolean isHighPriority;
|
||||||
@@ -1119,9 +1185,7 @@ index 0000000000..1c592c7956
|
|||||||
+ this.z = z;
|
+ this.z = z;
|
||||||
+ this.key = key;
|
+ this.key = key;
|
||||||
+ this.canGenerate = canGenerate;
|
+ this.canGenerate = canGenerate;
|
||||||
+ Priority taskPriority = priority ? Priority.HIGH : Priority.NORMAL;
|
+ taskPriority = priority ? Priority.HIGH : Priority.NORMAL;
|
||||||
+ this.chunkGenTask = generationExecutor.createPendingTask(this::generateChunk, taskPriority);
|
|
||||||
+ this.task = EXECUTOR.submitTask(this, taskPriority);
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private synchronized void setStatus(PendingStatus status) {
|
+ private synchronized void setStatus(PendingStatus status) {
|
||||||
@@ -1141,6 +1205,11 @@ index 0000000000..1c592c7956
|
|||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private Chunk generateChunk() {
|
+ private Chunk generateChunk() {
|
||||||
|
+ synchronized (this) {
|
||||||
|
+ if (requests.get() <= 0) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
+ CompletableFuture<Chunk> pending = new CompletableFuture<>();
|
+ CompletableFuture<Chunk> pending = new CompletableFuture<>();
|
||||||
+ batchScheduler.startBatch();
|
+ batchScheduler.startBatch();
|
||||||
+ batchScheduler.add(new ChunkCoordIntPair(x, z));
|
+ batchScheduler.add(new ChunkCoordIntPair(x, z));
|
||||||
@@ -1178,8 +1247,11 @@ index 0000000000..1c592c7956
|
|||||||
+ loadOnly.complete(null);
|
+ loadOnly.complete(null);
|
||||||
+
|
+
|
||||||
+ synchronized (this) {
|
+ synchronized (this) {
|
||||||
+ if (!canGenerate) {
|
+ boolean cancelled = requests.get() <= 0;
|
||||||
|
+ if (!canGenerate || cancelled) {
|
||||||
|
+ if (!cancelled) {
|
||||||
+ setStatus(PendingStatus.FAIL);
|
+ setStatus(PendingStatus.FAIL);
|
||||||
|
+ }
|
||||||
+ this.chunk = null;
|
+ this.chunk = null;
|
||||||
+ this.hasFinished = true;
|
+ this.hasFinished = true;
|
||||||
+ pendingChunks.remove(key);
|
+ pendingChunks.remove(key);
|
||||||
@@ -1232,7 +1304,7 @@ index 0000000000..1c592c7956
|
|||||||
+ throw new IllegalStateException("Must post from main");
|
+ throw new IllegalStateException("Must post from main");
|
||||||
+ }
|
+ }
|
||||||
+ synchronized (this) {
|
+ synchronized (this) {
|
||||||
+ if (hasPosted) {
|
+ if (hasPosted || requests.get() <= 0) { // if pending is 0, all were cancelled
|
||||||
+ return chunk;
|
+ return chunk;
|
||||||
+ }
|
+ }
|
||||||
+ hasPosted = true;
|
+ hasPosted = true;
|
||||||
@@ -1269,20 +1341,32 @@ index 0000000000..1c592c7956
|
|||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ synchronized void addListener(CompletableFuture<Chunk> future, boolean gen) {
|
+ synchronized PendingChunkRequest addListener(CompletableFuture<Chunk> future, boolean gen) {
|
||||||
+ if (hasFinished) {
|
+ if (hasFinished) {
|
||||||
+ future.complete(chunk);
|
+ future.complete(chunk);
|
||||||
|
+ return new PendingChunkRequest(this);
|
||||||
+ } else if (gen) {
|
+ } else if (gen) {
|
||||||
+ canGenerate = true;
|
+ canGenerate = true;
|
||||||
+ generate.thenAccept(future::complete);
|
+ generate.thenAccept(future::complete);
|
||||||
+ } else {
|
+ } else {
|
||||||
+ if (generating) {
|
+ if (generating) {
|
||||||
+ future.complete(null);
|
+ future.complete(null);
|
||||||
|
+ return new PendingChunkRequest(this);
|
||||||
+ } else {
|
+ } else {
|
||||||
+ loadOnly.thenAccept(future::complete);
|
+ loadOnly.thenAccept(future::complete);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
|
+ requests.incrementAndGet();
|
||||||
|
+ if (loadTask == null) {
|
||||||
|
+ // Take care of a race condition in that a request could be cancelled after the synchronize
|
||||||
|
+ // on pendingChunks, but before a listener is added, which would erase these pending tasks.
|
||||||
|
+ genTask = generationExecutor.createPendingTask(this::generateChunk, taskPriority);
|
||||||
|
+ loadTask = EXECUTOR.submitTask(this, taskPriority);
|
||||||
+ }
|
+ }
|
||||||
|
+ return new PendingChunkRequest(this, gen);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+
|
+
|
||||||
+ @Override
|
+ @Override
|
||||||
+ public void run() {
|
+ public void run() {
|
||||||
@@ -1306,35 +1390,69 @@ index 0000000000..1c592c7956
|
|||||||
+ mainThreadQueue.notify();
|
+ mainThreadQueue.notify();
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
+ generationExecutor.submitTask(chunkGenTask);
|
+ generationExecutor.submitTask(genTask);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ void bumpPriority() {
|
+ void bumpPriority() {
|
||||||
+ task.bumpPriority();
|
+ this.taskPriority = Priority.HIGH;
|
||||||
+ chunkGenTask.bumpPriority();
|
+ PriorityQueuedExecutor.PendingTask<Void> loadTask = this.loadTask;
|
||||||
|
+ PriorityQueuedExecutor.PendingTask<Chunk> genTask = this.genTask;
|
||||||
|
+ if (loadTask != null) {
|
||||||
|
+ loadTask.bumpPriority();
|
||||||
|
+ }
|
||||||
|
+ if (genTask != null) {
|
||||||
|
+ genTask.bumpPriority();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public synchronized boolean isCancelled() {
|
||||||
|
+ return requests.get() <= 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public synchronized void cancel(PendingChunkRequest request) {
|
||||||
|
+ synchronized (pendingChunks) {
|
||||||
|
+ if (!request.cancelled.compareAndSet(false, true)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (requests.decrementAndGet() > 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ boolean c1 = genTask.cancel();
|
||||||
|
+ boolean c2 = loadTask.cancel();
|
||||||
|
+ loadTask = null;
|
||||||
|
+ genTask = null;
|
||||||
|
+ pendingChunks.remove(key);
|
||||||
|
+ setStatus(PendingStatus.CANCELLED);
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+}
|
+}
|
||||||
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||||
index 2c7c8adf7c..04ad94e171 100644
|
index 2c7c8adf7c..6d18cdeaf7 100644
|
||||||
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||||
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||||
@@ -0,0 +0,0 @@ public class PlayerChunk {
|
@@ -0,0 +0,0 @@ public class PlayerChunk {
|
||||||
|
// You know the drill, https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse
|
||||||
// All may seem good at first, but there's deeper issues if you play for a bit
|
// All may seem good at first, but there's deeper issues if you play for a bit
|
||||||
boolean chunkExists; // Paper
|
boolean chunkExists; // Paper
|
||||||
private boolean loadInProgress = false;
|
- private boolean loadInProgress = false;
|
||||||
- private Runnable loadedRunnable = new Runnable() {
|
- private Runnable loadedRunnable = new Runnable() {
|
||||||
- public void run() {
|
- public void run() {
|
||||||
- loadInProgress = false;
|
- loadInProgress = false;
|
||||||
- PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(location.x, location.z, true, true);
|
- PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(location.x, location.z, true, true);
|
||||||
- markChunkUsed(); // Paper - delay chunk unloads
|
- markChunkUsed(); // Paper - delay chunk unloads
|
||||||
- }
|
+ private PaperAsyncChunkProvider.CancellableChunkRequest chunkRequest;
|
||||||
+ // Paper start
|
+ // Paper start
|
||||||
+ private java.util.function.Consumer<Chunk> chunkLoadedConsumer = chunk -> {
|
+ private java.util.function.Consumer<Chunk> chunkLoadedConsumer = chunk -> {
|
||||||
+ loadInProgress = false;
|
+ chunkRequest = null;
|
||||||
+ PlayerChunk pChunk = PlayerChunk.this;
|
+ PlayerChunk pChunk = PlayerChunk.this;
|
||||||
|
+ if (chunk == null) {
|
||||||
|
+ new Throwable().printStackTrace();
|
||||||
|
}
|
||||||
+ pChunk.chunk = chunk;
|
+ pChunk.chunk = chunk;
|
||||||
+ markChunkUsed(); // Paper - delay chunk unloads
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
||||||
};
|
};
|
||||||
@@ -1353,6 +1471,16 @@ index 2c7c8adf7c..04ad94e171 100644
|
|||||||
+
|
+
|
||||||
+ markedHigh = true;
|
+ markedHigh = true;
|
||||||
+ playerChunkMap.getWorld().getChunkProviderServer().bumpPriority(location);
|
+ playerChunkMap.getWorld().getChunkProviderServer().bumpPriority(location);
|
||||||
|
+ if (chunkRequest == null) {
|
||||||
|
+ requestChunkIfNeeded(PlayerChunkMap.CAN_GEN_CHUNKS.test(player));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ private void requestChunkIfNeeded(boolean flag) {
|
||||||
|
+ if (chunkRequest == null) {
|
||||||
|
+ chunkRequest = this.playerChunkMap.getWorld().getChunkProviderServer().requestChunk(this.location.x, this.location.z, flag, markedHigh, chunkLoadedConsumer);
|
||||||
|
+ this.chunk = chunkRequest.getChunk(); // Paper)
|
||||||
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ private double getDistance(EntityPlayer player, int inFront) {
|
+ private double getDistance(EntityPlayer player, int inFront) {
|
||||||
+ final float yaw = MathHelper.normalizeYaw(player.yaw);
|
+ final float yaw = MathHelper.normalizeYaw(player.yaw);
|
||||||
@@ -1369,7 +1497,13 @@ index 2c7c8adf7c..04ad94e171 100644
|
|||||||
+ // Paper end
|
+ // Paper end
|
||||||
// Paper start - delay chunk unloads
|
// Paper start - delay chunk unloads
|
||||||
private void markChunkUsed() {
|
private void markChunkUsed() {
|
||||||
|
+ if (!chunkHasPlayers && chunkRequest != null) {
|
||||||
|
+ chunkRequest.cancel();
|
||||||
|
+ chunkRequest = null;
|
||||||
|
+ }
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -0,0 +0,0 @@ public class PlayerChunk {
|
@@ -0,0 +0,0 @@ public class PlayerChunk {
|
||||||
ChunkProviderServer chunkproviderserver = playerchunkmap.getWorld().getChunkProviderServer();
|
ChunkProviderServer chunkproviderserver = playerchunkmap.getWorld().getChunkProviderServer();
|
||||||
|
|
||||||
@@ -1397,19 +1531,24 @@ index 2c7c8adf7c..04ad94e171 100644
|
|||||||
- this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, true, flag);
|
- this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, true, flag);
|
||||||
- markChunkUsed(); // Paper - delay chunk unloads
|
- markChunkUsed(); // Paper - delay chunk unloads
|
||||||
+ // Paper start - async chunks
|
+ // Paper start - async chunks
|
||||||
+ if (!loadInProgress) {
|
+ requestChunkIfNeeded(flag);
|
||||||
+ loadInProgress = true;
|
|
||||||
+ this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, true, flag, markedHigh, chunkLoadedConsumer); // Paper)
|
|
||||||
+ markChunkUsed(); // Paper - delay chunk unloads
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
return this.chunk != null;
|
return this.chunk != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 d1a443ca8d..6c54294d3f 100644
|
index d1a443ca8d..1201a2758e 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
|
||||||
|
@@ -0,0 +0,0 @@ public class PlayerChunkMap {
|
||||||
|
};
|
||||||
|
private static final Predicate<EntityPlayer> b = (entityplayer) -> {
|
||||||
|
return entityplayer != null && (!entityplayer.isSpectator() || entityplayer.getWorldServer().getGameRules().getBoolean("spectatorsGenerateChunks"));
|
||||||
|
- };
|
||||||
|
+ }; static final Predicate<EntityPlayer> CAN_GEN_CHUNKS = b; // Paper - OBFHELPER
|
||||||
|
private final WorldServer world;
|
||||||
|
private final List<EntityPlayer> managedPlayers = Lists.newArrayList();
|
||||||
|
private final Long2ObjectMap<PlayerChunk> e = new Long2ObjectOpenHashMap(4096);
|
||||||
@@ -0,0 +0,0 @@ public class PlayerChunkMap {
|
@@ -0,0 +0,0 @@ public class PlayerChunkMap {
|
||||||
if (playerchunk != null) {
|
if (playerchunk != null) {
|
||||||
playerchunk.b(entityplayer);
|
playerchunk.b(entityplayer);
|
||||||
|
@@ -41,7 +41,7 @@ index 8da88e1c3a..64cec6d692 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||||
index 04ad94e171..748d5f28e5 100644
|
index 6d18cdeaf7..9584238859 100644
|
||||||
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||||
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||||
@@ -0,0 +0,0 @@ public class PlayerChunk {
|
@@ -0,0 +0,0 @@ public class PlayerChunk {
|
||||||
|
Reference in New Issue
Block a user