Fix many chunk loading issues
Fixes a few various issues with chunk ticket state restores mojangs ticket throttle but tries to be smarter about it. fixes a few state mismatches that needed to be handled. Fixes fake NPC's adding player tickets when they shouldn't have been. Improves teleport chunk loading by processing high priority on new area Fixes #3605 Fixes #3537 Fixes #3573
This commit is contained in:
parent
7c419073e4
commit
1c5229f4e4
1 changed files with 152 additions and 47 deletions
|
@ -101,6 +101,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
|
|
||||||
public abstract class ChunkMapDistance {
|
public abstract class ChunkMapDistance {
|
||||||
|
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
||||||
|
private final ChunkTaskQueueSorter i;
|
||||||
|
private final Mailbox<ChunkTaskQueueSorter.a<Runnable>> j;
|
||||||
|
private final Mailbox<ChunkTaskQueueSorter.b> k;
|
||||||
|
- private final LongSet l = new LongOpenHashSet();
|
||||||
|
+ private final LongSet l = new LongOpenHashSet(); LongSet getOnPlayerTicketAddQueue() { return l; } // Paper - OBFHELPER
|
||||||
|
private final Executor m;
|
||||||
|
private long currentTick;
|
||||||
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +190,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+
|
+
|
||||||
+ public void markAreaHighPriority(ChunkCoordIntPair center, int priority, int radius) {
|
+ public void markAreaHighPriority(ChunkCoordIntPair center, int priority, int radius) {
|
||||||
+ delayDistanceManagerTick = true;
|
+ delayDistanceManagerTick = true;
|
||||||
|
+ priority = Math.min(URGENT_PRIORITY - 1, Math.max(1, priority));
|
||||||
|
+ int finalPriority = priority;
|
||||||
+ MCUtil.getSpiralOutChunks(center.asPosition(), radius).forEach(coords -> {
|
+ MCUtil.getSpiralOutChunks(center.asPosition(), radius).forEach(coords -> {
|
||||||
+ addPriorityTicket(coords, TicketType.PRIORITY, priority);
|
+ addPriorityTicket(coords, TicketType.PRIORITY, finalPriority);
|
||||||
+ });
|
+ });
|
||||||
+ delayDistanceManagerTick = false;
|
+ delayDistanceManagerTick = false;
|
||||||
+ chunkMap.world.getChunkProvider().tickDistanceManager();
|
+ chunkMap.world.getChunkProvider().tickDistanceManager();
|
||||||
|
@ -197,17 +208,37 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ chunkMap.world.getChunkProvider().tickDistanceManager();
|
+ chunkMap.world.getChunkProvider().tickDistanceManager();
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ private boolean hasPlayerTicket(ChunkCoordIntPair coords, int level) {
|
||||||
|
+ ArraySetSorted<Ticket<?>> tickets = this.tickets.get(coords.pair());
|
||||||
|
+ if (tickets == null || tickets.isEmpty()) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ for (Ticket<?> ticket : tickets) {
|
||||||
|
+ if (ticket.getTicketType() == TicketType.PLAYER && ticket.getTicketLevel() == level) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ private boolean addPriorityTicket(ChunkCoordIntPair coords, TicketType<ChunkCoordIntPair> ticketType, int priority) {
|
+ private boolean addPriorityTicket(ChunkCoordIntPair coords, TicketType<ChunkCoordIntPair> ticketType, int priority) {
|
||||||
+ AsyncCatcher.catchOp("ChunkMapDistance::addPriorityTicket");
|
+ AsyncCatcher.catchOp("ChunkMapDistance::addPriorityTicket");
|
||||||
+ long pair = coords.pair();
|
+ long pair = coords.pair();
|
||||||
+ PlayerChunk chunk = chunkMap.getUpdatingChunk(pair);
|
+ PlayerChunk chunk = chunkMap.getUpdatingChunk(pair);
|
||||||
+ if (chunk != null && chunk.isFullChunkReady() && chunk.getTicketLevel() <= 33) {
|
+ boolean needsTicket = chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(pair) != null && !hasPlayerTicket(coords, 33);
|
||||||
+ return false;
|
+
|
||||||
+ }
|
+ if (needsTicket) {
|
||||||
+ if (chunk != null && chunk.getTicketLevel() > 33 && chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(pair) != null) {
|
|
||||||
+ Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, coords);
|
+ Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, coords);
|
||||||
|
+ getOnPlayerTicketAddQueue().add(pair);
|
||||||
+ addTicket(pair, ticket);
|
+ addTicket(pair, ticket);
|
||||||
+ }
|
+ }
|
||||||
|
+ if ((chunk != null && chunk.isFullChunkReady())) {
|
||||||
|
+ if (needsTicket) {
|
||||||
|
+ chunkMap.world.getChunkProvider().tickDistanceManager();
|
||||||
|
+ }
|
||||||
|
+ return needsTicket;
|
||||||
|
+ }
|
||||||
+
|
+
|
||||||
+ boolean success;
|
+ boolean success;
|
||||||
+ if (!(success = updatePriorityTicket(coords, ticketType, priority))) {
|
+ if (!(success = updatePriorityTicket(coords, ticketType, priority))) {
|
||||||
|
@ -278,37 +309,58 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
return this.addTicket(chunkcoordintpair.pair(), new Ticket<>(ticketType, level, identifier));
|
return this.addTicket(chunkcoordintpair.pair(), new Ticket<>(ticketType, level, identifier));
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
||||||
Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkCoordIntPair(i)); // Paper - no-tick view distance
|
|
||||||
|
private void a(long i, int j, boolean flag, boolean flag1) {
|
||||||
|
if (flag != flag1) {
|
||||||
|
- Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkCoordIntPair(i)); // Paper - no-tick view distance
|
||||||
|
+ ChunkCoordIntPair coords = new ChunkCoordIntPair(i); // Paper
|
||||||
|
+ Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, coords); // Paper - no-tick view distance
|
||||||
|
|
||||||
if (flag1) {
|
if (flag1) {
|
||||||
- ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
|
+ scheduleChunkLoad(i, MinecraftServer.currentTick, j, (priority) -> { // Paper - smarter ticket delay based on frustum and distance
|
||||||
- ChunkMapDistance.this.m.execute(() -> {
|
+ // Paper start - recheck its still valid if not cancel
|
||||||
- if (this.c(this.c(i))) {
|
+ if (!isChunkInRange(i)) {
|
||||||
+ // Paper start - smarter ticket delay based on frustum and distance
|
+ ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> {
|
||||||
+ scheduleChunkLoad(i, MinecraftServer.currentTick, j, (priority) -> {
|
+ ChunkMapDistance.this.m.execute(() -> {
|
||||||
+ //ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
|
+ ChunkMapDistance.this.removeTicket(i, ticket);
|
||||||
+ if (this.c(this.c(i))) { // Copy c(c()) stuff below
|
+ ChunkMapDistance.this.clearPriorityTickets(coords);
|
||||||
|
+ });
|
||||||
|
+ }, i, false));
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // abort early if we got a ticket already
|
||||||
|
+ if (hasPlayerTicket(coords, 33)) return;
|
||||||
|
+ // skip player ticket throttle for near chunks
|
||||||
|
+ if (priority <= 3) {
|
||||||
|
+ ChunkMapDistance.this.addTicket(i, ticket);
|
||||||
|
+ ChunkMapDistance.this.l.add(i);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
|
ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
|
||||||
|
ChunkMapDistance.this.m.execute(() -> {
|
||||||
|
- if (this.c(this.c(i))) {
|
||||||
|
+ if (isChunkInRange(i)) { if (!hasPlayerTicket(coords, 33)) { // Paper - high priority might of already added it
|
||||||
ChunkMapDistance.this.addTicket(i, ticket);
|
ChunkMapDistance.this.addTicket(i, ticket);
|
||||||
ChunkMapDistance.this.l.add(i);
|
ChunkMapDistance.this.l.add(i);
|
||||||
} else {
|
- } else {
|
||||||
|
+ }
|
||||||
|
+ } else { // Paper
|
||||||
ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
|
ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
|
||||||
}, i, false));
|
}, i, false));
|
||||||
}
|
}
|
||||||
-
|
|
||||||
- });
|
});
|
||||||
- }, i, () -> {
|
}, i, () -> {
|
||||||
- return j;
|
- return j;
|
||||||
- }));
|
+ return Math.min(PlayerChunkMap.GOLDEN_TICKET, priority); // Paper
|
||||||
+ //}, i, () -> {
|
}));
|
||||||
+ //return Math.min(PlayerChunkMap.GOLDEN_TICKET, (priority <= 6 ? 20 : 30) + priority); // Paper - delay new ticket adds to avoid spamming the queue
|
|
||||||
+ //})); // Paper
|
|
||||||
+ }); // Paper
|
+ }); // Paper
|
||||||
} else {
|
} else {
|
||||||
ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
|
ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
|
||||||
ChunkMapDistance.this.m.execute(() -> {
|
ChunkMapDistance.this.m.execute(() -> {
|
||||||
ChunkMapDistance.this.removeTicket(i, ticket);
|
ChunkMapDistance.this.removeTicket(i, ticket);
|
||||||
+ ChunkMapDistance.this.clearPriorityTickets(new ChunkCoordIntPair(i)); // Paper
|
+ ChunkMapDistance.this.clearPriorityTickets(coords); // Paper
|
||||||
});
|
});
|
||||||
}, i, true));
|
}, i, true));
|
||||||
}
|
}
|
||||||
|
@ -317,11 +369,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // Paper start - smart scheduling of player tickets
|
+ // Paper start - smart scheduling of player tickets
|
||||||
|
+ private boolean isChunkInRange(long i) {
|
||||||
|
+ return this.isLoadedChunkLevel(this.getChunkLevel(i));
|
||||||
|
+ }
|
||||||
+ public void scheduleChunkLoad(long i, long startTick, int initialDistance, java.util.function.Consumer<Integer> task) {
|
+ public void scheduleChunkLoad(long i, long startTick, int initialDistance, java.util.function.Consumer<Integer> task) {
|
||||||
+ long elapsed = MinecraftServer.currentTick - startTick;
|
+ long elapsed = MinecraftServer.currentTick - startTick;
|
||||||
+ ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(i);
|
+ ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(i);
|
||||||
+ PlayerChunk updatingChunk = chunkMap.getUpdatingChunk(i);
|
+ PlayerChunk updatingChunk = chunkMap.getUpdatingChunk(i);
|
||||||
+ if ((updatingChunk != null && updatingChunk.isFullChunkReady()) || !this.c(this.c(i)) || getChunkPriority(chunkPos) > 0) { // Copied from above
|
+ if ((updatingChunk != null && updatingChunk.isFullChunkReady()) || !isChunkInRange(i) || getChunkPriority(chunkPos) > 0) { // Copied from above
|
||||||
+ // no longer needed
|
+ // no longer needed
|
||||||
+ task.accept(1);
|
+ task.accept(1);
|
||||||
+ return;
|
+ return;
|
||||||
|
@ -355,8 +410,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+
|
+
|
||||||
+ double dist = Math.min(frontDist, center);
|
+ double dist = Math.min(frontDist, center);
|
||||||
+ if (!isFront) {
|
+ if (!isFront) {
|
||||||
+
|
+ ChunkCoordIntPair pointInBack = player.getChunkInFront(-7);
|
||||||
+ ChunkCoordIntPair pointInBack = player.getChunkInFront(-5);
|
|
||||||
+ pos.setValues(pointInBack.x << 4, 0, pointInBack.z << 4);
|
+ pos.setValues(pointInBack.x << 4, 0, pointInBack.z << 4);
|
||||||
+ double backDist = MCUtil.distanceSq(pos, blockPos);
|
+ double backDist = MCUtil.distanceSq(pos, blockPos);
|
||||||
+ if (frontDist < backDist) {
|
+ if (frontDist < backDist) {
|
||||||
|
@ -375,8 +429,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ }
|
+ }
|
||||||
+ if (minDist > 4) {
|
+ if (minDist > 4) {
|
||||||
+ int desiredTimeDelayMax = isFront ?
|
+ int desiredTimeDelayMax = isFront ?
|
||||||
+ (minDist < 10 ? 10 : 20) : // Front
|
+ (minDist < 10 ? 7 : 15) : // Front
|
||||||
+ (minDist < 10 ? 20 : 40); // Back
|
+ (minDist < 10 ? 15 : 45); // Back
|
||||||
+ desireDelay += (desiredTimeDelayMax * 20) * (minDist / 32);
|
+ desireDelay += (desiredTimeDelayMax * 20) * (minDist / 32);
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
|
@ -389,7 +443,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ for (int x = -1; x <= 1; x++) {
|
+ for (int x = -1; x <= 1; x++) {
|
||||||
+ for (int z = -1; z <= 1; z++) {
|
+ for (int z = -1; z <= 1; z++) {
|
||||||
+ if (x == 0 && z == 0) continue;
|
+ if (x == 0 && z == 0) continue;
|
||||||
+ long pair = new ChunkCoordIntPair(chunkPos.x + x, chunkPos.z + z).pair();
|
+ long pair = ChunkCoordIntPair.pair(chunkPos.x + x, chunkPos.z + z);
|
||||||
+ PlayerChunk neighbor = chunkMap.getUpdatingChunk(pair);
|
+ PlayerChunk neighbor = chunkMap.getUpdatingChunk(pair);
|
||||||
+ ChunkStatus current = neighbor != null ? neighbor.getChunkHolderStatus() : null;
|
+ ChunkStatus current = neighbor != null ? neighbor.getChunkHolderStatus() : null;
|
||||||
+ if (current != null && current.isAtLeastStatus(ChunkStatus.LIGHT)) {
|
+ if (current != null && current.isAtLeastStatus(ChunkStatus.LIGHT)) {
|
||||||
|
@ -398,13 +452,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ if (!hasAnyNeighbor) {
|
+ if (!hasAnyNeighbor) {
|
||||||
+ delay += 10;
|
+ delay += 20;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ if (delay <= 0) {
|
+ if (delay <= 0) {
|
||||||
+ task.accept((int) minDist);
|
+ task.accept((int) minDist);
|
||||||
+ } else {
|
+ } else {
|
||||||
+ MCUtil.scheduleTask((int) Math.min(delay, minDist >= 10 ? 40 : (minDist < 6 ? 5 : 20)), () -> scheduleChunkLoad(i, startTick, initialDistance, task), "Player Ticket Delayer");
|
+ int taskDelay = (int) Math.min(delay, minDist >= 10 ? 40 : (minDist < 6 ? 5 : 20));
|
||||||
|
+ MCUtil.scheduleTask(taskDelay, () -> scheduleChunkLoad(i, startTick, initialDistance, task), "Player Ticket Delayer");
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
|
@ -412,6 +467,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
@Override
|
@Override
|
||||||
public void a() {
|
public void a() {
|
||||||
super.a();
|
super.a();
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
+ private boolean isLoadedChunkLevel(int i) { return c(i); } // Paper - OBFHELPER
|
||||||
|
private boolean c(int i) {
|
||||||
|
return i <= this.e - 2;
|
||||||
|
}
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
||||||
|
this.a.defaultReturnValue((byte) (i + 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
+ protected final int getChunkLevel(long i) { return c(i); } // Paper - OBFHELPER
|
||||||
|
@Override
|
||||||
|
protected int c(long i) {
|
||||||
|
return this.a.get(i);
|
||||||
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||||||
|
@ -509,6 +580,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
private int lastExpLevelScored = Integer.MIN_VALUE;
|
private int lastExpLevelScored = Integer.MIN_VALUE;
|
||||||
private int lastExpTotalScored = Integer.MIN_VALUE;
|
private int lastExpTotalScored = Integer.MIN_VALUE;
|
||||||
+ public long lastHighPriorityChecked; // Paper
|
+ public long lastHighPriorityChecked; // Paper
|
||||||
|
+ public void forceCheckHighPriority() {
|
||||||
|
+ lastHighPriorityChecked = -1;
|
||||||
|
+ getWorldServer().getChunkProvider().playerChunkMap.checkHighPriorityChunks(this);
|
||||||
|
+ }
|
||||||
|
+ public boolean isRealPlayer; // Paper
|
||||||
private float lastHealthSent = -1.0E8F;
|
private float lastHealthSent = -1.0E8F;
|
||||||
private int lastFoodSent = -99999999;
|
private int lastFoodSent = -99999999;
|
||||||
private boolean lastSentSaturationZero = true;
|
private boolean lastSentSaturationZero = true;
|
||||||
|
@ -538,7 +614,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
if (valid && (!this.isSpectator() || this.world.isLoaded(new BlockPosition(this)))) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
|
if (valid && (!this.isSpectator() || this.world.isLoaded(new BlockPosition(this)))) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
|
||||||
super.tick();
|
super.tick();
|
||||||
}
|
}
|
||||||
+ if (valid && isAlive()) ((WorldServer)world).getChunkProvider().playerChunkMap.checkHighPriorityChunks(this); // Paper
|
+ if (valid && isAlive() && playerConnection != null) ((WorldServer)world).getChunkProvider().playerChunkMap.checkHighPriorityChunks(this); // Paper
|
||||||
|
|
||||||
for (int i = 0; i < this.inventory.getSize(); ++i) {
|
for (int i = 0; i < this.inventory.getSize(); ++i) {
|
||||||
ItemStack itemstack = this.inventory.getItem(i);
|
ItemStack itemstack = this.inventory.getItem(i);
|
||||||
|
@ -709,7 +785,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ return CHUNK_STATUSES.get(status.getStatusIndex() + 1);
|
+ return CHUNK_STATUSES.get(status.getStatusIndex() + 1);
|
||||||
+ }
|
+ }
|
||||||
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFutureUncheckedMain(ChunkStatus chunkstatus) {
|
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFutureUncheckedMain(ChunkStatus chunkstatus) {
|
||||||
+ return MCUtil.ensureMain(getStatusFutureUnchecked(chunkstatus));
|
+ return ensureMain(getStatusFutureUnchecked(chunkstatus));
|
||||||
|
+ }
|
||||||
|
+ public <T> CompletableFuture<T> ensureMain(CompletableFuture<T> future) {
|
||||||
|
+ return future.thenApplyAsync(r -> r, chunkMap.mainInvokingExecutor);
|
||||||
+ }
|
+ }
|
||||||
// Paper end
|
// Paper end
|
||||||
|
|
||||||
|
@ -736,7 +815,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
// Paper start - cache ticking ready status
|
// Paper start - cache ticking ready status
|
||||||
int expectCreateCount = ++this.fullChunkCreateCount;
|
int expectCreateCount = ++this.fullChunkCreateCount;
|
||||||
- this.fullChunkFuture = playerchunkmap.b(this); this.fullChunkFuture.thenAccept((either) -> {
|
- this.fullChunkFuture = playerchunkmap.b(this); this.fullChunkFuture.thenAccept((either) -> {
|
||||||
+ this.fullChunkFuture = playerchunkmap.b(this); MCUtil.ensureMain(this.fullChunkFuture).thenAccept((either) -> { // Paper - ensure main
|
+ this.fullChunkFuture = playerchunkmap.b(this); ensureMain(this.fullChunkFuture).thenAccept((either) -> { // Paper - ensure main
|
||||||
if (either.left().isPresent() && PlayerChunk.this.fullChunkCreateCount == expectCreateCount) {
|
if (either.left().isPresent() && PlayerChunk.this.fullChunkCreateCount == expectCreateCount) {
|
||||||
// note: Here is a very good place to add callbacks to logic waiting on this.
|
// note: Here is a very good place to add callbacks to logic waiting on this.
|
||||||
Chunk fullChunk = either.left().get();
|
Chunk fullChunk = either.left().get();
|
||||||
|
@ -751,7 +830,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
if (!flag4 && flag5) {
|
if (!flag4 && flag5) {
|
||||||
// Paper start - cache ticking ready status
|
// Paper start - cache ticking ready status
|
||||||
- this.tickingFuture = playerchunkmap.a(this); this.tickingFuture.thenAccept((either) -> {
|
- this.tickingFuture = playerchunkmap.a(this); this.tickingFuture.thenAccept((either) -> {
|
||||||
+ this.tickingFuture = playerchunkmap.a(this); MCUtil.ensureMain(this.tickingFuture).thenAccept((either) -> { // Paper - ensure main
|
+ this.tickingFuture = playerchunkmap.a(this); ensureMain(this.tickingFuture).thenAccept((either) -> { // Paper - ensure main
|
||||||
if (either.left().isPresent()) {
|
if (either.left().isPresent()) {
|
||||||
// note: Here is a very good place to add callbacks to logic waiting on this.
|
// note: Here is a very good place to add callbacks to logic waiting on this.
|
||||||
Chunk tickingChunk = either.left().get();
|
Chunk tickingChunk = either.left().get();
|
||||||
|
@ -760,7 +839,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
|
|
||||||
// Paper start - cache ticking ready status
|
// Paper start - cache ticking ready status
|
||||||
- this.entityTickingFuture = playerchunkmap.b(this.location); this.entityTickingFuture.thenAccept((either) -> {
|
- this.entityTickingFuture = playerchunkmap.b(this.location); this.entityTickingFuture.thenAccept((either) -> {
|
||||||
+ this.entityTickingFuture = playerchunkmap.b(this.location); MCUtil.ensureMain(this.entityTickingFuture).thenAccept((either) -> { // Paper ensureMain
|
+ this.entityTickingFuture = playerchunkmap.b(this.location); ensureMain(this.entityTickingFuture).thenAccept((either) -> { // Paper ensureMain
|
||||||
if (either.left().isPresent()) {
|
if (either.left().isPresent()) {
|
||||||
// note: Here is a very good place to add callbacks to logic waiting on this.
|
// note: Here is a very good place to add callbacks to logic waiting on this.
|
||||||
Chunk entityTickingChunk = either.left().get();
|
Chunk entityTickingChunk = either.left().get();
|
||||||
|
@ -847,7 +926,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
PlayerChunkMap.this.world.getChunkProvider().removeTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update
|
PlayerChunkMap.this.world.getChunkProvider().removeTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update
|
||||||
- });
|
- });
|
||||||
+ PlayerChunkMap.this.world.getChunkProvider().clearPriorityTickets(chunkPos);
|
+ PlayerChunkMap.this.world.getChunkProvider().clearPriorityTickets(chunkPos);
|
||||||
+ }, (player, prevPos, newPos) -> checkHighPriorityChunks(player));
|
+ }, (player, prevPos, newPos) -> {
|
||||||
|
+ player.lastHighPriorityChecked = -1; // reset and recheck
|
||||||
|
+ checkHighPriorityChunks(player);
|
||||||
|
+ });
|
||||||
this.playerViewDistanceNoTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
|
this.playerViewDistanceNoTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
|
||||||
this.playerViewDistanceBroadcastMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
this.playerViewDistanceBroadcastMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||||
(EntityPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
(EntityPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||||
|
@ -878,33 +960,41 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ return playerchunk == null || unloadQueue.contains(playerchunk.location.pair());
|
+ return playerchunk == null || unloadQueue.contains(playerchunk.location.pair());
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ private void updateChunkPriorityMap(it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap map, long chunk, int level) {
|
||||||
|
+ int prev = map.getOrDefault(chunk, -1);
|
||||||
|
+ if (level > prev) {
|
||||||
|
+ map.put(chunk, level);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ public void checkHighPriorityChunks(EntityPlayer player) {
|
+ public void checkHighPriorityChunks(EntityPlayer player) {
|
||||||
+ int currentTick = MinecraftServer.currentTick;
|
+ int currentTick = MinecraftServer.currentTick;
|
||||||
+ if (currentTick - player.lastHighPriorityChecked < 20) {
|
+ if (currentTick - player.lastHighPriorityChecked < 20 || !player.isRealPlayer) { // weed out fake players
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+ player.lastHighPriorityChecked = currentTick;
|
+ player.lastHighPriorityChecked = currentTick;
|
||||||
|
+ it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap priorities = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap();
|
||||||
+
|
+
|
||||||
+ int viewDistance = getEffectiveNoTickViewDistance();
|
+ int viewDistance = getEffectiveNoTickViewDistance();
|
||||||
+ chunkDistanceManager.delayDistanceManagerTick = true;
|
|
||||||
+ BlockPosition.PooledBlockPosition pos = BlockPosition.PooledBlockPosition.acquire();
|
+ BlockPosition.PooledBlockPosition pos = BlockPosition.PooledBlockPosition.acquire();
|
||||||
+
|
+
|
||||||
+ // Prioritize circular near
|
+ // Prioritize circular near
|
||||||
+ double playerChunkX = MathHelper.floor(player.locX()) >> 4;
|
+ double playerChunkX = MathHelper.floor(player.locX()) >> 4;
|
||||||
+ double playerChunkZ = MathHelper.floor(player.locZ()) >> 4;
|
+ double playerChunkZ = MathHelper.floor(player.locZ()) >> 4;
|
||||||
+ pos.setValues(player.locX(), 0, player.locZ());
|
+ pos.setValues(player.locX(), 0, player.locZ());
|
||||||
|
+ double twoThirdModifier = 2D / 3D;
|
||||||
+ MCUtil.getSpiralOutChunks(pos, Math.min(6, viewDistance)).forEach(coord -> {
|
+ MCUtil.getSpiralOutChunks(pos, Math.min(6, viewDistance)).forEach(coord -> {
|
||||||
+ if (shouldSkipPrioritization(coord)) return;
|
+ if (shouldSkipPrioritization(coord)) return;
|
||||||
+
|
+
|
||||||
+ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
|
+ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
|
||||||
+ // Prioritize immediate
|
+ // Prioritize immediate
|
||||||
+ if (dist <= 4 * 4) {
|
+ if (dist <= 4 * 4) {
|
||||||
+ chunkDistanceManager.markHighPriority(coord, (int) (27 - Math.sqrt(dist)));
|
+ updateChunkPriorityMap(priorities, coord.pair(), (int) (27 - Math.sqrt(dist)));
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ // Prioritize nearby chunks
|
+ // Prioritize nearby chunks
|
||||||
+ chunkDistanceManager.markHighPriority(coord, (int) (16 - Math.sqrt(dist*(2D/3D))));
|
+ updateChunkPriorityMap(priorities, coord.pair(), (int) (20 - Math.sqrt(dist) * twoThirdModifier));
|
||||||
+ });
|
+ });
|
||||||
+
|
+
|
||||||
+ // Prioritize Frustum near 3
|
+ // Prioritize Frustum near 3
|
||||||
|
@ -913,7 +1003,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ MCUtil.getSpiralOutChunks(pos, Math.min(5, viewDistance)).forEach(coord -> {
|
+ MCUtil.getSpiralOutChunks(pos, Math.min(5, viewDistance)).forEach(coord -> {
|
||||||
+ if (shouldSkipPrioritization(coord)) return;
|
+ if (shouldSkipPrioritization(coord)) return;
|
||||||
+
|
+
|
||||||
+ chunkDistanceManager.markHighPriority(coord, 26);
|
+ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
|
||||||
|
+ updateChunkPriorityMap(priorities, coord.pair(), (int) (25 - Math.sqrt(dist) * twoThirdModifier));
|
||||||
+ });
|
+ });
|
||||||
+
|
+
|
||||||
+ // Prioritize Frustum near 5
|
+ // Prioritize Frustum near 5
|
||||||
|
@ -923,7 +1014,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ MCUtil.getSpiralOutChunks(pos, 4).forEach(coord -> {
|
+ MCUtil.getSpiralOutChunks(pos, 4).forEach(coord -> {
|
||||||
+ if (shouldSkipPrioritization(coord)) return;
|
+ if (shouldSkipPrioritization(coord)) return;
|
||||||
+
|
+
|
||||||
+ chunkDistanceManager.markHighPriority(coord, 20);
|
+ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
|
||||||
|
+ updateChunkPriorityMap(priorities, coord.pair(), (int) (25 - Math.sqrt(dist) * twoThirdModifier));
|
||||||
+ });
|
+ });
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
@ -935,13 +1027,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ if (shouldSkipPrioritization(coord)) {
|
+ if (shouldSkipPrioritization(coord)) {
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+ chunkDistanceManager.markHighPriority(coord, 15);
|
+ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
|
||||||
|
+ updateChunkPriorityMap(priorities, coord.pair(), (int) (25 - Math.sqrt(dist) * twoThirdModifier));
|
||||||
+ });
|
+ });
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ pos.close();
|
+ pos.close();
|
||||||
|
+ if (priorities.isEmpty()) return;
|
||||||
|
+ chunkDistanceManager.delayDistanceManagerTick = true;
|
||||||
|
+ priorities.long2IntEntrySet().fastForEach(entry -> chunkDistanceManager.markHighPriority(new ChunkCoordIntPair(entry.getLongKey()), entry.getIntValue()));
|
||||||
+ chunkDistanceManager.delayDistanceManagerTick = false;
|
+ chunkDistanceManager.delayDistanceManagerTick = false;
|
||||||
+ world.getChunkProvider().tickDistanceManager();
|
+ world.getChunkProvider().tickDistanceManager();
|
||||||
|
+
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private boolean shouldSkipPrioritization(ChunkCoordIntPair coord) {
|
+ private boolean shouldSkipPrioritization(ChunkCoordIntPair coord) {
|
||||||
|
@ -1018,13 +1115,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
|
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
|
||||||
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
|
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
|
||||||
@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
|
@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
|
||||||
// CraftBukkit end
|
|
||||||
|
|
||||||
this.A = this.e;
|
this.A = this.e;
|
||||||
+ this.player.getWorldServer().getChunkProvider().markAreaHighPriority(new ChunkCoordIntPair(MathHelper.floor(d1) >> 4, MathHelper.floor(d3) >> 4), 28, 3); // Paper - load area high priority
|
|
||||||
this.player.setLocation(d0, d1, d2, f, f1);
|
this.player.setLocation(d0, d1, d2, f, f1);
|
||||||
this.syncPosition(); // Paper
|
this.syncPosition(); // Paper
|
||||||
|
+ this.player.forceCheckHighPriority(); // Paper
|
||||||
this.player.playerConnection.sendPacket(new PacketPlayOutPosition(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.teleportAwait));
|
this.player.playerConnection.sendPacket(new PacketPlayOutPosition(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.teleportAwait));
|
||||||
|
}
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
|
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/server/PlayerList.java
|
--- a/src/main/java/net/minecraft/server/PlayerList.java
|
||||||
|
@ -1048,11 +1145,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||||
|
SocketAddress socketaddress = loginlistener.networkManager.getSocketAddress();
|
||||||
|
|
||||||
|
EntityPlayer entity = new EntityPlayer(this.server, this.server.getWorldServer(DimensionManager.OVERWORLD), gameprofile, new PlayerInteractManager(this.server.getWorldServer(DimensionManager.OVERWORLD)));
|
||||||
|
+ entity.isRealPlayer = true; // Paper
|
||||||
|
Player player = entity.getBukkitEntity();
|
||||||
|
PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.networkManager.getRawAddress()).getAddress());
|
||||||
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
worldserver.getChunkProvider().addTicket(TicketType.POST_TELEPORT, new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
|
worldserver.getChunkProvider().addTicket(TicketType.POST_TELEPORT, new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
|
||||||
+ worldserver.getChunkProvider().markAreaHighPriority(new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4), 28, 3); // Paper - load area at high priority
|
+ entityplayer1.forceCheckHighPriority(); // Player
|
||||||
while (avoidSuffocation && !worldserver.getCubes(entityplayer1) && entityplayer1.locY() < 256.0D) {
|
while (avoidSuffocation && !worldserver.getCubes(entityplayer1) && entityplayer1.locY() < 256.0D) {
|
||||||
entityplayer1.setPosition(entityplayer1.locX(), entityplayer1.locY() + 1.0D, entityplayer1.locZ());
|
entityplayer1.setPosition(entityplayer1.locX(), entityplayer1.locY() + 1.0D, entityplayer1.locZ());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue