Many improvements to chunk prioritization and bug fixes

Fixed a few bugs, and made numerous improvements.
Fixed issue where a sync chunk load could have its ticket removed and the
priority ticket could expire...
Still not perfect there but better than before.

Also fixed few other misc issues such as watchdog cpu usage, chunk queue update
had risk of double enqueue due to it no longer being a set.

Added much more information about chunk state to watchdog prints.

I see some more room for improvement even, but this is much better than before.

Fixes #3407
Fixes #3411
Fixes #3395
Fixes #3389
This commit is contained in:
Aikar 2020-05-20 05:11:57 -04:00
parent c82b292ab0
commit 7e1525ea2d
No known key found for this signature in database
GPG Key ID: 401ADFC9891FAAFE
13 changed files with 323 additions and 149 deletions

View File

@ -5,19 +5,28 @@ Subject: [PATCH] ChunkMapDistance CME
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
index ae661297774f51c8b61fc08ca43e13ba368d0021..682a64c775adc1254f12d9f93b23375735ed4895 100644
index ae661297774f51c8b61fc08ca43e13ba368d0021..83da76fdc495225b563cecbdb71422aec2b534f3 100644
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
@@ -33,7 +33,7 @@ public abstract class ChunkMapDistance {
@@ -33,7 +33,16 @@ public abstract class ChunkMapDistance {
private final ChunkMapDistance.a e = new ChunkMapDistance.a();
private final ChunkMapDistance.b f = new ChunkMapDistance.b(8);
private final ChunkMapDistance.c g = new ChunkMapDistance.c(33);
- private final Set<PlayerChunk> pendingChunkUpdates = Sets.newHashSet();
+ private final java.util.Queue<PlayerChunk> pendingChunkUpdates = new java.util.ArrayDeque<>(); // PAIL pendingChunkUpdates // Paper - use a queue
+ // Paper start use a queue, but still keep unique requirement
+ public final java.util.Queue<PlayerChunk> pendingChunkUpdates = new java.util.ArrayDeque<PlayerChunk>() {
+ @Override
+ public boolean add(PlayerChunk o) {
+ if (o.isUpdateQueued) return true;
+ o.isUpdateQueued = true;
+ return super.add(o);
+ }
+ };
+ // Paper end
private final ChunkTaskQueueSorter i;
private final Mailbox<ChunkTaskQueueSorter.a<Runnable>> j;
private final Mailbox<ChunkTaskQueueSorter.b> k;
@@ -94,26 +94,12 @@ public abstract class ChunkMapDistance {
@@ -94,26 +103,14 @@ public abstract class ChunkMapDistance {
;
}
@ -43,9 +52,23 @@ index ae661297774f51c8b61fc08ca43e13ba368d0021..682a64c775adc1254f12d9f93b233757
- // CraftBukkit end
-
+ while(!this.pendingChunkUpdates.isEmpty()) {
+ this.pendingChunkUpdates.remove().a(playerchunkmap);
+ PlayerChunk remove = this.pendingChunkUpdates.remove();
+ remove.isUpdateQueued = false;
+ remove.a(playerchunkmap);
+ }
+ // Paper end
return true;
} else {
if (!this.l.isEmpty()) {
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 6e9f402fb0faccc222b4289deb36e2d85a66eb7c..980044b9a81232e7d0eab8e4947db6ca1f845c1c 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -18,6 +18,7 @@ public class PlayerChunk {
private static final CompletableFuture<Either<Chunk, PlayerChunk.Failure>> UNLOADED_CHUNK_FUTURE = CompletableFuture.completedFuture(PlayerChunk.UNLOADED_CHUNK);
private static final List<ChunkStatus> CHUNK_STATUSES = ChunkStatus.a();
private static final PlayerChunk.State[] CHUNK_STATES = PlayerChunk.State.values();
+ boolean isUpdateQueued = false; // Paper
private final AtomicReferenceArray<CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> statusFutures;
private volatile CompletableFuture<Either<Chunk, PlayerChunk.Failure>> fullChunkFuture; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage
private volatile CompletableFuture<Either<Chunk, PlayerChunk.Failure>> tickingFuture; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage

View File

@ -399,10 +399,10 @@ index 206d04dcce1d7d074cf7151a083bdc626b0b8e07..f75f48a3d0b0bc1da3c5ae3b3cf20b64
+ }
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 6e9f402fb0faccc222b4289deb36e2d85a66eb7c..a640cb3845a853780b8cc2dbfc6e9be3728817e7 100644
index 980044b9a81232e7d0eab8e4947db6ca1f845c1c..47e3e618c9e683e6975fb64e1094dc7078574dae 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -26,7 +26,7 @@ public class PlayerChunk {
@@ -27,7 +27,7 @@ public class PlayerChunk {
public int oldTicketLevel;
private int ticketLevel;
private int n;

View File

@ -108,10 +108,10 @@ index 8b499c815c77bf5b356d4216ba6cbf2a329c9aca..cfed5f51431ec5aecb538a321327bfb6
this.methodProfiler.enter("snooper");
if (((DedicatedServer) this).getDedicatedServerProperties().snooperEnabled && !this.snooper.d() && this.ticks > 100) { // Spigot
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index a640cb3845a853780b8cc2dbfc6e9be3728817e7..3d255b19647fb37f53a420c907bc634181580c18 100644
index 47e3e618c9e683e6975fb64e1094dc7078574dae..ed9ada49c7cc1131691bd6e005b2380274ef23e3 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -40,6 +40,9 @@ public class PlayerChunk {
@@ -41,6 +41,9 @@ public class PlayerChunk {
private final PlayerChunkMap chunkMap; // Paper
@ -121,7 +121,7 @@ index a640cb3845a853780b8cc2dbfc6e9be3728817e7..3d255b19647fb37f53a420c907bc6341
public PlayerChunk(ChunkCoordIntPair chunkcoordintpair, int i, LightEngine lightengine, PlayerChunk.c playerchunk_c, PlayerChunk.d playerchunk_d) {
this.statusFutures = new AtomicReferenceArray(PlayerChunk.CHUNK_STATUSES.size());
this.fullChunkFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
@@ -385,7 +388,19 @@ public class PlayerChunk {
@@ -386,7 +389,19 @@ public class PlayerChunk {
boolean flag2 = playerchunk_state.isAtLeast(PlayerChunk.State.BORDER);
boolean flag3 = playerchunk_state1.isAtLeast(PlayerChunk.State.BORDER);
@ -141,7 +141,7 @@ index a640cb3845a853780b8cc2dbfc6e9be3728817e7..3d255b19647fb37f53a420c907bc6341
if (!flag2 && flag3) {
// Paper start - cache ticking ready status
int expectCreateCount = ++this.fullChunkCreateCount;
@@ -505,8 +520,32 @@ public class PlayerChunk {
@@ -506,8 +521,32 @@ public class PlayerChunk {
}
public void m() {

View File

@ -108,10 +108,10 @@ index f0a052eec2fb72b11dc70bf62a5e57f599bbc190..2f95174fcc467908808ed3f2dc956bdc
@Nullable
private PersistentStructureLegacy c;
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 3d255b19647fb37f53a420c907bc634181580c18..040d4b41ea2223937ca22de2d40560f97b310f9a 100644
index ed9ada49c7cc1131691bd6e005b2380274ef23e3..52ea4f05a0c7f29f62f31bb032a5ceb905107e60 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -114,6 +114,19 @@ public class PlayerChunk {
@@ -115,6 +115,19 @@ public class PlayerChunk {
Either<IChunkAccess, PlayerChunk.Failure> either = (Either<IChunkAccess, PlayerChunk.Failure>) statusFuture.getNow(null);
return either == null ? null : (Chunk) either.left().orElse(null);
}

View File

@ -160,6 +160,44 @@ index fa1c920ea6092259149f9e7f9cd7cc1ed27bf338..98acbfa44dd9042b26fdf719d7748f92
}
public static Timing getTickList(WorldServer worldserver, String timingsType) {
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
index af810987846efcd2bffbd23c31481b2d31c168dd..331493a172f58e71b464d635efdba461082bd27d 100644
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
@@ -1,5 +1,6 @@
package com.destroystokyo.paper;
+import com.destroystokyo.paper.io.chunk.ChunkTaskManager;
import com.google.common.base.Functions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -28,14 +29,14 @@ public class PaperCommand extends Command {
public PaperCommand(String name) {
super(name);
this.description = "Paper related commands";
- this.usageMessage = "/paper [heap | entity | reload | version | debug | chunkinfo]";
+ this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo]";
this.setPermission("bukkit.command.paper");
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
if (args.length <= 1)
- return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "chunkinfo");
+ return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo");
switch (args[0].toLowerCase(Locale.ENGLISH))
{
@@ -127,6 +128,9 @@ public class PaperCommand extends Command {
case "debug":
doDebug(sender, args);
break;
+ case "dumpwaiting":
+ ChunkTaskManager.dumpAllChunkLoadInfo();
+ break;
case "chunkinfo":
doChunkInfo(sender, args);
break;
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index dbd14399707cdd43f98af40191be8ff3e76edf43..74295466e53db06d0d019a13768f3575ac61d699 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
@ -1809,10 +1847,10 @@ index 0000000000000000000000000000000000000000..1dfa8abfd869ca97e4cc566d44e509b4
+}
diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b20c159f6bb425be70201cf33159aa9e949eb54
index 0000000000000000000000000000000000000000..d9580eb998801edd34c610ced3f82f9627c6685b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
@@ -0,0 +1,492 @@
@@ -0,0 +1,502 @@
+package com.destroystokyo.paper.io.chunk;
+
+import com.destroystokyo.paper.io.PaperFileIOThread;
@ -1824,7 +1862,9 @@ index 0000000000000000000000000000000000000000..2b20c159f6bb425be70201cf33159aa9
+import net.minecraft.server.IChunkAccess;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.NBTTagCompound;
+import net.minecraft.server.PlayerChunk;
+import net.minecraft.server.WorldServer;
+import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.Level;
+import org.bukkit.Bukkit;
+import org.spigotmc.AsyncCatcher;
@ -1912,20 +1952,28 @@ index 0000000000000000000000000000000000000000..2b20c159f6bb425be70201cf33159aa9
+ // log current status of chunk to indicate whether we're waiting on generation or loading
+ net.minecraft.server.PlayerChunk chunkHolder = chunkInfo.world.getChunkProvider().playerChunkMap.getVisibleChunk(key);
+
+ if (chunkHolder == null) {
+ PaperFileIOThread.LOGGER.log(Level.ERROR, "Chunk Holder - null");
+ } else {
+ IChunkAccess chunk = chunkHolder.getAvailableChunkNow();
+ net.minecraft.server.ChunkStatus holderStatus = chunkHolder.getChunkHolderStatus();
+ PaperFileIOThread.LOGGER.log(Level.ERROR, "Chunk Holder - non-null");
+ PaperFileIOThread.LOGGER.log(Level.ERROR, "Chunk Status - " + ((chunk == null) ? "null chunk" : chunk.getChunkStatus().toString()));
+ PaperFileIOThread.LOGGER.log(Level.ERROR, "Chunk Holder Status - " + ((holderStatus == null) ? "null" : holderStatus.toString()));
+ }
+
+ dumpChunkInfo(chunkHolder, chunkInfo.chunkX, chunkInfo.chunkZ);
+ }
+ }
+ }
+
+ static void dumpChunkInfo(PlayerChunk chunkHolder, int x, int z) {
+ dumpChunkInfo(chunkHolder, x, z, 0);
+ }
+ static void dumpChunkInfo(PlayerChunk chunkHolder, int x, int z, int indent) {
+ String indentStr = StringUtils.repeat(" ", indent);
+ if (chunkHolder == null) {
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Holder - null for (" + x +"," + z +")");
+ } else {
+ IChunkAccess chunk = chunkHolder.getAvailableChunkNow();
+ net.minecraft.server.ChunkStatus holderStatus = chunkHolder.getChunkHolderStatus();
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Holder - non-null");
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Status - " + ((chunk == null) ? "null chunk" : chunk.getChunkStatus().toString()));
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Ticket Status - " + PlayerChunk.getChunkStatus(chunkHolder.getTicketLevel()));
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Holder Status - " + ((holderStatus == null) ? "null" : holderStatus.toString()));
+ }
+ }
+
+ public static void initGlobalLoadThreads(int threads) {
+ if (threads <= 0 || globalWorkers != null) {
+ return;
@ -3004,10 +3052,10 @@ index 4c52c57c02571353f71772e3650932f314da62ca..71daa0cb08d69c16bded510d1a490534
@Override
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 040d4b41ea2223937ca22de2d40560f97b310f9a..bf592125f4ce5d7ea6e802e637ee3bfbe25d23aa 100644
index 52ea4f05a0c7f29f62f31bb032a5ceb905107e60..0f1576effe10795bcb8ed3b519f4dbafdf9ea6ed 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -127,6 +127,18 @@ public class PlayerChunk {
@@ -128,6 +128,18 @@ public class PlayerChunk {
}
return null;
}
@ -3026,7 +3074,7 @@ index 040d4b41ea2223937ca22de2d40560f97b310f9a..bf592125f4ce5d7ea6e802e637ee3bfb
// Paper end
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFutureUnchecked(ChunkStatus chunkstatus) {
@@ -352,7 +364,7 @@ public class PlayerChunk {
@@ -353,7 +365,7 @@ public class PlayerChunk {
ChunkStatus chunkstatus = getChunkStatus(this.oldTicketLevel);
ChunkStatus chunkstatus1 = getChunkStatus(this.ticketLevel);
boolean flag = this.oldTicketLevel <= PlayerChunkMap.GOLDEN_TICKET;
@ -3035,7 +3083,7 @@ index 040d4b41ea2223937ca22de2d40560f97b310f9a..bf592125f4ce5d7ea6e802e637ee3bfb
PlayerChunk.State playerchunk_state = getChunkState(this.oldTicketLevel);
PlayerChunk.State playerchunk_state1 = getChunkState(this.ticketLevel);
// CraftBukkit start
@@ -388,6 +400,12 @@ public class PlayerChunk {
@@ -389,6 +401,12 @@ public class PlayerChunk {
}
});

View File

@ -11,12 +11,13 @@ it must be enabled by setting the startup flag -Dpaper.debug-sync-loads=true
To get a debug log for sync loads, the command is /paper syncloadinfo
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
index af810987846efcd2bffbd23c31481b2d31c168dd..ddb60e9a48e5e7225ad575240b94fda24b6b78ca 100644
index 331493a172f58e71b464d635efdba461082bd27d..182b440ba4802d199b8e44f7779b3401ace495d5 100644
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
@@ -1,9 +1,13 @@
@@ -1,10 +1,14 @@
package com.destroystokyo.paper;
import com.destroystokyo.paper.io.chunk.ChunkTaskManager;
+import com.destroystokyo.paper.io.SyncLoadFinder;
import com.google.common.base.Functions;
import com.google.common.collect.Iterables;
@ -28,7 +29,7 @@ index af810987846efcd2bffbd23c31481b2d31c168dd..ddb60e9a48e5e7225ad575240b94fda2
import net.minecraft.server.*;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
@@ -18,6 +22,9 @@ import org.bukkit.craftbukkit.CraftWorld;
@@ -19,6 +23,9 @@ import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import java.io.File;
@ -38,24 +39,24 @@ index af810987846efcd2bffbd23c31481b2d31c168dd..ddb60e9a48e5e7225ad575240b94fda2
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@@ -28,14 +35,14 @@ public class PaperCommand extends Command {
@@ -29,14 +36,14 @@ public class PaperCommand extends Command {
public PaperCommand(String name) {
super(name);
this.description = "Paper related commands";
- this.usageMessage = "/paper [heap | entity | reload | version | debug | chunkinfo]";
+ this.usageMessage = "/paper [heap | entity | reload | version | debug | chunkinfo | syncloadinfo]";
- this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo]";
+ this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo | syncloadinfo]";
this.setPermission("bukkit.command.paper");
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
if (args.length <= 1)
- return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "chunkinfo");
+ return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "chunkinfo", "syncloadinfo");
- return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo");
+ return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo", "syncloadinfo");
switch (args[0].toLowerCase(Locale.ENGLISH))
{
@@ -130,6 +137,9 @@ public class PaperCommand extends Command {
@@ -134,6 +141,9 @@ public class PaperCommand extends Command {
case "chunkinfo":
doChunkInfo(sender, args);
break;
@ -65,7 +66,7 @@ index af810987846efcd2bffbd23c31481b2d31c168dd..ddb60e9a48e5e7225ad575240b94fda2
case "ver":
case "version":
Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
@@ -146,6 +156,40 @@ public class PaperCommand extends Command {
@@ -150,6 +160,40 @@ public class PaperCommand extends Command {
return true;
}

View File

@ -42,7 +42,7 @@ sets the excessive tick delay to the specified ticks (defaults to
60 * 20 ticks, aka 60 seconds)
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index f4836e2da1061e7aa62ddb01c8ca7b3467b18415..647f6fc8efb350fbd0bc4c40358a998f8b89b96a 100644
index 74295466e53db06d0d019a13768f3575ac61d699..f1b41e16c8ce8323a896339c5d822f8ff7d8f7e6 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -369,6 +369,13 @@ public class PaperConfig {
@ -883,7 +883,7 @@ index 0000000000000000000000000000000000000000..118988c39e58f28e8a2851792b9c014f
+ }
+}
diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java
index 063f8eb08635aaa44803f2a67d118805294ae938..58ba1209155e05e802171800f4420e3ae419950f 100644
index 3fcfe416d26808fa1c9bfdc5b413b149764c544a..3bf17ccdaef21322b787db538d569e0bc614ef22 100644
--- a/src/main/java/net/minecraft/server/BlockPosition.java
+++ b/src/main/java/net/minecraft/server/BlockPosition.java
@@ -126,6 +126,7 @@ public class BlockPosition extends BaseBlockPosition implements MinecraftSeriali
@ -895,7 +895,7 @@ index 063f8eb08635aaa44803f2a67d118805294ae938..58ba1209155e05e802171800f4420e3a
return this.b(baseblockposition.getX(), baseblockposition.getY(), baseblockposition.getZ());
}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index e67e00653575c3e57fe16980d2ff074d8413a95e..ca1b5b3b094b847f96742d8466fc42c5bdedbff5 100644
index 4f65c3aca4e1c299114c03339605e0749a969653..fd998e4fb1534690a2ef8c1bca55e0ae9fe855f9 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -200,6 +200,13 @@ public class ChunkProviderServer extends IChunkProvider {
@ -984,10 +984,10 @@ index 33cfeabdee03195a294f303f28044a313cb1c4ed..2287e47d1b891135a5f2579ec324c705
public String toString() {
return this.e + ": " + this.a + ", " + this.b + ", " + this.c + ", " + this.f;
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index bf592125f4ce5d7ea6e802e637ee3bfbe25d23aa..3d610e41969768da0d2848fa1ae195035ccfd660 100644
index 0f1576effe10795bcb8ed3b519f4dbafdf9ea6ed..afc92dd031cdaf725b85c0b301d5a5a21da54720 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -472,7 +472,9 @@ public class PlayerChunk {
@@ -473,7 +473,9 @@ public class PlayerChunk {
PlayerChunk.this.isTickingReady = true;
@ -1161,7 +1161,7 @@ index f533860bbed19ff2915c90186c259b466f41ce90..3f1aa5ced697490b5481ba992cf5af5d
}
}
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index fcbc9f29139ce5cd3b165130006f9c326a5d9eea..5173731dc55db416a312e13afd09e4e69d829e45 100644
index 5519fb529dd8e1f93aab79dbc434715e08edb94f..be61f898cc96afeffe6ff2eb0ae3c4ce8da10b80 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -170,6 +170,15 @@ public class WorldServer extends World {

View File

@ -313,10 +313,18 @@ index aefea3a9a8b9b75c62bd20018be7cd166a213001..123de5ac9026508e21cdc225f0962f5c
String[] split = restartScript.split( " " );
if ( split.length > 0 && new File( split[0] ).isFile() )
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 5bdcdcf9e85b73086722783bff26321d03382bb9..fe4b8caf28b2d36b2034ac90b1a76dea7b691feb 100644
index 5bdcdcf9e85b73086722783bff26321d03382bb9..513c1041c34ebb3ac1775674a3f4526693759c08 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -41,6 +41,7 @@ public class WatchdogThread extends Thread
@@ -13,6 +13,7 @@ import org.bukkit.Bukkit;
public class WatchdogThread extends Thread
{
+ public static final boolean DISABLE_WATCHDOG = Boolean.getBoolean("disable.watchdog"); // Paper
private static WatchdogThread instance;
private final long timeoutTime;
private final long earlyWarningEvery; // Paper - Timeout time for just printing a dump but not restarting
@@ -41,6 +42,7 @@ public class WatchdogThread extends Thread
{
if ( instance == null )
{
@ -324,13 +332,13 @@ index 5bdcdcf9e85b73086722783bff26321d03382bb9..fe4b8caf28b2d36b2034ac90b1a76dea
instance = new WatchdogThread( timeoutTime * 1000L, restart );
instance.start();
}
@@ -67,12 +68,13 @@ public class WatchdogThread extends Thread
@@ -67,12 +69,13 @@ public class WatchdogThread extends Thread
// Paper start
Logger log = Bukkit.getServer().getLogger();
long currentTime = monotonicMillis();
- if ( lastTick != 0 && currentTime > lastTick + earlyWarningEvery && !Boolean.getBoolean("disable.watchdog") )
+ MinecraftServer server = MinecraftServer.getServer();
+ if (lastTick != 0 && hasStarted && (!server.isRunning() || (currentTime > lastTick + earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) ))
+ if (lastTick != 0 && hasStarted && (!server.isRunning() || (currentTime > lastTick + earlyWarningEvery && !DISABLE_WATCHDOG) ))
{
- boolean isLongTimeout = currentTime > lastTick + timeoutTime;
+ boolean isLongTimeout = currentTime > lastTick + timeoutTime || (!server.isRunning() && !server.hasStopped() && currentTime > lastTick + 1000);
@ -341,7 +349,7 @@ index 5bdcdcf9e85b73086722783bff26321d03382bb9..fe4b8caf28b2d36b2034ac90b1a76dea
lastEarlyWarning = currentTime;
if (isLongTimeout) {
// Paper end
@@ -114,7 +116,7 @@ public class WatchdogThread extends Thread
@@ -114,7 +117,7 @@ public class WatchdogThread extends Thread
log.log( Level.SEVERE, "------------------------------" );
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
@ -350,7 +358,7 @@ index 5bdcdcf9e85b73086722783bff26321d03382bb9..fe4b8caf28b2d36b2034ac90b1a76dea
log.log( Level.SEVERE, "------------------------------" );
//
// Paper start - Only print full dump on long timeouts
@@ -135,9 +137,24 @@ public class WatchdogThread extends Thread
@@ -135,9 +138,24 @@ public class WatchdogThread extends Thread
if ( isLongTimeout )
{

View File

@ -7,10 +7,10 @@ Subject: [PATCH] Don't crash if player is attempted to be removed from
I suspect it deals with teleporting as it uses players current x/y/z
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
index 682a64c775adc1254f12d9f93b23375735ed4895..534bb87caf88f0f1bf7988494274b762ab7210e1 100644
index 83da76fdc495225b563cecbdb71422aec2b534f3..4e0ea454f00c69f03023f01c1d4bd2eda5553a02 100644
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
@@ -226,6 +226,7 @@ public abstract class ChunkMapDistance {
@@ -237,6 +237,7 @@ public abstract class ChunkMapDistance {
public void b(SectionPosition sectionposition, EntityPlayer entityplayer) {
long i = sectionposition.u().pair();
ObjectSet<EntityPlayer> objectset = (ObjectSet) this.c.get(i);

View File

@ -6,7 +6,7 @@ Subject: [PATCH] Optimize isOutsideRange to use distance maps
Use a distance map to find the players in range quickly
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
index 534bb87caf88f0f1bf7988494274b762ab7210e1..b98abed74f214932b4a226f12645f987191b0097 100644
index 4e0ea454f00c69f03023f01c1d4bd2eda5553a02..353b186060b2c0417a49ab3865ea5972c859b016 100644
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
@@ -31,7 +31,7 @@ public abstract class ChunkMapDistance {
@ -16,9 +16,9 @@ index 534bb87caf88f0f1bf7988494274b762ab7210e1..b98abed74f214932b4a226f12645f987
- private final ChunkMapDistance.b f = new ChunkMapDistance.b(8);
+ public static final int MOB_SPAWN_RANGE = 8; //private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used
private final ChunkMapDistance.c g = new ChunkMapDistance.c(33);
private final java.util.Queue<PlayerChunk> pendingChunkUpdates = new java.util.ArrayDeque<>(); // PAIL pendingChunkUpdates // Paper - use a queue
private final ChunkTaskQueueSorter i;
@@ -41,6 +41,8 @@ public abstract class ChunkMapDistance {
// Paper start use a queue, but still keep unique requirement
public final java.util.Queue<PlayerChunk> pendingChunkUpdates = new java.util.ArrayDeque<PlayerChunk>() {
@@ -50,6 +50,8 @@ public abstract class ChunkMapDistance {
private final Executor m;
private long currentTick;
@ -27,7 +27,7 @@ index 534bb87caf88f0f1bf7988494274b762ab7210e1..b98abed74f214932b4a226f12645f987
protected ChunkMapDistance(Executor executor, Executor executor1) {
executor1.getClass();
Mailbox<Runnable> mailbox = Mailbox.a("player ticket throttler", executor1::execute);
@@ -85,7 +87,7 @@ public abstract class ChunkMapDistance {
@@ -94,7 +96,7 @@ public abstract class ChunkMapDistance {
protected abstract PlayerChunk a(long i, int j, @Nullable PlayerChunk playerchunk, int k);
public boolean a(PlayerChunkMap playerchunkmap) {
@ -36,7 +36,7 @@ index 534bb87caf88f0f1bf7988494274b762ab7210e1..b98abed74f214932b4a226f12645f987
this.g.a();
int i = Integer.MAX_VALUE - this.e.a(Integer.MAX_VALUE);
boolean flag = i != 0;
@@ -219,7 +221,7 @@ public abstract class ChunkMapDistance {
@@ -230,7 +232,7 @@ public abstract class ChunkMapDistance {
((ObjectSet) this.c.computeIfAbsent(i, (j) -> {
return new ObjectOpenHashSet();
})).add(entityplayer);
@ -45,7 +45,7 @@ index 534bb87caf88f0f1bf7988494274b762ab7210e1..b98abed74f214932b4a226f12645f987
this.g.b(i, 0, true);
}
@@ -231,7 +233,7 @@ public abstract class ChunkMapDistance {
@@ -242,7 +244,7 @@ public abstract class ChunkMapDistance {
objectset.remove(entityplayer);
if (objectset.isEmpty()) {
this.c.remove(i);
@ -54,7 +54,7 @@ index 534bb87caf88f0f1bf7988494274b762ab7210e1..b98abed74f214932b4a226f12645f987
this.g.b(i, Integer.MAX_VALUE, false);
}
@@ -255,13 +257,17 @@ public abstract class ChunkMapDistance {
@@ -266,13 +268,17 @@ public abstract class ChunkMapDistance {
}
public int b() {
@ -161,10 +161,10 @@ index 79c2187b7383336e7574709e6d4ad805e557976f..0560eca744cb2032bb6a3faf5aeafa95
super((World) worldserver, gameprofile);
playerinteractmanager.player = this;
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 3d610e41969768da0d2848fa1ae195035ccfd660..c4aad20a2952cc34e334ba665a6e0910d5609497 100644
index afc92dd031cdaf725b85c0b301d5a5a21da54720..6980d19f36c18cdbed6679dbdf04afd694e078b6 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -43,6 +43,18 @@ public class PlayerChunk {
@@ -44,6 +44,18 @@ public class PlayerChunk {
long lastAutoSaveTime; // Paper - incremental autosave
long inactiveTimeStart; // Paper - incremental autosave
@ -183,7 +183,7 @@ index 3d610e41969768da0d2848fa1ae195035ccfd660..c4aad20a2952cc34e334ba665a6e0910
public PlayerChunk(ChunkCoordIntPair chunkcoordintpair, int i, LightEngine lightengine, PlayerChunk.c playerchunk_c, PlayerChunk.d playerchunk_d) {
this.statusFutures = new AtomicReferenceArray(PlayerChunk.CHUNK_STATUSES.size());
this.fullChunkFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
@@ -59,6 +71,7 @@ public class PlayerChunk {
@@ -60,6 +72,7 @@ public class PlayerChunk {
this.n = this.oldTicketLevel;
this.a(i);
this.chunkMap = (PlayerChunkMap)playerchunk_d; // Paper

View File

@ -79,10 +79,10 @@ index 750fb07756f7e40b21f8ab0925f2e842aae50f7b..8c1f3290d23795b58a30274c9437dc7d
public final boolean areNeighboursLoaded(final int radius) {
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
index b98abed74f214932b4a226f12645f987191b0097..716d4eab382244ee9bc4855bf0f026e65ec057d6 100644
index 353b186060b2c0417a49ab3865ea5972c859b016..586a20fe5c77c2ad5fa26f337a94a16e21d8b5e2 100644
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
@@ -252,7 +252,7 @@ public abstract class ChunkMapDistance {
@@ -263,7 +263,7 @@ public abstract class ChunkMapDistance {
return s;
}
@ -91,7 +91,7 @@ index b98abed74f214932b4a226f12645f987191b0097..716d4eab382244ee9bc4855bf0f026e6
this.g.a(i);
}
@@ -371,7 +371,7 @@ public abstract class ChunkMapDistance {
@@ -382,7 +382,7 @@ public abstract class ChunkMapDistance {
private void a(long i, int j, boolean flag, boolean flag1) {
if (flag != flag1) {
@ -114,20 +114,10 @@ index 0560eca744cb2032bb6a3faf5aeafa95a7a6815e..07a6fc3d88e7d44bfab7f3d6a0eef7dc
super((World) worldserver, gameprofile);
playerinteractmanager.player = this;
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index c4aad20a2952cc34e334ba665a6e0910d5609497..845e5d2a8ee025ac61cf916de04e0797e32db568 100644
index 6980d19f36c18cdbed6679dbdf04afd694e078b6..03fb688fe4bdc19b4bc36b1f1d5b40c61e7bef9b 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -47,14 +47,28 @@ public class PlayerChunk {
// cached here to avoid a map lookup
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> playersInMobSpawnRange;
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> playersInChunkTickRange;
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> playersInTickingRange;
void updateRanges() {
long key = net.minecraft.server.MCUtil.getCoordinateKey(this.location);
this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
+ this.playersInTickingRange = this.chunkMap.playerViewDistanceTickMap.getObjectsInRange(key);
@@ -56,6 +56,18 @@ public class PlayerChunk {
}
// Paper end - optimise isOutsideOfRange
@ -146,7 +136,7 @@ index c4aad20a2952cc34e334ba665a6e0910d5609497..845e5d2a8ee025ac61cf916de04e0797
public PlayerChunk(ChunkCoordIntPair chunkcoordintpair, int i, LightEngine lightengine, PlayerChunk.c playerchunk_c, PlayerChunk.d playerchunk_d) {
this.statusFutures = new AtomicReferenceArray(PlayerChunk.CHUNK_STATUSES.size());
this.fullChunkFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
@@ -210,7 +224,7 @@ public class PlayerChunk {
@@ -211,7 +223,7 @@ public class PlayerChunk {
}
public void a(int i, int j, int k) {
@ -155,7 +145,7 @@ index c4aad20a2952cc34e334ba665a6e0910d5609497..845e5d2a8ee025ac61cf916de04e0797
if (chunk != null) {
this.r |= 1 << (j >> 4);
@@ -230,7 +244,7 @@ public class PlayerChunk {
@@ -231,7 +243,7 @@ public class PlayerChunk {
}
public void a(EnumSkyBlock enumskyblock, int i) {
@ -164,7 +154,7 @@ index c4aad20a2952cc34e334ba665a6e0910d5609497..845e5d2a8ee025ac61cf916de04e0797
if (chunk != null) {
chunk.setNeedsSaving(true);
@@ -315,9 +329,48 @@ public class PlayerChunk {
@@ -316,9 +328,48 @@ public class PlayerChunk {
}
private void a(Packet<?> packet, boolean flag) {

View File

@ -7,10 +7,10 @@ This lets you run /paper fixlight <chunkRadius> (max 5) to automatically
fix all light data in the chunks.
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..beb50f78e8b2f79d45e2e7fdc932e947138be7aa 100644
index 182b440ba4802d199b8e44f7779b3401ace495d5..10b72083322b7f8e3e14525b3e834f5374ec369d 100644
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
@@ -19,6 +19,7 @@ import org.bukkit.command.Command;
@@ -20,6 +20,7 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
@ -18,24 +18,24 @@ index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..beb50f78e8b2f79d45e2e7fdc932e947
import org.bukkit.entity.Player;
import java.io.File;
@@ -35,14 +36,14 @@ public class PaperCommand extends Command {
@@ -36,14 +37,14 @@ public class PaperCommand extends Command {
public PaperCommand(String name) {
super(name);
this.description = "Paper related commands";
- this.usageMessage = "/paper [heap | entity | reload | version | debug | chunkinfo | syncloadinfo]";
+ this.usageMessage = "/paper [heap | entity | reload | version | debug | chunkinfo | syncloadinfo | fixlight]";
- this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo | syncloadinfo]";
+ this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo | syncloadinfo | fixlight]";
this.setPermission("bukkit.command.paper");
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
if (args.length <= 1)
- return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "chunkinfo", "syncloadinfo");
+ return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "chunkinfo", "syncloadinfo", "fixlight");
- return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo", "syncloadinfo");
+ return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo", "syncloadinfo", "fixlight");
switch (args[0].toLowerCase(Locale.ENGLISH))
{
@@ -140,6 +141,9 @@ public class PaperCommand extends Command {
@@ -144,6 +145,9 @@ public class PaperCommand extends Command {
case "syncloadinfo":
this.doSyncLoadInfo(sender, args);
break;
@ -45,7 +45,7 @@ index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..beb50f78e8b2f79d45e2e7fdc932e947
case "ver":
case "version":
Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
@@ -156,6 +160,75 @@ public class PaperCommand extends Command {
@@ -160,6 +164,75 @@ public class PaperCommand extends Command {
return true;
}
@ -122,10 +122,10 @@ index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..beb50f78e8b2f79d45e2e7fdc932e947
if (!SyncLoadFinder.ENABLED) {
sender.sendMessage(ChatColor.RED + "This command requires the server startup flag '-Dpaper.debug-sync-loads=true' to be set.");
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 845e5d2a8ee025ac61cf916de04e0797e32db568..9e95c6b54f0855ddde6db6bd3e768e87fee6c21a 100644
index 03fb688fe4bdc19b4bc36b1f1d5b40c61e7bef9b..aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -328,6 +328,7 @@ public class PlayerChunk {
@@ -327,6 +327,7 @@ public class PlayerChunk {
}

View File

@ -22,20 +22,68 @@ view distance holds on you.
Chunks in front of the player have higher priority, to help with
fast traveling players keep up with their movement.
diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
index d9580eb998801edd34c610ced3f82f9627c6685b..537a22b72aa2c90f0102b035843e09c54e5ae39f 100644
--- a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
+++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
@@ -4,7 +4,10 @@ import com.destroystokyo.paper.io.PaperFileIOThread;
import com.destroystokyo.paper.io.IOUtil;
import com.destroystokyo.paper.io.PrioritizedTaskQueue;
import com.destroystokyo.paper.io.QueueExecutorThread;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import net.minecraft.server.ChunkCoordIntPair;
import net.minecraft.server.ChunkRegionLoader;
+import net.minecraft.server.ChunkStatus;
import net.minecraft.server.IAsyncTaskHandler;
import net.minecraft.server.IChunkAccess;
import net.minecraft.server.MinecraftServer;
@@ -118,6 +121,32 @@ public final class ChunkTaskManager {
PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Status - " + ((chunk == null) ? "null chunk" : chunk.getChunkStatus().toString()));
PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Ticket Status - " + PlayerChunk.getChunkStatus(chunkHolder.getTicketLevel()));
PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Holder Status - " + ((holderStatus == null) ? "null" : holderStatus.toString()));
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Holder Priority - " + chunkHolder.getCurrentPriority());
+ synchronized (chunkHolder.neighborPriorities) {
+ if (!chunkHolder.neighborPriorities.isEmpty()) {
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Neighbors Requested Priority: ");
+ for (Long2ObjectMap.Entry<Integer> entry : chunkHolder.neighborPriorities.long2ObjectEntrySet()) {
+ ChunkCoordIntPair r = new ChunkCoordIntPair(entry.getLongKey());
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + " (" + r.x + "," + r.z + "): " + entry.getValue());
+ }
+ }
+ }
+
+ synchronized (chunkHolder.neighbors) {
+ if (!chunkHolder.neighbors.isEmpty()) {
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Neighbors: ");
+ for (PlayerChunk neighbor : chunkHolder.neighbors.keySet()) {
+ ChunkStatus status = neighbor.getChunkHolderStatus();
+ if (status != null && status.isAtLeastStatus(PlayerChunk.getChunkStatus(neighbor.getTicketLevel()))) {
+ continue;
+ }
+ int nx = neighbor.location.x;
+ int nz = neighbor.location.z;
+ PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + " " + nx + "," + nz + " in " + chunkHolder.getWorld().getWorld().getName() + ":");
+ dumpChunkInfo(neighbor, nx, nz, indent + 1);
+ }
+ }
+ }
}
}
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
index 716d4eab382244ee9bc4855bf0f026e65ec057d6..20052dcbc71899165ac99801fa9f7753672ba997 100644
index 586a20fe5c77c2ad5fa26f337a94a16e21d8b5e2..58407f488bbd8bda8781959d7c9da5d09f2a3cc4 100644
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
@@ -143,7 +143,7 @@ public abstract class ChunkMapDistance {
@@ -154,7 +154,7 @@ public abstract class ChunkMapDistance {
Ticket<?> ticket1 = (Ticket) arraysetsorted.a(ticket); // CraftBukkit - decompile error
ticket1.a(this.currentTick);
- if (ticket.b() < j) {
+ if (ticket.b() < j || (ticket.getTicketType() == TicketType.PRIORITY && ((Ticket<Integer>) ticket).getObjectReason() < j)) { // Paper - check priority tickets too
+ if (ticket.b() < j || (ticket.getTicketType() == TicketType.PRIORITY && (30 - ticket.priority) < j)) { // Paper - check priority tickets too
this.e.b(i, ticket.b(), true);
}
@@ -171,6 +171,48 @@ public abstract class ChunkMapDistance {
@@ -182,6 +182,54 @@ public abstract class ChunkMapDistance {
this.addTicketAtLevel(tickettype, chunkcoordintpair, i, t0);
}
@ -45,8 +93,15 @@ index 716d4eab382244ee9bc4855bf0f026e65ec057d6..20052dcbc71899165ac99801fa9f7753
+ }
+ public boolean markHighPriority(ChunkCoordIntPair coords, int priority) {
+ priority = Math.min(30, Math.max(1, priority));
+ Ticket<Integer> ticket = new Ticket<Integer>(TicketType.PRIORITY, 31, priority);
+ return this.addTicket(coords.pair(), ticket);
+ long pair = coords.pair();
+ int currentPriority = getChunkPriority(coords);
+ if (currentPriority > priority) {
+ return false;
+ }
+ Ticket<Integer> ticket = new Ticket<Integer>(TicketType.PRIORITY, 31, 0);
+ ticket.priority = priority;
+ this.removeTicket(pair, ticket);
+ return this.addTicket(pair, ticket);
+ }
+ public int getChunkPriority(ChunkCoordIntPair coords) {
+ int priority = 0;
@ -55,36 +110,35 @@ index 716d4eab382244ee9bc4855bf0f026e65ec057d6..20052dcbc71899165ac99801fa9f7753
+ return priority;
+ }
+ for (Ticket<?> ticket : tickets) {
+ if (ticket.getTicketType() != TicketType.PRIORITY) {
+ continue;
+ }
+ //noinspection unchecked
+ Ticket<Integer> prioTicket = (Ticket<Integer>) ticket;
+ if (prioTicket.getObjectReason() > priority) {
+ priority = prioTicket.getObjectReason();
+ if (ticket.getTicketType() == TicketType.PRIORITY && ticket.priority > 0) {
+ return ticket.priority;
+ }
+ }
+ return priority;
+ }
+ public void clearPriorityTickets(ChunkCoordIntPair coords) {
+
+ public void refreshUrgentTicket(ChunkCoordIntPair coords) {
+ ArraySetSorted<Ticket<?>> tickets = this.tickets.get(coords.pair());
+ java.util.List<Ticket<?>> toRemove = new java.util.ArrayList<>();
+ if (tickets == null) return;
+ if (tickets == null) {
+ markUrgent(coords);
+ return;
+ }
+ for (Ticket<?> ticket : tickets) {
+ if (ticket.getTicketType() == TicketType.PRIORITY) {
+ toRemove.add(ticket);
+ ticket.setCurrentTick(this.currentTick);
+ return;
+ }
+ }
+ for (Ticket<?> ticket : toRemove) {
+ this.removeTicket(coords.pair(), ticket);
+ }
+
+ }
+ public void clearPriorityTickets(ChunkCoordIntPair coords) {
+ this.removeTicket(coords.pair(), new Ticket<Integer>(TicketType.PRIORITY, 31, 0));
+ }
+ // Paper end
public <T> boolean addTicketAtLevel(TicketType<T> ticketType, ChunkCoordIntPair chunkcoordintpair, int level, T identifier) {
return this.addTicket(chunkcoordintpair.pair(), new Ticket<>(ticketType, level, identifier));
// CraftBukkit end
@@ -386,7 +428,8 @@ public abstract class ChunkMapDistance {
@@ -397,7 +445,8 @@ public abstract class ChunkMapDistance {
});
}, i, () -> {
@ -95,7 +149,7 @@ index 716d4eab382244ee9bc4855bf0f026e65ec057d6..20052dcbc71899165ac99801fa9f7753
} else {
ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 0a99b347d8497f097ef1da6560a5d0adc1374f25..d6f629d45e05167c22b6cd08a9709809a32b15a1 100644
index 0a99b347d8497f097ef1da6560a5d0adc1374f25..e57e4c739b86646ef148c1f8e06ca160dbc778a1 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -431,6 +431,16 @@ public class ChunkProviderServer extends IChunkProvider {
@ -115,7 +169,7 @@ index 0a99b347d8497f097ef1da6560a5d0adc1374f25..d6f629d45e05167c22b6cd08a9709809
// Paper end
@Nullable
@@ -469,6 +479,8 @@ public class ChunkProviderServer extends IChunkProvider {
@@ -469,14 +479,22 @@ public class ChunkProviderServer extends IChunkProvider {
if (!completablefuture.isDone()) { // Paper
// Paper start - async chunk io/loading
@ -124,15 +178,22 @@ index 0a99b347d8497f097ef1da6560a5d0adc1374f25..d6f629d45e05167c22b6cd08a9709809
this.world.asyncChunkTaskManager.raisePriority(x, z, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY);
com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.world, x, z);
// Paper end
@@ -477,6 +489,7 @@ public class ChunkProviderServer extends IChunkProvider {
this.serverThreadQueue.awaitTasks(completablefuture::isDone);
com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.world, x, z); // Paper - sync load info
this.world.timings.syncChunkLoad.startTiming(); // Paper
- this.serverThreadQueue.awaitTasks(completablefuture::isDone);
+ // Paper start - keep priority ticket refreshed
+ this.serverThreadQueue.awaitTasks(() -> {
+ this.chunkMapDistance.refreshUrgentTicket(pair);
+ return completablefuture.isDone();
+ });
+ // PAper end
com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug
this.world.timings.syncChunkLoad.stopTiming(); // Paper
+ this.clearPriorityTickets(pair); // Paper
} // Paper
ichunkaccess = (IChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> {
return ichunkaccess1;
@@ -529,6 +542,7 @@ public class ChunkProviderServer extends IChunkProvider {
@@ -529,6 +547,7 @@ public class ChunkProviderServer extends IChunkProvider {
if (flag && !currentlyUnloading) {
// CraftBukkit end
this.chunkMapDistance.a(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
@ -140,7 +201,7 @@ index 0a99b347d8497f097ef1da6560a5d0adc1374f25..d6f629d45e05167c22b6cd08a9709809
if (this.a(playerchunk, l)) {
GameProfilerFiller gameprofilerfiller = this.world.getMethodProfiler();
@@ -541,8 +555,13 @@ public class ChunkProviderServer extends IChunkProvider {
@@ -541,8 +560,13 @@ public class ChunkProviderServer extends IChunkProvider {
}
}
}
@ -181,26 +242,36 @@ index d129c7f54d9f65fff6f512d8ff5f1c3866632603..9b9536fba4a62c0153b921e678e6a968
chunkData.addProperty("queued-for-unload", chunkMap.unloadQueue.contains(playerChunk.location.pair()));
chunkData.addProperty("status", status == null ? "unloaded" : status.toString());
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 9e95c6b54f0855ddde6db6bd3e768e87fee6c21a..44721a4f446bdd5bf4575e4168a0570afd71c4d4 100644
index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..46462298c7d02fcf31bb8da502a3ee5d98fe7905 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -25,7 +25,7 @@ public class PlayerChunk {
@@ -26,8 +26,8 @@ public class PlayerChunk {
private CompletableFuture<IChunkAccess> chunkSave;
public int oldTicketLevel;
private int ticketLevel;
- private int n;
+ private int n; public final int getCurrentPriority() { return n; } // Paper - OBFHELPER
final ChunkCoordIntPair location; // Paper - private -> package
- final ChunkCoordIntPair location; // Paper - private -> package
+ volatile int n; public final int getCurrentPriority() { return n; } // Paper - OBFHELPER - make volatile since this is concurrently accessed
+ public final ChunkCoordIntPair location; // Paper - private -> public
private final short[] dirtyBlocks;
private int dirtyCount;
@@ -68,6 +68,92 @@ public class PlayerChunk {
private int r;
@@ -40,6 +40,7 @@ public class PlayerChunk {
private boolean hasBeenLoaded;
private final PlayerChunkMap chunkMap; // Paper
+ public WorldServer getWorld() { return chunkMap.world; } // Paper
long lastAutoSaveTime; // Paper - incremental autosave
long inactiveTimeStart; // Paper - incremental autosave
@@ -67,6 +68,92 @@ public class PlayerChunk {
return null;
}
// Paper end - no-tick view distance
+ // Paper start - Chunk gen/load priority system
+ volatile int neighborPriority = -1;
+ final java.util.concurrent.ConcurrentHashMap<PlayerChunk, Integer> neighbors = new java.util.concurrent.ConcurrentHashMap<>();
+ final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<Integer> neighborPriorities = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
+ public final java.util.concurrent.ConcurrentHashMap<PlayerChunk, ChunkStatus> neighbors = new java.util.concurrent.ConcurrentHashMap<>();
+ public final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<Integer> neighborPriorities = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
+
+ public int getPreferredPriority() {
+ int priority = neighborPriority; // if we have a neighbor priority, use it
@ -221,10 +292,10 @@ index 9e95c6b54f0855ddde6db6bd3e768e87fee6c21a..44721a4f446bdd5bf4575e4168a0570a
+ return Math.max(1, Math.min(PlayerChunkMap.GOLDEN_TICKET, priority));
+ }
+ public void onNeighborRequest(PlayerChunk neighbor, ChunkStatus status) {
+ int currentPriority = getCurrentPriority();
+ if (!neighborPriorities.containsKey(neighbor.location.pair()) && (neighbor.neighborPriority == -1 || neighbor.neighborPriority > currentPriority)) {
+ this.neighbors.put(neighbor, currentPriority);
+ neighbor.setNeighborPriority(this, Math.max(1, currentPriority));
+ int priority = getCurrentPriority() + 1;
+ if (!neighborPriorities.containsKey(neighbor.location.pair()) && (neighbor.neighborPriority == -1 || neighbor.neighborPriority > priority)) {
+ this.neighbors.put(neighbor, status);
+ neighbor.setNeighborPriority(this, Math.max(1, priority));
+ }
+ }
+
@ -286,7 +357,7 @@ index 9e95c6b54f0855ddde6db6bd3e768e87fee6c21a..44721a4f446bdd5bf4575e4168a0570a
public PlayerChunk(ChunkCoordIntPair chunkcoordintpair, int i, LightEngine lightengine, PlayerChunk.c playerchunk_c, PlayerChunk.d playerchunk_d) {
this.statusFutures = new AtomicReferenceArray(PlayerChunk.CHUNK_STATUSES.size());
@@ -166,6 +252,12 @@ public class PlayerChunk {
@@ -165,6 +252,12 @@ public class PlayerChunk {
}
return null;
}
@ -299,26 +370,15 @@ index 9e95c6b54f0855ddde6db6bd3e768e87fee6c21a..44721a4f446bdd5bf4575e4168a0570a
// Paper end
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFutureUnchecked(ChunkStatus chunkstatus) {
@@ -419,8 +511,18 @@ public class PlayerChunk {
@@ -418,6 +511,7 @@ public class PlayerChunk {
return this.n;
}
+ private void setPriority(int i) { d(i); } // Paper - OBFHELPER
private void d(int i) {
+ if (i == n) return; // Paper
this.n = i;
+ // Paper start
+ this.neighbors.keySet().forEach(neighbor -> {
+ if (neighbor.getCurrentPriority() > i) {
+ neighbor.setNeighborPriority(this, i);
+ this.w.changePriority(neighbor.location, neighbor::getCurrentPriority, neighbor.getCurrentPriority(), neighbor::setPriority);
+ }
+ });
+ // Paper end
}
public void a(int i) {
@@ -508,6 +610,7 @@ public class PlayerChunk {
@@ -507,6 +601,7 @@ public class PlayerChunk {
Chunk fullChunk = either.left().get();
PlayerChunk.this.isFullChunkReady = true;
fullChunk.playerChunk = PlayerChunk.this;
@ -326,16 +386,40 @@ index 9e95c6b54f0855ddde6db6bd3e768e87fee6c21a..44721a4f446bdd5bf4575e4168a0570a
}
@@ -583,7 +686,7 @@ public class PlayerChunk {
@@ -581,8 +676,30 @@ public class PlayerChunk {
this.entityTickingFuture.complete(PlayerChunk.UNLOADED_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage
this.entityTickingFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
}
-
- this.w.a(this.location, this::k, this.ticketLevel, this::d);
+ this.w.a(this.location, this::k, getPreferredPriority(), this::d); // Paper - preferred priority
+ // Paper start - raise IO/load priority if priority changes, use our preferred priority
+ int priority = getPreferredPriority();
+ if (getCurrentPriority() > priority) {
+ int ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY;
+ if (priority <= 10) {
+ ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY;
+ } else if (priority <= 20) {
+ ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY;
+ }
+ chunkMap.world.asyncChunkTaskManager.raisePriority(location.x, location.z, ioPriority);
+ }
+ this.w.a(this.location, this::getCurrentPriority, priority, this::setPriority); // use preferred priority
+ this.neighbors.forEach((neighbor, neighborDesired) -> {
+ ChunkStatus neighborCurrent = neighbor.getChunkHolderStatus();
+ if (neighborCurrent == null || !neighborCurrent.isAtLeastStatus(neighborDesired)) {
+ if (neighbor.getCurrentPriority() > priority + 1 && neighbor.neighborPriority > priority + 1) {
+ neighbor.setNeighborPriority(this, priority + 1);
+ // Pending chunk update will run this same code here for the neighbor to update their priority
+ // And since we are in the poll loop when this method runs, it should happen immediately after this.
+ chunkMap.chunkDistanceManager.pendingChunkUpdates.add(neighbor);
+ }
+ }
+ });
+ // Paper end
this.oldTicketLevel = this.ticketLevel;
// CraftBukkit start
// ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins.
@@ -670,6 +773,7 @@ public class PlayerChunk {
@@ -669,6 +786,7 @@ public class PlayerChunk {
public interface c {
@ -489,6 +573,26 @@ index e772095e1c44842f743661a326c2a9a8a677ab02..5621416660d2722f26582fcecd5b61a1
});
}
diff --git a/src/main/java/net/minecraft/server/Ticket.java b/src/main/java/net/minecraft/server/Ticket.java
index 7a8397815a5b7f79f3e3a0348aeedf63fe879f8f..a7cd67b0d5e49a4492dc14ec80e442a0f32671d3 100644
--- a/src/main/java/net/minecraft/server/Ticket.java
+++ b/src/main/java/net/minecraft/server/Ticket.java
@@ -8,6 +8,7 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
private final int b;
public final T identifier; public final T getObjectReason() { return this.identifier; } // Paper - OBFHELPER
private long d; public final long getCreationTick() { return this.d; } // Paper - OBFHELPER
+ public int priority = 0; // Paper
protected Ticket(TicketType<T> tickettype, int i, T t0) {
this.a = tickettype;
@@ -56,6 +57,7 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
return this.b;
}
+ protected final void setCurrentTick(long i) { a(i); } // Paper - OBFHELPER
protected void a(long i) {
this.d = i;
}
diff --git a/src/main/java/net/minecraft/server/TicketType.java b/src/main/java/net/minecraft/server/TicketType.java
index 8055f5998213ab1c6c10d03d88d2b14d220a5e40..4913205c15a2b6d5ea058890b02090b494e9c177 100644
--- a/src/main/java/net/minecraft/server/TicketType.java