mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-17 16:37:43 +01:00
Upstream has released updates that appears to apply and compile correctly Paper Changes: cc477e6a Force Plugins that use delayed tasks for init back in their place 597263fd Don't skip full player connection tick when dead e2c23475 Revert loaded entity list (#3304) fa87db6b Move another NetworkManager util into the inner class (#3303) 841c7d18 Make loaded entity list logic more consistent (#3301) 36f34f01 Updated Upstream (Bukkit/CraftBukkit) 5ca5f131 Rebuild all patches using the new rebuild pattern 1ccff6fa Add villager reputation API 5c0bfffa Speed up rebuilding patches and reduce diff f37381ea Optimize Network Manager to not need synchronization 8f9df2ed Anti Xray cleanup 878c66f1 No-Tick view distance implementation - Closes #3196 b87743c1 Stop copy-on-write operations for updating light data 97a9c972 Optimize isOutsideRange to use distance maps b4e629a2 Use distance map to optimise entity tracker / Misc Utils d80d1517 Optimize Entity Ticking to Loaded Chunks only 31d7686d Add item slot helper methods for various inventories (#3221) 75e1e3b3 Mob Goal API c7bc393a Revert "Don't flush packet queue off main thread" 1abd2bd2 Don't flush packet queue off main thread a4ed58a9 Clean up Direct Memory Region Files Fix for different Java versions 55e35019 Set cap on JDK per-thread native byte buffer cache b5101f4f Cleanup Region Files Direct Memory on close 81e655d7 Optimize Voxel Shape Merging ed9fc11f Sync position on teleportation 9c326fce Nanothing to see here 3e9fc24b Attempt to fix FastLogin maybe
226 lines
12 KiB
Diff
226 lines
12 KiB
Diff
From 3755fa9ef7cb0798f63098b7cc08db5a4bac6b73 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
|
Date: Fri, 25 Oct 2019 02:11:30 -0700
|
|
Subject: [PATCH] Tuinity - Delay chunk unloads
|
|
|
|
Chunk unloads are now delayed by 10s. Specifically, ticket level
|
|
reduction is delayed by 10s. This is done to allow players to
|
|
teleport and have their pets follow them, as the chunks will no longer
|
|
unload or have entity ticking status removed.
|
|
|
|
It's also targetted to reduce performance regressions when
|
|
plugins or edge cases in code do not spam sync loads since chunks
|
|
without tickets get unloaded immediately.
|
|
|
|
Configurable under `delay-chunkunloads-by` in config.
|
|
---
|
|
.../java/net/minecraft/server/ChunkMap.java | 1 +
|
|
.../minecraft/server/ChunkMapDistance.java | 68 ++++++++++++++++++-
|
|
.../java/net/minecraft/server/Ticket.java | 6 +-
|
|
.../java/net/minecraft/server/TicketType.java | 1 +
|
|
.../java/net/pl3x/purpur/PurpurConfig.java | 9 +++
|
|
.../org/bukkit/craftbukkit/CraftWorld.java | 1 +
|
|
6 files changed, 82 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkMap.java b/src/main/java/net/minecraft/server/ChunkMap.java
|
|
index 55f9f4e6e..ac21fdb4c 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkMap.java
|
|
@@ -68,6 +68,7 @@ public abstract class ChunkMap extends LightEngineGraph {
|
|
|
|
protected abstract int b(long i);
|
|
|
|
+ public final void update(long coordinate, int level, boolean increaseInLevel) { this.b(coordinate, level, increaseInLevel); } // Purpur - OBFHELPER
|
|
public void b(long i, int j, boolean flag) {
|
|
this.a(ChunkCoordIntPair.a, i, j, flag);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
|
index 942efe62f..6f710ffa2 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
|
@@ -30,7 +30,7 @@ public abstract class ChunkMapDistance {
|
|
private static final int b = 33 + ChunkStatus.a(ChunkStatus.FULL) - 2;
|
|
private final Long2ObjectMap<ObjectSet<EntityPlayer>> c = new Long2ObjectOpenHashMap();
|
|
public final Long2ObjectOpenHashMap<ArraySetSorted<Ticket<?>>> tickets = new Long2ObjectOpenHashMap();
|
|
- private final ChunkMapDistance.a e = new ChunkMapDistance.a();
|
|
+ private final ChunkMapDistance.a e = new ChunkMapDistance.a(); final ChunkMapDistance.a getTicketTracker() { return this.e; } // Purpur - OBFHELPER
|
|
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.LinkedList<>(); // PAIL pendingChunkUpdates // Paper - use a queue
|
|
@@ -42,6 +42,46 @@ public abstract class ChunkMapDistance {
|
|
private long currentTick;
|
|
|
|
PlayerChunkMap chunkMap; // Paper
|
|
+ // Purpur start
|
|
+ private long nextUnloadId;
|
|
+ private final Long2ObjectOpenHashMap<Ticket<Long>> delayedChunks = new Long2ObjectOpenHashMap<>();
|
|
+ public final void removeTickets(long chunk, TicketType<?> type) {
|
|
+ ArraySetSorted<Ticket<?>> tickets = this.tickets.get(chunk);
|
|
+ if (tickets == null) {
|
|
+ return;
|
|
+ }
|
|
+ if (type == TicketType.DELAYED_UNLOAD) {
|
|
+ this.delayedChunks.remove(chunk);
|
|
+ }
|
|
+ boolean changed = tickets.removeIf((Ticket<?> ticket) -> {
|
|
+ return ticket.getTicketType() == type;
|
|
+ });
|
|
+ if (changed) {
|
|
+ this.getTicketTracker().update(chunk, getLowestTicketLevel(tickets), false);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private final java.util.function.LongFunction<Ticket<Long>> computeFuntion = (long key) -> {
|
|
+ Ticket<Long> ret = new Ticket<>(TicketType.DELAYED_UNLOAD, -1, ++ChunkMapDistance.this.nextUnloadId);
|
|
+ ret.isCached = true;
|
|
+ return ret;
|
|
+ };
|
|
+
|
|
+ private void computeDelayedTicketFor(long chunk, int removedLevel, ArraySetSorted<Ticket<?>> tickets) {
|
|
+ int lowestLevel = getLowestTicketLevel(tickets);
|
|
+ if (removedLevel > lowestLevel) {
|
|
+ return;
|
|
+ }
|
|
+ final Ticket<Long> ticket = this.delayedChunks.computeIfAbsent(chunk, this.computeFuntion);
|
|
+ if (ticket.getTicketLevel() != -1) {
|
|
+ // since we modify data used in sorting, we need to remove before
|
|
+ tickets.remove(ticket);
|
|
+ }
|
|
+ ticket.setCreationTick(this.currentTick);
|
|
+ ticket.setTicketLevel(removedLevel);
|
|
+ tickets.add(ticket); // re-add with new expire time and ticket level
|
|
+ }
|
|
+ // Purpur end
|
|
|
|
protected ChunkMapDistance(Executor executor, Executor executor1) {
|
|
executor1.getClass();
|
|
@@ -58,12 +98,30 @@ public abstract class ChunkMapDistance {
|
|
++this.currentTick;
|
|
ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().fastIterator();
|
|
|
|
+ int[] tempLevel = new int[] { PlayerChunkMap.GOLDEN_TICKET + 1 }; // Purpur
|
|
while (objectiterator.hasNext()) {
|
|
Entry<ArraySetSorted<Ticket<?>>> entry = (Entry) objectiterator.next();
|
|
|
|
if ((entry.getValue()).removeIf((ticket) -> { // CraftBukkit - decompile error
|
|
- return ticket.b(this.currentTick);
|
|
+ // Purpur start
|
|
+ boolean ret = ticket.isExpired(this.currentTick);
|
|
+ if (net.pl3x.purpur.PurpurConfig.delayChunkUnloadsBy <= 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ if (ret && ticket.getTicketType() != TicketType.DELAYED_UNLOAD && ticket.getTicketLevel() < tempLevel[0]) {
|
|
+ tempLevel[0] = ticket.getTicketLevel();
|
|
+ }
|
|
+ if (ticket.getTicketType() == TicketType.DELAYED_UNLOAD && ticket.isCached) {
|
|
+ this.delayedChunks.remove(entry.getLongKey(), ticket); // clean up ticket...
|
|
+ }
|
|
+ return ret;
|
|
+ // Purpur end
|
|
})) {
|
|
+ // Purpur start
|
|
+ if (tempLevel[0] < (PlayerChunkMap.GOLDEN_TICKET + 1)) {
|
|
+ this.computeDelayedTicketFor(entry.getLongKey(), tempLevel[0], entry.getValue());
|
|
+ }
|
|
+ // Purpur end
|
|
this.e.b(entry.getLongKey(), a((ArraySetSorted) entry.getValue()), false);
|
|
}
|
|
|
|
@@ -74,6 +132,7 @@ public abstract class ChunkMapDistance {
|
|
|
|
}
|
|
|
|
+ private static int getLowestTicketLevel(ArraySetSorted<Ticket<?>> arraysetsorted) { return a(arraysetsorted); } // Purpur - OBFHELPER
|
|
private static int a(ArraySetSorted<Ticket<?>> arraysetsorted) {
|
|
return !arraysetsorted.isEmpty() ? ((Ticket) arraysetsorted.b()).b() : PlayerChunkMap.GOLDEN_TICKET + 1;
|
|
}
|
|
@@ -156,6 +215,11 @@ public abstract class ChunkMapDistance {
|
|
boolean removed = false; // CraftBukkit
|
|
if (arraysetsorted.remove(ticket)) {
|
|
removed = true; // CraftBukkit
|
|
+ // Purpur start
|
|
+ if (net.pl3x.purpur.PurpurConfig.delayChunkUnloadsBy > 0 && ticket.getTicketType() != TicketType.DELAYED_UNLOAD) {
|
|
+ this.computeDelayedTicketFor(i, ticket.getTicketLevel(), arraysetsorted);
|
|
+ }
|
|
+ // Purpur end
|
|
}
|
|
|
|
if (arraysetsorted.isEmpty()) {
|
|
diff --git a/src/main/java/net/minecraft/server/Ticket.java b/src/main/java/net/minecraft/server/Ticket.java
|
|
index 7a8397815..8aae0b63e 100644
|
|
--- a/src/main/java/net/minecraft/server/Ticket.java
|
|
+++ b/src/main/java/net/minecraft/server/Ticket.java
|
|
@@ -5,9 +5,10 @@ import java.util.Objects;
|
|
public final class Ticket<T> implements Comparable<Ticket<?>> {
|
|
|
|
private final TicketType<T> a;
|
|
- private final int b;
|
|
+ private int b; public final void setTicketLevel(final int value) { this.b = value; } // Purpur - remove final - OBFHELPER
|
|
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
|
|
+ private long d; public final long getCreationTick() { return this.d; } public final void setCreationTick(final long value) { this.d = value; } // Paper - OBFHELPER // Purpur - OBFHELPER
|
|
+ boolean isCached; // Purpur - delay chunk unloads, this defends against really stupid plugins
|
|
|
|
protected Ticket(TicketType<T> tickettype, int i, T t0) {
|
|
this.a = tickettype;
|
|
@@ -60,6 +61,7 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
|
|
this.d = i;
|
|
}
|
|
|
|
+ protected final boolean isExpired(long time) { return this.b(time); } // Purpur - OBFHELPER
|
|
protected boolean b(long i) {
|
|
long j = this.a.b();
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/TicketType.java b/src/main/java/net/minecraft/server/TicketType.java
|
|
index 8055f5998..93587068f 100644
|
|
--- a/src/main/java/net/minecraft/server/TicketType.java
|
|
+++ b/src/main/java/net/minecraft/server/TicketType.java
|
|
@@ -23,6 +23,7 @@ public class TicketType<T> {
|
|
public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = a("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
|
|
public static final TicketType<Long> FUTURE_AWAIT = a("future_await", Long::compareTo); // Paper
|
|
public static final TicketType<Long> ASYNC_LOAD = a("async_load", Long::compareTo); // Paper
|
|
+ public static final TicketType<Long> DELAYED_UNLOAD = a("delayed_unload", Long::compareTo); // Purpur
|
|
|
|
public static <T> TicketType<T> a(String s, Comparator<T> comparator) {
|
|
return new TicketType<>(s, comparator, 0L);
|
|
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
|
|
index ab88636ca..becb13e0e 100644
|
|
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
|
|
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
|
|
@@ -4,6 +4,7 @@ import com.google.common.base.Throwables;
|
|
import net.minecraft.server.Enchantment;
|
|
import net.minecraft.server.IRegistry;
|
|
import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.server.TicketType;
|
|
import net.pl3x.purpur.command.PurpurCommand;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.command.Command;
|
|
@@ -206,4 +207,12 @@ public class PurpurConfig {
|
|
enchantment.setMaxLevel(maxLevel);
|
|
}
|
|
}
|
|
+
|
|
+ public static int delayChunkUnloadsBy;
|
|
+ private static void delayChunkUnloadsBy() {
|
|
+ delayChunkUnloadsBy = getInt("settings.delay-chunk-unloads-by", 1) * 20;
|
|
+ if (delayChunkUnloadsBy >= 0) {
|
|
+ TicketType.DELAYED_UNLOAD.loadPeriod = delayChunkUnloadsBy;
|
|
+ }
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
index 6a50d7de3..513e84f76 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
@@ -487,6 +487,7 @@ public class CraftWorld implements World {
|
|
net.minecraft.server.IChunkAccess chunk = world.getChunkProvider().getChunkAtIfLoadedImmediately(x, z); // Paper
|
|
if (chunk != null) {
|
|
world.getChunkProvider().removeTicket(TicketType.PLUGIN, chunk.getPos(), 1, Unit.INSTANCE);
|
|
+ ((ChunkMapDistance)world.getChunkProvider().playerChunkMap.getChunkMapDistanceManager()).removeTickets(ChunkCoordIntPair.pair(x, z), TicketType.DELAYED_UNLOAD); // Purpur - delay chunk unloads - let plugins override
|
|
}
|
|
|
|
return true;
|
|
--
|
|
2.24.0
|
|
|