geforkt von Mirrors/Paper
Rewrite chunk system (#8177)
Patch documentation to come Issues with the old system that are fixed now: - World generation does not scale with cpu cores effectively. - Relies on the main thread for scheduling and maintaining chunk state, dropping chunk load/generate rates at lower tps. - Unreliable prioritisation of chunk gen/load calls that block the main thread. - Shutdown logic is utterly unreliable, as it has to wait for all chunks to unload - is it guaranteed that the chunk system is in a state on shutdown that it can reliably do this? Watchdog shutdown also typically failed due to thread checks, which is now resolved. - Saving of data is not unified (i.e can save chunk data without saving entity data, poses problems for desync if shutdown is really abnormal. - Entities are not loaded with chunks. This caused quite a bit of headache for Chunk#getEntities API, but now the new chunk system loads entities with chunks so that they are ready whenever the chunk loads in. Effectively brings the behavior back to 1.16 era, but still storing entities in their own separate regionfiles. The above list is not complete. The patch documentation will complete it. New chunk system hard relies on starlight and dataconverter, and most importantly the new concurrent utilities in ConcurrentUtil. Some of the old async chunk i/o interface (i.e the old file io thread reroutes _some_ calls to the new file io thread) is kept for plugin compat reasons. It will be removed in the next major version of minecraft. The old legacy chunk system patches have been moved to the removed folder in case we need them again.
Dieser Commit ist enthalten in:
Ursprung
614f528234
Commit
0f1a8717e8
@ -1,321 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
Date: Mon, 31 Aug 2020 11:08:17 -0700
|
||||
Subject: [PATCH] Actually unload POI data
|
||||
|
||||
While it's not likely for a poi data leak to be meaningful,
|
||||
sometimes it is.
|
||||
|
||||
This patch also prevents the saving/unloading of POI data when
|
||||
world saving is disabled.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/ChunkSystem.java
|
||||
+++ b/src/main/java/net/minecraft/server/ChunkSystem.java
|
||||
@@ -0,0 +0,0 @@ public final class ChunkSystem {
|
||||
for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) {
|
||||
chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z);
|
||||
}
|
||||
+ chunkMap.getPoiManager().dequeueUnload(holder.pos.longKey); // Paper - unload POI data
|
||||
}
|
||||
|
||||
public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) {
|
||||
@@ -0,0 +0,0 @@ public final class ChunkSystem {
|
||||
for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) {
|
||||
chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z);
|
||||
}
|
||||
+ chunkMap.getPoiManager().queueUnload(holder.pos.longKey, MinecraftServer.currentTickLong + 1); // Paper - unload POI data
|
||||
}
|
||||
|
||||
public static void onChunkBorder(LevelChunk chunk, ChunkHolder holder) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
private void processUnloads(BooleanSupplier shouldKeepTicking) {
|
||||
LongIterator longiterator = this.toDrop.iterator();
|
||||
- for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) {
|
||||
+ for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { // Paper - diff on change
|
||||
long j = longiterator.nextLong();
|
||||
ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
this.poiManager.loadInData(pos, chunkHolder.poiData);
|
||||
chunkHolder.tasks.forEach(Runnable::run);
|
||||
+ this.getPoiManager().dequeueUnload(pos.longKey); // Paper
|
||||
|
||||
if (chunkHolder.protoChunk != null) {
|
||||
ProtoChunk protochunk = chunkHolder.protoChunk;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
@@ -0,0 +0,0 @@
|
||||
package net.minecraft.world.entity.ai.village.poi;
|
||||
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; // Paper
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.storage.SectionStorage;
|
||||
public class PoiManager extends SectionStorage<PoiSection> {
|
||||
public static final int MAX_VILLAGE_DISTANCE = 6;
|
||||
public static final int VILLAGE_SECTION_SIZE = 1;
|
||||
- private final PoiManager.DistanceTracker distanceTracker;
|
||||
+ // Paper start - unload poi data
|
||||
+ // the vanilla tracker needs to be replaced because it does not support level removes
|
||||
+ private final io.papermc.paper.util.misc.Delayed26WayDistancePropagator3D villageDistanceTracker = new io.papermc.paper.util.misc.Delayed26WayDistancePropagator3D();
|
||||
+ static final int POI_DATA_SOURCE = 7;
|
||||
+ public static int convertBetweenLevels(final int level) {
|
||||
+ return POI_DATA_SOURCE - level;
|
||||
+ }
|
||||
+
|
||||
+ protected void updateDistanceTracking(long section) {
|
||||
+ if (this.isVillageCenter(section)) {
|
||||
+ this.villageDistanceTracker.setSource(section, POI_DATA_SOURCE);
|
||||
+ } else {
|
||||
+ this.villageDistanceTracker.removeSource(section);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - unload poi data
|
||||
private final LongSet loadedChunks = new LongOpenHashSet();
|
||||
public final net.minecraft.server.level.ServerLevel world; // Paper // Paper public
|
||||
|
||||
public PoiManager(Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) {
|
||||
super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world);
|
||||
+ if (world == null) { throw new IllegalStateException("world must be non-null"); } // Paper - require non-null
|
||||
this.world = (net.minecraft.server.level.ServerLevel)world; // Paper
|
||||
- this.distanceTracker = new PoiManager.DistanceTracker();
|
||||
}
|
||||
|
||||
+ // Paper start - actually unload POI data
|
||||
+ private final java.util.TreeSet<QueuedUnload> queuedUnloads = new java.util.TreeSet<>();
|
||||
+ private final Long2ObjectOpenHashMap<QueuedUnload> queuedUnloadsByCoordinate = new Long2ObjectOpenHashMap<>();
|
||||
+
|
||||
+ static final class QueuedUnload implements Comparable<QueuedUnload> {
|
||||
+
|
||||
+ private final long unloadTick;
|
||||
+ private final long coordinate;
|
||||
+
|
||||
+ public QueuedUnload(long unloadTick, long coordinate) {
|
||||
+ this.unloadTick = unloadTick;
|
||||
+ this.coordinate = coordinate;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int compareTo(QueuedUnload other) {
|
||||
+ if (other.unloadTick == this.unloadTick) {
|
||||
+ return Long.compare(this.coordinate, other.coordinate);
|
||||
+ } else {
|
||||
+ return Long.compare(this.unloadTick, other.unloadTick);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ int hash = 1;
|
||||
+ hash = hash * 31 + Long.hashCode(this.unloadTick);
|
||||
+ hash = hash * 31 + Long.hashCode(this.coordinate);
|
||||
+ return hash;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(Object obj) {
|
||||
+ if (obj == null || obj.getClass() != QueuedUnload.class) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ QueuedUnload other = (QueuedUnload)obj;
|
||||
+ return other.unloadTick == this.unloadTick && other.coordinate == this.coordinate;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ long determineDelay(long coordinate) {
|
||||
+ if (this.isEmpty(coordinate)) {
|
||||
+ return 5 * 60 * 20;
|
||||
+ } else {
|
||||
+ return 60 * 20;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void queueUnload(long coordinate, long minTarget) {
|
||||
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload queue");
|
||||
+ QueuedUnload unload = new QueuedUnload(minTarget + this.determineDelay(coordinate), coordinate);
|
||||
+ QueuedUnload existing = this.queuedUnloadsByCoordinate.put(coordinate, unload);
|
||||
+ if (existing != null) {
|
||||
+ this.queuedUnloads.remove(existing);
|
||||
+ }
|
||||
+ this.queuedUnloads.add(unload);
|
||||
+ }
|
||||
+
|
||||
+ public void dequeueUnload(long coordinate) {
|
||||
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload dequeue");
|
||||
+ QueuedUnload unload = this.queuedUnloadsByCoordinate.remove(coordinate);
|
||||
+ if (unload != null) {
|
||||
+ this.queuedUnloads.remove(unload);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void pollUnloads(BooleanSupplier canSleepForTick) {
|
||||
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload");
|
||||
+ long currentTick = net.minecraft.server.MinecraftServer.currentTickLong;
|
||||
+ net.minecraft.server.level.ServerChunkCache chunkProvider = this.world.getChunkSource();
|
||||
+ net.minecraft.server.level.ChunkMap playerChunkMap = chunkProvider.chunkMap;
|
||||
+ // copied target determination from PlayerChunkMap
|
||||
+
|
||||
+ java.util.Iterator<QueuedUnload> iterator = this.queuedUnloads.iterator();
|
||||
+ for (int i = 0; iterator.hasNext() && (i < 200 || this.queuedUnloads.size() > 2000 || canSleepForTick.getAsBoolean()); i++) {
|
||||
+ QueuedUnload unload = iterator.next();
|
||||
+ if (unload.unloadTick > currentTick) {
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ long coordinate = unload.coordinate;
|
||||
+
|
||||
+ iterator.remove();
|
||||
+ this.queuedUnloadsByCoordinate.remove(coordinate);
|
||||
+
|
||||
+ if (playerChunkMap.getUnloadingChunkHolder(net.minecraft.server.MCUtil.getCoordinateX(coordinate), net.minecraft.server.MCUtil.getCoordinateZ(coordinate)) != null
|
||||
+ || playerChunkMap.getUpdatingChunkIfPresent(coordinate) != null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.unloadData(coordinate);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void unloadData(long coordinate) {
|
||||
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async unloading poi data");
|
||||
+ super.unloadData(coordinate);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void onUnload(long coordinate) {
|
||||
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload callback");
|
||||
+ this.loadedChunks.remove(coordinate);
|
||||
+ int chunkX = net.minecraft.server.MCUtil.getCoordinateX(coordinate);
|
||||
+ int chunkZ = net.minecraft.server.MCUtil.getCoordinateZ(coordinate);
|
||||
+ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
|
||||
+ long sectionPos = SectionPos.asLong(chunkX, section, chunkZ);
|
||||
+ this.updateDistanceTracking(sectionPos);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - actually unload POI data
|
||||
+
|
||||
public void add(BlockPos pos, Holder<PoiType> type) {
|
||||
this.getOrCreate(SectionPos.asLong(pos)).add(pos, type);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
||||
}
|
||||
|
||||
public int sectionsToVillage(SectionPos pos) {
|
||||
- this.distanceTracker.runAllUpdates();
|
||||
- return this.distanceTracker.getLevel(pos.asLong());
|
||||
+ this.villageDistanceTracker.propagateUpdates(); // Paper - replace distance tracking util
|
||||
+ return convertBetweenLevels(this.villageDistanceTracker.getLevel(io.papermc.paper.util.CoordinateUtils.getChunkSectionKey(pos))); // Paper - replace distance tracking util
|
||||
}
|
||||
|
||||
boolean isVillageCenter(long pos) {
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
||||
@Override
|
||||
public void tick(BooleanSupplier shouldKeepTicking) {
|
||||
// Paper start - async chunk io
|
||||
- while (!this.dirty.isEmpty() && shouldKeepTicking.getAsBoolean()) {
|
||||
+ while (!this.dirty.isEmpty() && shouldKeepTicking.getAsBoolean() && !this.world.noSave()) { // Paper - unload POI data - don't write to disk if saving is disabled
|
||||
ChunkPos chunkcoordintpair = SectionPos.of(this.dirty.firstLong()).chunk();
|
||||
|
||||
net.minecraft.nbt.CompoundTag data;
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
||||
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.world,
|
||||
chunkcoordintpair.x, chunkcoordintpair.z, data, null, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY);
|
||||
}
|
||||
+ // Paper start - unload POI data
|
||||
+ if (!this.world.noSave()) { // don't write to disk if saving is disabled
|
||||
+ this.pollUnloads(shouldKeepTicking);
|
||||
+ }
|
||||
+ // Paper end - unload POI data
|
||||
// Paper end
|
||||
- this.distanceTracker.runAllUpdates();
|
||||
+ this.villageDistanceTracker.propagateUpdates(); // Paper - replace distance tracking until
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDirty(long pos) {
|
||||
super.setDirty(pos);
|
||||
- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false);
|
||||
+ this.updateDistanceTracking(pos); // Paper - move to new distance tracking util
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSectionLoad(long pos) {
|
||||
- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false);
|
||||
+ this.updateDistanceTracking(pos); // Paper - move to new distance tracking util
|
||||
}
|
||||
|
||||
public void checkConsistencyWithBlocks(ChunkPos chunkPos, LevelChunkSection chunkSection) {
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
||||
|
||||
@Override
|
||||
protected int getLevelFromSource(long id) {
|
||||
- return PoiManager.this.isVillageCenter(id) ? 0 : 7;
|
||||
+ return PoiManager.this.isVillageCenter(id) ? 0 : 7; // Paper - unload poi data - diff on change, this specifies the source level to use for distance tracking
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
@@ -0,0 +0,0 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
|
||||
// Paper - remove mojang I/O thread
|
||||
}
|
||||
|
||||
+ // Paper start - actually unload POI data
|
||||
+ public void unloadData(long coordinate) {
|
||||
+ ChunkPos chunkPos = new ChunkPos(coordinate);
|
||||
+ this.flush(chunkPos);
|
||||
+
|
||||
+ Long2ObjectMap<Optional<R>> data = this.storage;
|
||||
+ int before = data.size();
|
||||
+
|
||||
+ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
|
||||
+ data.remove(SectionPos.asLong(chunkPos.x, section, chunkPos.z));
|
||||
+ }
|
||||
+
|
||||
+ if (before != data.size()) {
|
||||
+ this.onUnload(coordinate);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected void onUnload(long coordinate) {}
|
||||
+
|
||||
+ public boolean isEmpty(long coordinate) {
|
||||
+ Long2ObjectMap<Optional<R>> data = this.storage;
|
||||
+ int x = net.minecraft.server.MCUtil.getCoordinateX(coordinate);
|
||||
+ int z = net.minecraft.server.MCUtil.getCoordinateZ(coordinate);
|
||||
+ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
|
||||
+ Optional<R> optional = data.get(SectionPos.asLong(x, section, z));
|
||||
+ if (optional != null && optional.orElse(null) != null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - actually unload POI data
|
||||
+
|
||||
protected void tick(BooleanSupplier shouldKeepTicking) {
|
||||
while(this.hasWork() && shouldKeepTicking.getAsBoolean()) {
|
||||
ChunkPos chunkPos = SectionPos.of(this.dirty.firstLong()).chunk();
|
||||
@@ -0,0 +0,0 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
|
||||
});
|
||||
}
|
||||
}
|
||||
+ if (this instanceof net.minecraft.world.entity.ai.village.poi.PoiManager) { ((net.minecraft.world.entity.ai.village.poi.PoiManager)this).queueUnload(pos.longKey, net.minecraft.server.MinecraftServer.currentTickLong + 1); } // Paper - unload POI data
|
||||
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
|
||||
|
||||
public boolean isRealPlayer; // Paper
|
||||
public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
|
||||
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||
+ public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event
|
||||
|
@ -34,7 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
|
||||
public void placeNewPlayer(Connection connection, ServerPlayer player) {
|
||||
player.isRealPlayer = true; // Paper - Chunk priority
|
||||
player.isRealPlayer = true; // Paper
|
||||
+ player.loginTime = System.currentTimeMillis(); // Paper
|
||||
GameProfile gameprofile = player.getGameProfile();
|
||||
GameProfileCache usercache = this.server.getProfileCache();
|
||||
|
@ -2020,7 +2020,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
return new Throwable(entity + " Added to world at " + new java.util.Date());
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return this.entityManager.canPositionTick(pos.toLong()); // Paper
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
|
||||
+ // Paper start - optimize redstone (Alternate Current)
|
||||
|
@ -69,7 +69,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
private static WatchdogThread instance;
|
||||
private long timeoutTime;
|
||||
private boolean restart;
|
||||
@ -80,7 +80,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
private volatile long lastTick;
|
||||
private volatile boolean stopping;
|
||||
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
super( "Paper Watchdog Thread" );
|
||||
this.timeoutTime = timeoutTime;
|
||||
this.restart = restart;
|
||||
@ -89,7 +89,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
|
||||
private static long monotonicMillis()
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
while ( !this.stopping )
|
||||
{
|
||||
//
|
||||
@ -110,7 +110,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
|
||||
log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" );
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
@ -122,7 +122,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // Paper end - Different message for short timeout
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
||||
|
@ -207,8 +207,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
import java.util.ArrayList;
|
||||
@@ -0,0 +0,0 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("version"), new VersionCommand());
|
||||
commands.put(Set.of("debug", "chunkinfo"), new ChunkDebugCommand());
|
||||
commands.put(Set.of("fixlight"), new FixLightCommand());
|
||||
commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand());
|
||||
+ commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
|
||||
|
||||
return commands.entrySet().stream()
|
||||
@ -302,21 +302,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
this.level.asyncChunkTaskManager.raisePriority(x1, z1, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY);
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.level, x1, z1);
|
||||
// Paper start - async chunk io/loading
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.pushChunkWait(this.level, x1, z1); // Paper - rewrite chunk system
|
||||
// Paper end
|
||||
+ com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x1, z1); // Paper - sync load info
|
||||
this.level.timings.syncChunkLoad.startTiming(); // Paper
|
||||
chunkproviderserver_b.managedBlock(completablefuture::isDone);
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - async chunk debug // Paper - rewrite chunk system
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
};
|
||||
public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager;
|
||||
// Paper end
|
||||
return this.entityLookup;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean hasChunk(int chunkX, int chunkZ) {
|
||||
|
@ -48,18 +48,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return internalTask;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
ChunkMap.LOGGER.error("Failed to save chunk {},{}", new Object[]{chunkcoordintpair.x, chunkcoordintpair.z, exception});
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
|
||||
return false;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
|
@ -1,44 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 15 Jul 2021 01:41:53 -0700
|
||||
Subject: [PATCH] Add more async catchers
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||
@@ -0,0 +0,0 @@ public class EntityTickList {
|
||||
}
|
||||
|
||||
public void add(Entity entity) {
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist addition"); // Paper
|
||||
this.ensureActiveIsNotIterated();
|
||||
this.active.put(entity.getId(), entity);
|
||||
}
|
||||
|
||||
public void remove(Entity entity) {
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist removal"); // Paper
|
||||
this.ensureActiveIsNotIterated();
|
||||
this.active.remove(entity.getId());
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class EntityTickList {
|
||||
}
|
||||
|
||||
public void forEach(Consumer<Entity> action) {
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist iteration"); // Paper
|
||||
if (this.iterated != null) {
|
||||
throw new UnsupportedOperationException("Only one concurrent iteration supported");
|
||||
} else {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void updateChunkStatus(ChunkPos chunkPos, ChunkHolder.FullChunkStatus levelType) {
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous chunk ticking status update"); // Paper
|
||||
Visibility visibility = Visibility.fromFullChunkStatus(levelType);
|
||||
|
||||
this.updateChunkStatus(chunkPos, visibility);
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 30 Oct 2020 22:37:16 -0700
|
||||
Subject: [PATCH] Add packet limiter config
|
||||
|
||||
|
@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
import io.papermc.paper.command.subcommands.SyncLoadInfoCommand;
|
||||
import io.papermc.paper.command.subcommands.VersionCommand;
|
||||
@@ -0,0 +0,0 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("fixlight"), new FixLightCommand());
|
||||
commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand());
|
||||
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
|
||||
commands.put(Set.of("dumpitem"), new DumpItemCommand());
|
||||
+ commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand());
|
||||
|
@ -65,7 +65,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" );
|
||||
log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem );
|
||||
}
|
||||
@ -85,4 +85,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // Paper end
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 4 Apr 2020 15:27:44 -0700
|
||||
Subject: [PATCH] Allow controlled flushing for network manager
|
||||
|
||||
@ -110,8 +110,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
if (callbacks != null) {
|
||||
channelfuture.addListener((future) -> {
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
private boolean processQueue() {
|
||||
try { // Paper - add pending task queue
|
||||
if (this.queue.isEmpty()) return true;
|
||||
+ // Paper start - make only one flush call per sendPacketQueue() call
|
||||
+ final boolean needsFlush = this.canFlush;
|
||||
|
@ -1,89 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 19 Jun 2021 22:47:17 -0700
|
||||
Subject: [PATCH] Allow removal/addition of entities to entity ticklist during
|
||||
tick
|
||||
|
||||
It really doesn't make any sense that we would iterate over removed
|
||||
entities during tick. Sure - tick entity checks removed, but
|
||||
does it check if the entity is in an entity ticking chunk?
|
||||
No it doesn't. So, allowing removal while iteration
|
||||
ENSURES only entities MARKED TO TICK are ticked.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||
@@ -0,0 +0,0 @@ import javax.annotation.Nullable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
public class EntityTickList {
|
||||
- private Int2ObjectMap<Entity> active = new Int2ObjectLinkedOpenHashMap<>();
|
||||
- private Int2ObjectMap<Entity> passive = new Int2ObjectLinkedOpenHashMap<>();
|
||||
- @Nullable
|
||||
- private Int2ObjectMap<Entity> iterated;
|
||||
+ private final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Entity> entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking?
|
||||
|
||||
private void ensureActiveIsNotIterated() {
|
||||
- if (this.iterated == this.active) {
|
||||
- this.passive.clear();
|
||||
-
|
||||
- for(Int2ObjectMap.Entry<Entity> entry : Int2ObjectMaps.fastIterable(this.active)) {
|
||||
- this.passive.put(entry.getIntKey(), entry.getValue());
|
||||
- }
|
||||
-
|
||||
- Int2ObjectMap<Entity> int2ObjectMap = this.active;
|
||||
- this.active = this.passive;
|
||||
- this.passive = int2ObjectMap;
|
||||
- }
|
||||
+ // Paper - replace with better logic, do not delay removals
|
||||
|
||||
}
|
||||
|
||||
public void add(Entity entity) {
|
||||
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist addition"); // Paper
|
||||
this.ensureActiveIsNotIterated();
|
||||
- this.active.put(entity.getId(), entity);
|
||||
+ this.entities.add(entity); // Paper - replace with better logic, do not delay removals/additions
|
||||
}
|
||||
|
||||
public void remove(Entity entity) {
|
||||
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist removal"); // Paper
|
||||
this.ensureActiveIsNotIterated();
|
||||
- this.active.remove(entity.getId());
|
||||
+ this.entities.remove(entity); // Paper - replace with better logic, do not delay removals/additions
|
||||
}
|
||||
|
||||
public boolean contains(Entity entity) {
|
||||
- return this.active.containsKey(entity.getId());
|
||||
+ return this.entities.contains(entity); // Paper - replace with better logic, do not delay removals/additions
|
||||
}
|
||||
|
||||
public void forEach(Consumer<Entity> action) {
|
||||
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist iteration"); // Paper
|
||||
- if (this.iterated != null) {
|
||||
- throw new UnsupportedOperationException("Only one concurrent iteration supported");
|
||||
- } else {
|
||||
- this.iterated = this.active;
|
||||
-
|
||||
- try {
|
||||
- for(Entity entity : this.active.values()) {
|
||||
- action.accept(entity);
|
||||
- }
|
||||
- } finally {
|
||||
- this.iterated = null;
|
||||
+ // Paper start - replace with better logic, do not delay removals/additions
|
||||
+ // To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
|
||||
+ // (by dfl iterator() is configured to not iterate over new entries)
|
||||
+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = this.entities.iterator();
|
||||
+ try {
|
||||
+ while (iterator.hasNext()) {
|
||||
+ action.accept(iterator.next());
|
||||
}
|
||||
-
|
||||
+ } finally {
|
||||
+ iterator.finishedIterating();
|
||||
}
|
||||
+ // Paper end - replace with better logic, do not delay removals/additions
|
||||
}
|
||||
}
|
@ -1047,30 +1047,12 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/j
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
completablefuture1.thenAcceptAsync((either) -> {
|
||||
either.ifLeft((chunk) -> {
|
||||
this.tickingGenerated.getAndIncrement();
|
||||
- MutableObject<ClientboundLevelChunkWithLightPacket> mutableobject = new MutableObject();
|
||||
+ MutableObject<java.util.Map<Object, ClientboundLevelChunkWithLightPacket>> mutableobject = new MutableObject<>(); // Paper - Anti-Xray - Bypass
|
||||
|
||||
this.getPlayers(chunkcoordintpair, false).forEach((entityplayer) -> {
|
||||
this.playerLoadedChunk(entityplayer, mutableobject, chunk);
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
while (objectiterator.hasNext()) {
|
||||
ChunkHolder playerchunk = (ChunkHolder) objectiterator.next();
|
||||
ChunkPos chunkcoordintpair = playerchunk.getPos();
|
||||
- MutableObject<ClientboundLevelChunkWithLightPacket> mutableobject = new MutableObject();
|
||||
+ MutableObject<java.util.Map<Object, ClientboundLevelChunkWithLightPacket>> mutableobject = new MutableObject<>(); // Paper - Anti-Xray - Bypass
|
||||
|
||||
this.getPlayers(chunkcoordintpair, false).forEach((entityplayer) -> {
|
||||
SectionPos sectionposition = entityplayer.getLastSectionPos();
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
}
|
||||
|
||||
- protected void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject<ClientboundLevelChunkWithLightPacket> packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) {
|
||||
+ protected void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject<java.util.Map<Object, ClientboundLevelChunkWithLightPacket>> packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { // Paper - Anti-Xray - Bypass
|
||||
- public void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject<ClientboundLevelChunkWithLightPacket> packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { // Paper - public
|
||||
+ public void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject<java.util.Map<Object, ClientboundLevelChunkWithLightPacket>> packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { // Paper - public // Paper - Anti-Xray - Bypass
|
||||
if (player.level == this.level) {
|
||||
if (newWithinViewDistance && !oldWithinViewDistance) {
|
||||
ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong());
|
||||
@ -1205,9 +1187,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
public LevelChunk(Level world, ChunkPos pos, UpgradeData upgradeData, LevelChunkTicks<Block> blockTickScheduler, LevelChunkTicks<Fluid> fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sectionArrayInitializer, @Nullable LevelChunk.PostLoadProcessor entityLoader, @Nullable BlendingData blendingData) {
|
||||
- super(pos, upgradeData, world, world.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), inhabitedTime, sectionArrayInitializer, blendingData);
|
||||
+ super(pos, upgradeData, world, net.minecraft.server.MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), inhabitedTime, sectionArrayInitializer, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry
|
||||
this.tickersInLevel = Maps.newHashMap();
|
||||
this.clientLightReady = false;
|
||||
this.level = (ServerLevel) world; // CraftBukkit - type
|
||||
// Paper start - rewrite light engine
|
||||
this.setBlockNibbles(ca.spottedleaf.starlight.common.light.StarLightEngine.getFilledEmptyLight(world));
|
||||
this.setSkyNibbles(ca.spottedleaf.starlight.common.light.StarLightEngine.getFilledEmptyLight(world));
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@ -1560,7 +1542,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
List<ServerPlayer> playersInRange = playerChunk.playerProvider.getPlayers(playerChunk.getPos(), false);
|
||||
if (playersInRange.isEmpty()) return;
|
||||
if (playersInRange.isEmpty()) return true; // Paper - rewrite player chunk loader
|
||||
|
||||
- ClientboundLevelChunkWithLightPacket refreshPacket = new ClientboundLevelChunkWithLightPacket(chunk, this.world.getLightEngine(), null, null, true);
|
||||
+ // Paper start - Anti-Xray - Bypass
|
||||
@ -1575,8 +1557,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }));
|
||||
+ // Paper end
|
||||
}
|
||||
});
|
||||
});
|
||||
// Paper - rewrite player chunk loader
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
|
@ -16,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ this.getProfileCache().save(false); // Paper
|
||||
}
|
||||
// Spigot end
|
||||
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper
|
||||
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
|
@ -17,8 +17,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
private boolean addEntityUuid(T entity) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper
|
||||
if (!this.knownUuids.add(entity.getUUID())) {
|
||||
// Paper start
|
||||
T conflict = this.visibleEntityStorage.getEntity(entity.getUUID());
|
||||
PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity);
|
||||
return false;
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
@ -116,13 +116,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
while (!longset.isEmpty()) {
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
long i = SectionPos.asLong(blockposition); final long newSectionPos = i; // Paper - diff on change, new position section
|
||||
long i = SectionPos.asLong(blockposition);
|
||||
|
||||
if (i != this.currentSectionKey) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper
|
||||
PersistentEntitySectionManager.this.entitySliceManager.moveEntity((Entity)this.entity); // Paper
|
||||
Visibility visibility = this.currentSection.getStatus(); final Visibility oldVisibility = visibility; // Paper - diff on change - this should be OLD section visibility
|
||||
// Paper start
|
||||
Visibility visibility = this.currentSection.getStatus();
|
||||
|
||||
if (!this.currentSection.remove(this.entity)) {
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
|
||||
@Override
|
||||
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -694,7 +694,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
+ private final boolean isChunkData; // Paper
|
||||
+
|
||||
RegionFileStorage(Path directory, boolean dsync) {
|
||||
protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor
|
||||
+ // Paper start - add isChunkData param
|
||||
+ this(directory, dsync, false);
|
||||
+ }
|
||||
|
@ -1,124 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: CullanP <cullanpage@gmail.com>
|
||||
Date: Thu, 3 Mar 2016 02:13:38 -0600
|
||||
Subject: [PATCH] Avoid hopper searches if there are no items
|
||||
|
||||
Hoppers searching for items and minecarts is the most expensive part of hopper ticking.
|
||||
We keep track of the number of minecarts and items in a chunk.
|
||||
If there are no items in the chunk, we skip searching for items.
|
||||
If there are no minecarts in the chunk, we skip searching for them.
|
||||
|
||||
Usually hoppers aren't near items, so we can skip most item searches.
|
||||
And since minecart hoppers are used _very_ rarely near we can avoid alot of searching there.
|
||||
|
||||
Combined, this adds up a lot.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
- });
|
||||
+ }, predicate == net.minecraft.world.entity.EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper
|
||||
return list;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/EntitySection.java b/src/main/java/net/minecraft/world/level/entity/EntitySection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/EntitySection.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/EntitySection.java
|
||||
@@ -0,0 +0,0 @@ public class EntitySection<T extends EntityAccess> {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final ClassInstanceMultiMap<T> storage;
|
||||
private Visibility chunkStatus;
|
||||
+ // Paper start - track number of items and minecarts
|
||||
+ public int itemCount;
|
||||
+ public int inventoryEntityCount;
|
||||
+ // Paper end
|
||||
|
||||
public EntitySection(Class<T> entityClass, Visibility status) {
|
||||
this.chunkStatus = status;
|
||||
@@ -0,0 +0,0 @@ public class EntitySection<T extends EntityAccess> {
|
||||
}
|
||||
|
||||
public void add(T entity) {
|
||||
+ // Paper start
|
||||
+ if (entity instanceof net.minecraft.world.entity.item.ItemEntity) {
|
||||
+ this.itemCount++;
|
||||
+ } else if (entity instanceof net.minecraft.world.Container) {
|
||||
+ this.inventoryEntityCount++;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.storage.add(entity);
|
||||
}
|
||||
|
||||
public boolean remove(T entity) {
|
||||
+ // Paper start
|
||||
+ if (entity instanceof net.minecraft.world.entity.item.ItemEntity) {
|
||||
+ this.itemCount--;
|
||||
+ } else if (entity instanceof net.minecraft.world.Container) {
|
||||
+ this.inventoryEntityCount--;
|
||||
+ }
|
||||
+ // Paper end
|
||||
return this.storage.remove(entity);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java
|
||||
@@ -0,0 +0,0 @@ public class EntitySectionStorage<T extends EntityAccess> {
|
||||
}
|
||||
|
||||
public void getEntities(AABB box, Consumer<T> action) {
|
||||
+ // Paper start
|
||||
+ this.getEntities(box, action, false);
|
||||
+ }
|
||||
+ public void getEntities(AABB box, Consumer<T> action, boolean isContainerSearch) {
|
||||
+ // Paper end
|
||||
this.forEachAccessibleNonEmptySection(box, (section) -> {
|
||||
+ if (isContainerSearch && section.inventoryEntityCount <= 0) return; // Paper
|
||||
section.getEntities(box, action);
|
||||
});
|
||||
}
|
||||
|
||||
public <U extends T> void getEntities(EntityTypeTest<T, U> filter, AABB box, Consumer<U> action) {
|
||||
this.forEachAccessibleNonEmptySection(box, (section) -> {
|
||||
+ if (filter.getBaseClass() == net.minecraft.world.entity.item.ItemEntity.class && section.itemCount <= 0) return; // Paper
|
||||
section.getEntities(filter, box, action);
|
||||
});
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java
|
||||
@@ -0,0 +0,0 @@ public interface LevelEntityGetter<T extends EntityAccess> {
|
||||
<U extends T> void get(EntityTypeTest<T, U> filter, Consumer<U> action);
|
||||
|
||||
void get(AABB box, Consumer<T> action);
|
||||
+ void get(AABB box, Consumer<T> action, boolean isContainerSearch); // Paper
|
||||
|
||||
<U extends T> void get(EntityTypeTest<T, U> filter, AABB box, Consumer<U> action);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java
|
||||
@@ -0,0 +0,0 @@ public class LevelEntityGetterAdapter<T extends EntityAccess> implements LevelEn
|
||||
|
||||
@Override
|
||||
public void get(AABB box, Consumer<T> action) {
|
||||
- this.sectionStorage.getEntities(box, action);
|
||||
+ // Paper start
|
||||
+ this.get(box, action, false);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void get(AABB box, Consumer<T> action, boolean isContainerSearch) {
|
||||
+ this.sectionStorage.getEntities(box, action, isContainerSearch);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
@ -16,8 +16,8 @@ diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MCUtil.java
|
||||
+++ b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
@@ -0,0 +0,0 @@ import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet;
|
||||
import java.lang.ref.Cleaner;
|
||||
@@ -0,0 +0,0 @@ import java.lang.ref.Cleaner;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -23,8 +23,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException {
|
||||
RegionFile regionfile = this.getRegionFile(pos, false, true); // CraftBukkit // Paper
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
try { // Paper
|
||||
+ int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper
|
||||
|
||||
|
@ -1,432 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 1 Jun 2019 13:00:55 -0700
|
||||
Subject: [PATCH] Chunk debug command
|
||||
|
||||
Prints all chunk information to a text file into the debug
|
||||
folder in the root server folder. The format is in JSON, and
|
||||
the data format is described in MCUtil#dumpChunks(File)
|
||||
|
||||
The command will output server version and all online players to the
|
||||
file as well. We do not log anything but the location, world and
|
||||
username of the player.
|
||||
|
||||
Also logs the value of these config values (note not all are paper's):
|
||||
- keep spawn loaded value
|
||||
- spawn radius
|
||||
- view distance
|
||||
|
||||
Each chunk has the following logged:
|
||||
- Coordinate
|
||||
- Ticket level & its corresponding state
|
||||
- Whether it is queued for unload
|
||||
- Chunk status (may be unloaded)
|
||||
- All tickets on the chunk
|
||||
|
||||
Example log:
|
||||
https://gist.githubusercontent.com/Spottedleaf/0131e7710ffd5d531e5fd246c3367380/raw/169ae1b2e240485f99bc7a6bd8e78d90e3af7397/chunks-2019-06-01_19.57.05.txt
|
||||
|
||||
For references on certain keywords (ticket, status, etc), please see:
|
||||
|
||||
https://bugs.mojang.com/browse/MC-141484?focusedCommentId=528273&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-528273
|
||||
https://bugs.mojang.com/browse/MC-141484?focusedCommentId=528577&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-528577
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -0,0 +0,0 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
+import io.papermc.paper.command.subcommands.ChunkDebugCommand;
|
||||
import io.papermc.paper.command.subcommands.EntityCommand;
|
||||
import io.papermc.paper.command.subcommands.HeapDumpCommand;
|
||||
import io.papermc.paper.command.subcommands.ReloadCommand;
|
||||
@@ -0,0 +0,0 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("entity"), new EntityCommand());
|
||||
commands.put(Set.of("reload"), new ReloadCommand());
|
||||
commands.put(Set.of("version"), new VersionCommand());
|
||||
+ commands.put(Set.of("debug", "chunkinfo"), new ChunkDebugCommand());
|
||||
|
||||
return commands.entrySet().stream()
|
||||
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
||||
diff --git a/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.command.subcommands;
|
||||
+
|
||||
+import io.papermc.paper.command.CommandUtil;
|
||||
+import io.papermc.paper.command.PaperSubcommand;
|
||||
+import java.io.File;
|
||||
+import java.time.LocalDateTime;
|
||||
+import java.time.format.DateTimeFormatter;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+import java.util.Locale;
|
||||
+import net.minecraft.server.MCUtil;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ChunkHolder;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.BLUE;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.DARK_AQUA;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class ChunkDebugCommand implements PaperSubcommand {
|
||||
+ @Override
|
||||
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ switch (subCommand) {
|
||||
+ case "debug" -> this.doDebug(sender, args);
|
||||
+ case "chunkinfo" -> this.doChunkInfo(sender, args);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ switch (subCommand) {
|
||||
+ case "debug" -> {
|
||||
+ if (args.length == 1) {
|
||||
+ return CommandUtil.getListMatchingLast(sender, args, "help", "chunks");
|
||||
+ }
|
||||
+ }
|
||||
+ case "chunkinfo" -> {
|
||||
+ List<String> worldNames = new ArrayList<>();
|
||||
+ worldNames.add("*");
|
||||
+ for (org.bukkit.World world : Bukkit.getWorlds()) {
|
||||
+ worldNames.add(world.getName());
|
||||
+ }
|
||||
+ if (args.length == 1) {
|
||||
+ return CommandUtil.getListMatchingLast(sender, args, worldNames);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return Collections.emptyList();
|
||||
+ }
|
||||
+
|
||||
+ private void doChunkInfo(final CommandSender sender, final String[] args) {
|
||||
+ List<org.bukkit.World> worlds;
|
||||
+ if (args.length < 1 || args[0].equals("*")) {
|
||||
+ worlds = Bukkit.getWorlds();
|
||||
+ } else {
|
||||
+ worlds = new ArrayList<>(args.length);
|
||||
+ for (final String arg : args) {
|
||||
+ org.bukkit.@Nullable World world = Bukkit.getWorld(arg);
|
||||
+ if (world == null) {
|
||||
+ sender.sendMessage(text("World '" + arg + "' is invalid", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+ worlds.add(world);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ int accumulatedTotal = 0;
|
||||
+ int accumulatedInactive = 0;
|
||||
+ int accumulatedBorder = 0;
|
||||
+ int accumulatedTicking = 0;
|
||||
+ int accumulatedEntityTicking = 0;
|
||||
+
|
||||
+ for (final org.bukkit.World bukkitWorld : worlds) {
|
||||
+ final ServerLevel world = ((CraftWorld) bukkitWorld).getHandle();
|
||||
+
|
||||
+ int total = 0;
|
||||
+ int inactive = 0;
|
||||
+ int border = 0;
|
||||
+ int ticking = 0;
|
||||
+ int entityTicking = 0;
|
||||
+
|
||||
+ for (final ChunkHolder chunk : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(world)) {
|
||||
+ if (chunk.getFullChunkNowUnchecked() == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ++total;
|
||||
+
|
||||
+ ChunkHolder.FullChunkStatus state = chunk.getFullStatus();
|
||||
+
|
||||
+ switch (state) {
|
||||
+ case INACCESSIBLE -> ++inactive;
|
||||
+ case BORDER -> ++border;
|
||||
+ case TICKING -> ++ticking;
|
||||
+ case ENTITY_TICKING -> ++entityTicking;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ accumulatedTotal += total;
|
||||
+ accumulatedInactive += inactive;
|
||||
+ accumulatedBorder += border;
|
||||
+ accumulatedTicking += ticking;
|
||||
+ accumulatedEntityTicking += entityTicking;
|
||||
+
|
||||
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text(bukkitWorld.getName(), GREEN), text(":")));
|
||||
+ sender.sendMessage(text().color(DARK_AQUA).append(
|
||||
+ text("Total: ", BLUE), text(total),
|
||||
+ text(" Inactive: ", BLUE), text(inactive),
|
||||
+ text(" Border: ", BLUE), text(border),
|
||||
+ text(" Ticking: ", BLUE), text(ticking),
|
||||
+ text(" Entity: ", BLUE), text(entityTicking)
|
||||
+ ));
|
||||
+ }
|
||||
+ if (worlds.size() > 1) {
|
||||
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text("all listed worlds", GREEN), text(":", DARK_AQUA)));
|
||||
+ sender.sendMessage(text().color(DARK_AQUA).append(
|
||||
+ text("Total: ", BLUE), text(accumulatedTotal),
|
||||
+ text(" Inactive: ", BLUE), text(accumulatedInactive),
|
||||
+ text(" Border: ", BLUE), text(accumulatedBorder),
|
||||
+ text(" Ticking: ", BLUE), text(accumulatedTicking),
|
||||
+ text(" Entity: ", BLUE), text(accumulatedEntityTicking)
|
||||
+ ));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void doDebug(final CommandSender sender, final String[] args) {
|
||||
+ if (args.length < 1) {
|
||||
+ sender.sendMessage(text("Use /paper debug [chunks] help for more information on a specific command", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final String debugType = args[0].toLowerCase(Locale.ENGLISH);
|
||||
+ switch (debugType) {
|
||||
+ case "chunks" -> {
|
||||
+ if (args.length >= 2 && args[1].toLowerCase(Locale.ENGLISH).equals("help")) {
|
||||
+ sender.sendMessage(text("Use /paper debug chunks [world] to dump loaded chunk information to a file", RED));
|
||||
+ break;
|
||||
+ }
|
||||
+ File file = new File(new File(new File("."), "debug"),
|
||||
+ "chunks-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt");
|
||||
+ sender.sendMessage(text("Writing chunk information dump to " + file, GREEN));
|
||||
+ try {
|
||||
+ MCUtil.dumpChunks(file);
|
||||
+ sender.sendMessage(text("Successfully written chunk information!", GREEN));
|
||||
+ } catch (Throwable thr) {
|
||||
+ MinecraftServer.LOGGER.warn("Failed to dump chunk information to file " + file.toString(), thr);
|
||||
+ sender.sendMessage(text("Failed to dump chunk information, see console", RED));
|
||||
+ }
|
||||
+ }
|
||||
+ // "help" & default
|
||||
+ default -> sender.sendMessage(text("Use /paper debug [chunks] help for more information on a specific command", RED));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MCUtil.java
|
||||
+++ b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
@@ -0,0 +0,0 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
+import com.google.gson.JsonArray;
|
||||
+import com.google.gson.JsonObject;
|
||||
+import com.google.gson.internal.Streams;
|
||||
+import com.google.gson.stream.JsonWriter;
|
||||
+import com.mojang.datafixers.util.Either;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet;
|
||||
import java.lang.ref.Cleaner;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
+import net.minecraft.server.level.ChunkHolder;
|
||||
+import net.minecraft.server.level.ChunkMap;
|
||||
+import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.server.level.Ticket;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
+import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.BlockFace;
|
||||
@@ -0,0 +0,0 @@ import org.spigotmc.AsyncCatcher;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
+import java.io.*;
|
||||
+import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
+import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@@ -0,0 +0,0 @@ public final class MCUtil {
|
||||
}
|
||||
}
|
||||
|
||||
+ public static ChunkStatus getChunkStatus(ChunkHolder chunk) {
|
||||
+ return chunk.getChunkHolderStatus();
|
||||
+ }
|
||||
+
|
||||
+ public static void dumpChunks(File file) throws IOException {
|
||||
+ file.getParentFile().mkdirs();
|
||||
+ file.createNewFile();
|
||||
+ /*
|
||||
+ * Json format:
|
||||
+ *
|
||||
+ * Main data format:
|
||||
+ * -server-version:<string>
|
||||
+ * -data-version:<int>
|
||||
+ * -worlds:
|
||||
+ * -name:<world name>
|
||||
+ * -view-distance:<int>
|
||||
+ * -keep-spawn-loaded:<boolean>
|
||||
+ * -keep-spawn-loaded-range:<int>
|
||||
+ * -visible-chunk-count:<int>
|
||||
+ * -loaded-chunk-count:<int>
|
||||
+ * -verified-fully-loaded-chunks:<int>
|
||||
+ * -players:<array of player>
|
||||
+ * -chunk-data:<array of chunks>
|
||||
+ *
|
||||
+ * Player format:
|
||||
+ * -name:<string>
|
||||
+ * -x:<double>
|
||||
+ * -y:<double>
|
||||
+ * -z:<double>
|
||||
+ *
|
||||
+ * Chunk Format:
|
||||
+ * -x:<integer>
|
||||
+ * -z:<integer>
|
||||
+ * -ticket-level:<integer>
|
||||
+ * -state:<string>
|
||||
+ * -queued-for-unload:<boolean>
|
||||
+ * -status:<string>
|
||||
+ * -tickets:<array of tickets>
|
||||
+ *
|
||||
+ *
|
||||
+ * Ticket format:
|
||||
+ * -ticket-type:<string>
|
||||
+ * -ticket-level:<int>
|
||||
+ * -add-tick:<long>
|
||||
+ * -object-reason:<string> // This depends on the type of ticket. ie POST_TELEPORT -> entity id
|
||||
+ */
|
||||
+ List<org.bukkit.World> worlds = org.bukkit.Bukkit.getWorlds();
|
||||
+ JsonObject data = new JsonObject();
|
||||
+
|
||||
+ data.addProperty("server-version", org.bukkit.Bukkit.getVersion());
|
||||
+ data.addProperty("data-version", 0);
|
||||
+
|
||||
+ JsonArray worldsData = new JsonArray();
|
||||
+
|
||||
+ for (org.bukkit.World bukkitWorld : worlds) {
|
||||
+ JsonObject worldData = new JsonObject();
|
||||
+
|
||||
+ ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle();
|
||||
+ ChunkMap chunkMap = world.getChunkSource().chunkMap;
|
||||
+ DistanceManager chunkMapDistance = chunkMap.distanceManager;
|
||||
+ List<ChunkHolder> allChunks = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(world);
|
||||
+ List<ServerPlayer> players = world.players;
|
||||
+
|
||||
+ int fullLoadedChunks = 0;
|
||||
+
|
||||
+ for (ChunkHolder chunk : allChunks) {
|
||||
+ if (chunk.getFullChunkNowUnchecked() != null) {
|
||||
+ ++fullLoadedChunks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // sorting by coordinate makes the log easier to read
|
||||
+ allChunks.sort((ChunkHolder v1, ChunkHolder v2) -> {
|
||||
+ if (v1.pos.x != v2.pos.x) {
|
||||
+ return Integer.compare(v1.pos.x, v2.pos.x);
|
||||
+ }
|
||||
+ return Integer.compare(v1.pos.z, v2.pos.z);
|
||||
+ });
|
||||
+
|
||||
+ worldData.addProperty("name", world.getWorld().getName());
|
||||
+ worldData.addProperty("view-distance", world.spigotConfig.viewDistance);
|
||||
+ worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory);
|
||||
+ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16);
|
||||
+ worldData.addProperty("visible-chunk-count", allChunks.size());
|
||||
+ worldData.addProperty("loaded-chunk-count", chunkMap.entitiesInLevel.size());
|
||||
+ worldData.addProperty("verified-fully-loaded-chunks", fullLoadedChunks);
|
||||
+
|
||||
+ JsonArray playersData = new JsonArray();
|
||||
+
|
||||
+ for (ServerPlayer player : players) {
|
||||
+ JsonObject playerData = new JsonObject();
|
||||
+
|
||||
+ playerData.addProperty("name", player.getScoreboardName());
|
||||
+ playerData.addProperty("x", player.getX());
|
||||
+ playerData.addProperty("y", player.getY());
|
||||
+ playerData.addProperty("z", player.getZ());
|
||||
+
|
||||
+ playersData.add(playerData);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ worldData.add("players", playersData);
|
||||
+
|
||||
+ JsonArray chunksData = new JsonArray();
|
||||
+
|
||||
+ for (ChunkHolder playerChunk : allChunks) {
|
||||
+ JsonObject chunkData = new JsonObject();
|
||||
+
|
||||
+ Set<Ticket<?>> tickets = chunkMapDistance.tickets.get(playerChunk.pos.longKey);
|
||||
+ ChunkStatus status = getChunkStatus(playerChunk);
|
||||
+
|
||||
+ chunkData.addProperty("x", playerChunk.pos.x);
|
||||
+ chunkData.addProperty("z", playerChunk.pos.z);
|
||||
+ chunkData.addProperty("ticket-level", playerChunk.getTicketLevel());
|
||||
+ chunkData.addProperty("state", ChunkHolder.getFullChunkStatus(playerChunk.getTicketLevel()).toString());
|
||||
+ chunkData.addProperty("queued-for-unload", chunkMap.toDrop.contains(playerChunk.pos.longKey));
|
||||
+ chunkData.addProperty("status", status == null ? "unloaded" : status.toString());
|
||||
+
|
||||
+ JsonArray ticketsData = new JsonArray();
|
||||
+
|
||||
+ if (tickets != null) {
|
||||
+ for (Ticket<?> ticket : tickets) {
|
||||
+ JsonObject ticketData = new JsonObject();
|
||||
+
|
||||
+ ticketData.addProperty("ticket-type", ticket.getType().toString());
|
||||
+ ticketData.addProperty("ticket-level", ticket.getTicketLevel());
|
||||
+ ticketData.addProperty("object-reason", String.valueOf(ticket.key));
|
||||
+ ticketData.addProperty("add-tick", ticket.createdTick);
|
||||
+
|
||||
+ ticketsData.add(ticketData);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ chunkData.add("tickets", ticketsData);
|
||||
+ chunksData.add(chunkData);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ worldData.add("chunk-data", chunksData);
|
||||
+ worldsData.add(worldData);
|
||||
+ }
|
||||
+
|
||||
+ data.add("worlds", worldsData);
|
||||
+
|
||||
+ StringWriter stringWriter = new StringWriter();
|
||||
+ JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
+ jsonWriter.setIndent(" ");
|
||||
+ jsonWriter.setLenient(false);
|
||||
+ Streams.write(data, jsonWriter);
|
||||
+
|
||||
+ String fileData = stringWriter.toString();
|
||||
+
|
||||
+ try (PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)) {
|
||||
+ out.print(fileData);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) {
|
||||
return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status);
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Wed, 29 May 2019 04:01:22 +0100
|
||||
Subject: [PATCH] ChunkMapDistance CME
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
private boolean resendLight;
|
||||
private CompletableFuture<Void> pendingFullStateConfirmation;
|
||||
|
||||
+ boolean isUpdateQueued = false; // Paper
|
||||
private final ChunkMap chunkMap; // Paper
|
||||
|
||||
// Paper start
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
|
||||
private final TickingTracker tickingTicketsTracker = new TickingTracker();
|
||||
private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33);
|
||||
- final Set<ChunkHolder> chunksToUpdateFutures = Sets.newHashSet();
|
||||
+ // Paper start use a queue, but still keep unique requirement
|
||||
+ public final java.util.Queue<ChunkHolder> pendingChunkUpdates = new java.util.ArrayDeque<ChunkHolder>() {
|
||||
+ @Override
|
||||
+ public boolean add(ChunkHolder o) {
|
||||
+ if (o.isUpdateQueued) return true;
|
||||
+ o.isUpdateQueued = true;
|
||||
+ return super.add(o);
|
||||
+ }
|
||||
+ };
|
||||
+ // Paper end
|
||||
final ChunkTaskPriorityQueueSorter ticketThrottler;
|
||||
final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> ticketThrottlerInput;
|
||||
final ProcessorHandle<ChunkTaskPriorityQueueSorter.Release> ticketThrottlerReleaser;
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
;
|
||||
}
|
||||
|
||||
- if (!this.chunksToUpdateFutures.isEmpty()) {
|
||||
- // CraftBukkit start
|
||||
- // Iterate pending chunk updates with protection against concurrent modification exceptions
|
||||
- java.util.Iterator<ChunkHolder> iter = this.chunksToUpdateFutures.iterator();
|
||||
- int expectedSize = this.chunksToUpdateFutures.size();
|
||||
- do {
|
||||
- ChunkHolder playerchunk = iter.next();
|
||||
- iter.remove();
|
||||
- expectedSize--;
|
||||
-
|
||||
- playerchunk.updateFutures(chunkStorage, this.mainThreadExecutor);
|
||||
-
|
||||
- // Reset iterator if set was modified using add()
|
||||
- if (this.chunksToUpdateFutures.size() != expectedSize) {
|
||||
- expectedSize = this.chunksToUpdateFutures.size();
|
||||
- iter = this.chunksToUpdateFutures.iterator();
|
||||
- }
|
||||
- } while (iter.hasNext());
|
||||
- // CraftBukkit end
|
||||
-
|
||||
+ // Paper start
|
||||
+ if (!this.pendingChunkUpdates.isEmpty()) {
|
||||
+ while(!this.pendingChunkUpdates.isEmpty()) {
|
||||
+ ChunkHolder remove = this.pendingChunkUpdates.remove();
|
||||
+ remove.isUpdateQueued = false;
|
||||
+ remove.updateFutures(chunkStorage, this.mainThreadExecutor);
|
||||
+ }
|
||||
+ // Paper end
|
||||
return true;
|
||||
} else {
|
||||
if (!this.ticketsToRelease.isEmpty()) {
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
if (k != level) {
|
||||
playerchunk = DistanceManager.this.updateChunkScheduling(id, level, playerchunk, k);
|
||||
if (playerchunk != null) {
|
||||
- DistanceManager.this.chunksToUpdateFutures.add(playerchunk);
|
||||
+ DistanceManager.this.pendingChunkUpdates.add(playerchunk);
|
||||
}
|
||||
|
||||
}
|
@ -1412,6 +1412,160 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/ca/spottedleaf/concurrentutil/collection/SRSWLinkedQueue.java b/src/main/java/ca/spottedleaf/concurrentutil/collection/SRSWLinkedQueue.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/ca/spottedleaf/concurrentutil/collection/SRSWLinkedQueue.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package ca.spottedleaf.concurrentutil.collection;
|
||||
+
|
||||
+import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
|
||||
+import ca.spottedleaf.concurrentutil.util.Validate;
|
||||
+import java.lang.invoke.VarHandle;
|
||||
+import java.util.ConcurrentModificationException;
|
||||
+
|
||||
+/**
|
||||
+ * Single reader thread single writer thread queue. The reader side of the queue is ordered by acquire semantics,
|
||||
+ * and the writer side of the queue is ordered by release semantics.
|
||||
+ */
|
||||
+// TODO test
|
||||
+public class SRSWLinkedQueue<E> {
|
||||
+
|
||||
+ // always non-null
|
||||
+ protected LinkedNode<E> head;
|
||||
+
|
||||
+ // always non-null
|
||||
+ protected LinkedNode<E> tail;
|
||||
+
|
||||
+ /* IMPL NOTE: Leave hashCode and equals to their defaults */
|
||||
+
|
||||
+ public SRSWLinkedQueue() {
|
||||
+ final LinkedNode<E> dummy = new LinkedNode<>(null, null);
|
||||
+ this.head = this.tail = dummy;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Must be the reader thread.
|
||||
+ *
|
||||
+ * <p>
|
||||
+ * Returns, without removing, the first element of this queue.
|
||||
+ * </p>
|
||||
+ * @return Returns, without removing, the first element of this queue.
|
||||
+ */
|
||||
+ public E peekFirst() {
|
||||
+ LinkedNode<E> head = this.head;
|
||||
+ E ret = head.getElementPlain();
|
||||
+ if (ret == null) {
|
||||
+ head = head.getNextAcquire();
|
||||
+ if (head == null) {
|
||||
+ // empty
|
||||
+ return null;
|
||||
+ }
|
||||
+ // update head reference for next poll() call
|
||||
+ this.head = head;
|
||||
+ // guaranteed to be non-null
|
||||
+ ret = head.getElementPlain();
|
||||
+ if (ret == null) {
|
||||
+ throw new ConcurrentModificationException("Multiple reader threads");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Must be the reader thread.
|
||||
+ *
|
||||
+ * <p>
|
||||
+ * Returns and removes the first element of this queue.
|
||||
+ * </p>
|
||||
+ * @return Returns and removes the first element of this queue.
|
||||
+ */
|
||||
+ public E poll() {
|
||||
+ LinkedNode<E> head = this.head;
|
||||
+ E ret = head.getElementPlain();
|
||||
+ if (ret == null) {
|
||||
+ head = head.getNextAcquire();
|
||||
+ if (head == null) {
|
||||
+ // empty
|
||||
+ return null;
|
||||
+ }
|
||||
+ // guaranteed to be non-null
|
||||
+ ret = head.getElementPlain();
|
||||
+ if (ret == null) {
|
||||
+ throw new ConcurrentModificationException("Multiple reader threads");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ head.setElementPlain(null);
|
||||
+ LinkedNode<E> next = head.getNextAcquire();
|
||||
+ this.head = next == null ? head : next;
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Must be the writer thread.
|
||||
+ *
|
||||
+ * <p>
|
||||
+ * Adds the element to the end of the queue.
|
||||
+ * </p>
|
||||
+ *
|
||||
+ * @throws NullPointerException If the provided element is null
|
||||
+ */
|
||||
+ public void addLast(final E element) {
|
||||
+ Validate.notNull(element, "Provided element cannot be null");
|
||||
+ final LinkedNode<E> append = new LinkedNode<>(element, null);
|
||||
+
|
||||
+ this.tail.setNextRelease(append);
|
||||
+ this.tail = append;
|
||||
+ }
|
||||
+
|
||||
+ protected static final class LinkedNode<E> {
|
||||
+
|
||||
+ protected volatile Object element;
|
||||
+ protected volatile LinkedNode<E> next;
|
||||
+
|
||||
+ protected static final VarHandle ELEMENT_HANDLE = ConcurrentUtil.getVarHandle(LinkedNode.class, "element", Object.class);
|
||||
+ protected static final VarHandle NEXT_HANDLE = ConcurrentUtil.getVarHandle(LinkedNode.class, "next", LinkedNode.class);
|
||||
+
|
||||
+ protected LinkedNode(final Object element, final LinkedNode<E> next) {
|
||||
+ ELEMENT_HANDLE.set(this, element);
|
||||
+ NEXT_HANDLE.set(this, next);
|
||||
+ }
|
||||
+
|
||||
+ /* element */
|
||||
+
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ protected final E getElementPlain() {
|
||||
+ return (E)ELEMENT_HANDLE.get(this);
|
||||
+ }
|
||||
+
|
||||
+ protected final void setElementPlain(final E update) {
|
||||
+ ELEMENT_HANDLE.set(this, (Object)update);
|
||||
+ }
|
||||
+ /* next */
|
||||
+
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ protected final LinkedNode<E> getNextPlain() {
|
||||
+ return (LinkedNode<E>)NEXT_HANDLE.get(this);
|
||||
+ }
|
||||
+
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ protected final LinkedNode<E> getNextAcquire() {
|
||||
+ return (LinkedNode<E>)NEXT_HANDLE.getAcquire(this);
|
||||
+ }
|
||||
+
|
||||
+ protected final void setNextPlain(final LinkedNode<E> next) {
|
||||
+ NEXT_HANDLE.set(this, next);
|
||||
+ }
|
||||
+
|
||||
+ protected final void setNextRelease(final LinkedNode<E> next) {
|
||||
+ NEXT_HANDLE.setRelease(this, next);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/ca/spottedleaf/concurrentutil/completable/Completable.java b/src/main/java/ca/spottedleaf/concurrentutil/completable/Completable.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
@ -1575,11 +1729,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ * @throws IllegalStateException If the current thread is not allowed to wait
|
||||
+ */
|
||||
+ public default void waitUntilAllExecuted() throws IllegalStateException {
|
||||
+ long failures = 9L; // start out at 1ms
|
||||
+ long failures = 1L; // start at 0.25ms
|
||||
+
|
||||
+ while (!this.haveAllTasksExecuted()) {
|
||||
+ Thread.yield();
|
||||
+ failures = ConcurrentUtil.linearLongBackoff(failures, 500_000L, 5_000_000L); // 500us, 5ms
|
||||
+ failures = ConcurrentUtil.linearLongBackoff(failures, 250_000L, 5_000_000L); // 500us, 5ms
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 4 Apr 2020 17:00:20 -0700
|
||||
Subject: [PATCH] Consolidate flush calls for entity tracker packets
|
||||
|
||||
|
@ -1,37 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 21 Mar 2021 17:32:47 -0700
|
||||
Subject: [PATCH] Correctly handle recursion for chunkholder updates
|
||||
|
||||
If a chunk ticket level is brought up while unloading it would
|
||||
cause a recursive call which would handle the increase but then
|
||||
the caller would think the chunk would be unloaded.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
playerchunkmap.onFullChunkStatusChange(this.pos, playerchunk_state);
|
||||
}
|
||||
|
||||
+ protected long updateCount; // Paper - correctly handle recursion
|
||||
protected void updateFutures(ChunkMap chunkStorage, Executor executor) {
|
||||
io.papermc.paper.util.TickThread.ensureTickThread("Async ticket level update"); // Paper
|
||||
+ long updateCount = ++this.updateCount; // Paper - correctly handle recursion
|
||||
ChunkStatus chunkstatus = ChunkHolder.getStatus(this.oldTicketLevel);
|
||||
ChunkStatus chunkstatus1 = ChunkHolder.getStatus(this.ticketLevel);
|
||||
boolean flag = this.oldTicketLevel <= ChunkMap.MAX_CHUNK_DISTANCE;
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
|
||||
// Run callback right away if the future was already done
|
||||
chunkStorage.callbackExecutor.run();
|
||||
+ // Paper start - correctly handle recursion
|
||||
+ if (this.updateCount != updateCount) {
|
||||
+ // something else updated ticket level for us.
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - correctly handle recursion
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
@ -1,89 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 18 Jun 2016 23:22:12 -0400
|
||||
Subject: [PATCH] Delay Chunk Unloads based on Player Movement
|
||||
|
||||
When players are moving in the world, doing things such as building or exploring,
|
||||
they will commonly go back and forth in a small area. This causes a ton of chunk load
|
||||
and unload activity on the edge chunks of their view distance.
|
||||
|
||||
A simple back and forth movement in 6 blocks could spam a chunk to thrash a
|
||||
loading and unload cycle over and over again.
|
||||
|
||||
This is very wasteful. This system introduces a delay of inactivity on a chunk
|
||||
before it actually unloads, which will be handled by the ticket expiry process.
|
||||
|
||||
This allows servers with smaller worlds who do less long distance exploring to stop
|
||||
wasting cpu cycles on saving/unloading/reloading chunks repeatedly.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
boolean removed = false; // CraftBukkit
|
||||
if (arraysetsorted.remove(ticket)) {
|
||||
removed = true; // CraftBukkit
|
||||
+ // Paper start - delay chunk unloads for player tickets
|
||||
+ long delayChunkUnloadsBy = chunkMap.level.paperConfig().chunks.delayChunkUnloadsBy.ticks();
|
||||
+ if (ticket.getType() == TicketType.PLAYER && delayChunkUnloadsBy > 0) {
|
||||
+ boolean hasPlayer = false;
|
||||
+ for (Ticket<?> ticket1 : arraysetsorted) {
|
||||
+ if (ticket1.getType() == TicketType.PLAYER) {
|
||||
+ hasPlayer = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ ChunkHolder playerChunk = chunkMap.getUpdatingChunkIfPresent(i);
|
||||
+ if (!hasPlayer && playerChunk != null && playerChunk.isFullChunkReady()) {
|
||||
+ Ticket<Long> delayUnload = new Ticket<Long>(TicketType.DELAY_UNLOAD, 33, i);
|
||||
+ delayUnload.delayUnloadBy = delayChunkUnloadsBy;
|
||||
+ delayUnload.setCreatedTick(this.ticketTickCounter);
|
||||
+ arraysetsorted.remove(delayUnload);
|
||||
+ // refresh ticket
|
||||
+ arraysetsorted.add(delayUnload);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
if (arraysetsorted.isEmpty()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/Ticket.java b/src/main/java/net/minecraft/server/level/Ticket.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/Ticket.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/Ticket.java
|
||||
@@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
|
||||
private final int ticketLevel;
|
||||
public final T key;
|
||||
public long createdTick;
|
||||
+ public long delayUnloadBy; // Paper
|
||||
|
||||
protected Ticket(TicketType<T> type, int level, T argument) {
|
||||
this.type = type;
|
||||
this.ticketLevel = level;
|
||||
this.key = argument;
|
||||
+ this.delayUnloadBy = type.timeout; // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
|
||||
}
|
||||
|
||||
protected boolean timedOut(long currentTick) {
|
||||
- long l = this.type.timeout();
|
||||
+ long l = delayUnloadBy; // Paper
|
||||
return l != 0L && currentTick - this.createdTick > l;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
@@ -0,0 +0,0 @@ public class TicketType<T> {
|
||||
public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
|
||||
public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
|
||||
public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
|
||||
+ public static final TicketType<Long> DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper
|
||||
|
||||
public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) {
|
||||
return new TicketType<>(name, argumentComparator, 0L);
|
@ -571,7 +571,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" );
|
||||
log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" );
|
||||
log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
|
||||
@ -580,7 +580,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
{
|
||||
log.log( Level.SEVERE, "\t\t" + stack );
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
}
|
||||
log.log( Level.SEVERE, "\tStack:" );
|
||||
//
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 26 Mar 2020 21:59:32 -0700
|
||||
Subject: [PATCH] Detail more information in watchdog dumps
|
||||
|
||||
@ -208,7 +208,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
private volatile long lastTick;
|
||||
private volatile boolean stopping;
|
||||
|
||||
@ -287,11 +287,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
private WatchdogThread(long timeoutTime, boolean restart)
|
||||
{
|
||||
super( "Paper Watchdog Thread" );
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system
|
||||
+ this.dumpTickingInfo(); // Paper - log detailed tick information
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( server.serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 18 Jul 2020 16:03:57 -0700
|
||||
Subject: [PATCH] Distance manager tick timings
|
||||
|
||||
@ -18,23 +18,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks");
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
public boolean runDistanceManagerUpdates() {
|
||||
if (distanceManager.delayDistanceManagerTick) return false; // Paper - Chunk priority
|
||||
if (this.chunkMap.unloadingPlayerChunk) { LOGGER.error("Cannot tick distance manager while unloading playerchunks", new Throwable()); throw new IllegalStateException("Cannot tick distance manager while unloading playerchunks"); } // Paper
|
||||
+ co.aikar.timings.MinecraftTimings.distanceManagerTick.startTiming(); try { // Paper - add timings for distance manager
|
||||
boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
|
||||
boolean flag1 = this.chunkMap.promoteChunkMap();
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
this.clearCache();
|
||||
return true;
|
||||
}
|
||||
public boolean processTicketUpdates() {
|
||||
+ co.aikar.timings.MinecraftTimings.distanceManagerTick.startTiming(); try { // Paper - add timings for distance manager
|
||||
return this.processTicketUpdates(true, true, null);
|
||||
+ } finally { co.aikar.timings.MinecraftTimings.distanceManagerTick.stopTiming(); } // Paper - add timings for distance manager
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private static final ThreadLocal<List<ChunkProgressionTask>> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>();
|
||||
|
@ -1,23 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 11 Mar 2021 02:32:30 -0800
|
||||
Subject: [PATCH] Do not allow the server to unload chunks at request of
|
||||
plugins
|
||||
|
||||
In general the chunk system is not well suited for this behavior,
|
||||
especially if it is called during a chunk load. The chunks pushed
|
||||
to be unloaded will simply be unloaded next tick, rather than
|
||||
immediately.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
|
||||
// CraftBukkit start - modelled on below
|
||||
public void purgeUnload() {
|
||||
+ if (true) return; // Paper - tickets will be removed later, this behavior isn't really well accounted for by the chunk system
|
||||
this.level.getProfiler().push("purge");
|
||||
this.distanceManager.purgeStaleTickets();
|
||||
this.runDistanceManagerUpdates();
|
@ -1,40 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 20 Jun 2021 00:08:13 -0700
|
||||
Subject: [PATCH] Do not allow ticket level changes when updating chunk ticking
|
||||
state
|
||||
|
||||
This WILL cause state corruption if it happens. So, don't
|
||||
allow it.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
CompletableFuture<Void> completablefuture1 = new CompletableFuture();
|
||||
|
||||
completablefuture1.thenRunAsync(() -> {
|
||||
+ // Paper start - do not allow ticket level changes
|
||||
+ boolean unloadingBefore = this.chunkMap.unloadingPlayerChunk;
|
||||
+ this.chunkMap.unloadingPlayerChunk = true;
|
||||
+ try {
|
||||
+ // Paper end - do not allow ticket level changes
|
||||
playerchunkmap.onFullChunkStatusChange(this.pos, playerchunk_state);
|
||||
+ } finally { this.chunkMap.unloadingPlayerChunk = unloadingBefore; } // Paper - do not allow ticket level changes
|
||||
}, executor);
|
||||
this.pendingFullStateConfirmation = completablefuture1;
|
||||
completablefuture.thenAccept((either) -> {
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
|
||||
private void demoteFullChunk(ChunkMap playerchunkmap, ChunkHolder.FullChunkStatus playerchunk_state) {
|
||||
this.pendingFullStateConfirmation.cancel(false);
|
||||
+ // Paper start - do not allow ticket level changes
|
||||
+ boolean unloadingBefore = this.chunkMap.unloadingPlayerChunk;
|
||||
+ this.chunkMap.unloadingPlayerChunk = true;
|
||||
+ try { // Paper end - do not allow ticket level changes
|
||||
playerchunkmap.onFullChunkStatusChange(this.pos, playerchunk_state);
|
||||
+ } finally { this.chunkMap.unloadingPlayerChunk = unloadingBefore; } // Paper - do not allow ticket level changes
|
||||
}
|
||||
|
||||
protected long updateCount; // Paper - correctly handle recursion
|
@ -1,62 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
Date: Sat, 19 Sep 2020 15:29:16 -0700
|
||||
Subject: [PATCH] Do not allow ticket level changes while unloading
|
||||
playerchunks
|
||||
|
||||
Sync loading the chunk at this stage would cause it to load
|
||||
older data, as well as screwing our region state.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks
|
||||
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
|
||||
super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
|
||||
// Paper - don't copy
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
@Nullable
|
||||
ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k) {
|
||||
+ if (this.unloadingPlayerChunk) { net.minecraft.server.MinecraftServer.LOGGER.error("Cannot tick distance manager while unloading playerchunks", new Throwable()); throw new IllegalStateException("Cannot tick distance manager while unloading playerchunks"); } // Paper
|
||||
if (k > ChunkMap.MAX_CHUNK_DISTANCE && level > ChunkMap.MAX_CHUNK_DISTANCE) {
|
||||
return holder;
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
if (completablefuture1 != completablefuture) {
|
||||
this.scheduleUnload(pos, holder);
|
||||
} else {
|
||||
+ // Paper start - do not allow ticket level changes while unloading chunks
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("playerchunk unload");
|
||||
+ boolean unloadingBefore = this.unloadingPlayerChunk;
|
||||
+ this.unloadingPlayerChunk = true;
|
||||
+ try {
|
||||
+ // Paper end - do not allow ticket level changes while unloading chunks
|
||||
// Paper start
|
||||
boolean removed;
|
||||
if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) {
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
} else if (removed) { // Paper start
|
||||
net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder);
|
||||
} // Paper end
|
||||
+ } finally { this.unloadingPlayerChunk = unloadingBefore; } // Paper - do not allow ticket level changes while unloading chunks
|
||||
|
||||
}
|
||||
};
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
|
||||
public boolean runDistanceManagerUpdates() {
|
||||
if (distanceManager.delayDistanceManagerTick) return false; // Paper - Chunk priority
|
||||
+ if (this.chunkMap.unloadingPlayerChunk) { LOGGER.error("Cannot tick distance manager while unloading playerchunks", new Throwable()); throw new IllegalStateException("Cannot tick distance manager while unloading playerchunks"); } // Paper
|
||||
boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
|
||||
boolean flag1 = this.chunkMap.promoteChunkMap();
|
||||
|
@ -1,122 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 21 Mar 2021 11:22:10 -0700
|
||||
Subject: [PATCH] Do not copy visible chunks
|
||||
|
||||
For servers with a lot of chunk holders, copying for each
|
||||
tickDistanceManager call can take up quite a bit in
|
||||
the function. I saw approximately 1/3rd of the function
|
||||
on the copy.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/ChunkSystem.java
|
||||
+++ b/src/main/java/net/minecraft/server/ChunkSystem.java
|
||||
@@ -0,0 +0,0 @@ public final class ChunkSystem {
|
||||
}
|
||||
|
||||
public static List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level) {
|
||||
- return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values());
|
||||
+ if (Bukkit.isPrimaryThread()) {
|
||||
+ return level.chunkSource.chunkMap.updatingChunks.getVisibleValuesCopy();
|
||||
+ }
|
||||
+ synchronized (level.chunkSource.chunkMap.updatingChunks) {
|
||||
+ return level.chunkSource.chunkMap.updatingChunks.getVisibleValuesCopy();
|
||||
+ }
|
||||
}
|
||||
|
||||
public static List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level) {
|
||||
- return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values());
|
||||
+ return level.chunkSource.chunkMap.updatingChunks.getUpdatingValuesCopy();
|
||||
}
|
||||
|
||||
public static int getVisibleChunkHolderCount(final ServerLevel level) {
|
||||
- return level.chunkSource.chunkMap.visibleChunkMap.size();
|
||||
+ return level.chunkSource.chunkMap.updatingChunks.getVisibleMap().size();
|
||||
}
|
||||
|
||||
public static int getUpdatingChunkHolderCount(final ServerLevel level) {
|
||||
- return level.chunkSource.chunkMap.updatingChunkMap.size();
|
||||
+ return level.chunkSource.chunkMap.updatingChunks.getUpdatingMap().size();
|
||||
}
|
||||
|
||||
public static boolean hasAnyChunkHolders(final ServerLevel level) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
private static final int MIN_VIEW_DISTANCE = 3;
|
||||
public static final int MAX_VIEW_DISTANCE = 33;
|
||||
public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance();
|
||||
+ // Paper start - Don't copy
|
||||
+ public final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<ChunkHolder> updatingChunks = new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>();
|
||||
+ // Paper end - Don't copy
|
||||
public static final int FORCED_TICKET_LEVEL = 31;
|
||||
- public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap();
|
||||
- public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
|
||||
+ // Paper - Don't copy
|
||||
private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads;
|
||||
public final LongSet entitiesInLevel;
|
||||
public final ServerLevel level;
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
|
||||
super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
|
||||
- this.visibleChunkMap = this.updatingChunkMap.clone();
|
||||
+ // Paper - don't copy
|
||||
this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
|
||||
this.entitiesInLevel = new LongOpenHashSet();
|
||||
this.toDrop = new LongOpenHashSet();
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
@Nullable
|
||||
public ChunkHolder getUpdatingChunkIfPresent(long pos) {
|
||||
- return (ChunkHolder) this.updatingChunkMap.get(pos);
|
||||
+ return this.updatingChunks.getUpdating(pos); // Paper - Don't copy
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ChunkHolder getVisibleChunkIfPresent(long pos) {
|
||||
- return (ChunkHolder) this.visibleChunkMap.get(pos);
|
||||
+ // Paper start - Don't copy
|
||||
+ if (Thread.currentThread() == this.level.thread) {
|
||||
+ return this.updatingChunks.getVisible(pos);
|
||||
+ }
|
||||
+ return this.updatingChunks.getVisibleAsync(pos);
|
||||
+ // Paper end - Don't copy
|
||||
}
|
||||
|
||||
protected IntSupplier getChunkQueueLevel(long pos) {
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// Paper start
|
||||
holder.onChunkAdd();
|
||||
// Paper end
|
||||
- this.updatingChunkMap.put(pos, holder);
|
||||
+ this.updatingChunks.queueUpdate(pos, holder); // Paper - Don't copy
|
||||
this.modified = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) {
|
||||
long j = longiterator.nextLong();
|
||||
- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j);
|
||||
+ ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy
|
||||
|
||||
if (playerchunk != null) {
|
||||
playerchunk.onChunkRemove(); // Paper
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
if (!this.modified) {
|
||||
return false;
|
||||
} else {
|
||||
- this.visibleChunkMap = this.updatingChunkMap.clone();
|
||||
+ // Paper start - Don't copy
|
||||
+ synchronized (this.updatingChunks) {
|
||||
+ this.updatingChunks.performUpdates();
|
||||
+ }
|
||||
+ // Paper end - Don't copy
|
||||
+
|
||||
this.modified = false;
|
||||
return true;
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Fri, 3 Sep 2021 15:50:25 +0100
|
||||
Subject: [PATCH] Do not process entity loads in CraftChunk#getEntities
|
||||
|
||||
This re-introduces the issue behind #5872 but fixes #6543
|
||||
The logic here is generally flawed however somewhat of a nuance,
|
||||
upstream uses managedBlock which is basically needed to process
|
||||
the posted entity adds, but, has the side-effect of processing any
|
||||
chunk loads which has the naunce of stacking up and either causing a
|
||||
massive performance hit, or can potentially lead the server to crash.
|
||||
|
||||
This issue is particularly noticable on paper due to the cumulative efforts
|
||||
to drastically improve chunk loading speeds which means that there is much more
|
||||
of a chance that we're about to eat a dirtload of chunk load callbacks, thus
|
||||
making this issue much more of an issue
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -0,0 +0,0 @@ public class CraftChunk implements Chunk {
|
||||
this.getWorld().getChunkAt(x, z); // Transient load for this tick
|
||||
}
|
||||
|
||||
- PersistentEntitySectionManager<net.minecraft.world.entity.Entity> entityManager = this.getCraftWorld().getHandle().entityManager;
|
||||
- long pair = ChunkPos.asLong(x, z);
|
||||
-
|
||||
- if (entityManager.areEntitiesLoaded(pair)) {
|
||||
- return getCraftWorld().getHandle().getChunkEntities(this.x, this.z); // Paper - optimise this
|
||||
- }
|
||||
-
|
||||
- entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading
|
||||
-
|
||||
- // SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded
|
||||
- ProcessorMailbox<Runnable> mailbox = ((EntityStorage) entityManager.permanentStorage).entityDeserializerQueue;
|
||||
- BooleanSupplier supplier = () -> {
|
||||
- // only execute inbox if our entities are not present
|
||||
- if (entityManager.areEntitiesLoaded(pair)) {
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- if (!entityManager.isPending(pair)) {
|
||||
- // Our entities got unloaded, this should normally not happen.
|
||||
- entityManager.ensureChunkQueuedForLoad(pair); // Re-start entity loading
|
||||
- }
|
||||
-
|
||||
- // tick loading inbox, which loads the created entities to the world
|
||||
- // (if present)
|
||||
- entityManager.tick();
|
||||
- // check if our entities are loaded
|
||||
- return entityManager.areEntitiesLoaded(pair);
|
||||
- };
|
||||
-
|
||||
- // now we wait until the entities are loaded,
|
||||
- // the converting from NBT to entity object is done on the main Thread which is why we wait
|
||||
- while (!supplier.getAsBoolean()) {
|
||||
- if (mailbox.size() != 0) {
|
||||
- mailbox.run();
|
||||
- } else {
|
||||
- Thread.yield();
|
||||
- LockSupport.parkNanos("waiting for entity loading", 100000L);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
return getCraftWorld().getHandle().getChunkEntities(this.x, this.z); // Paper - optimise this
|
||||
}
|
||||
|
@ -20,4 +20,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ if (objectset == null || objectset.isEmpty()) { // Paper
|
||||
this.playersPerChunk.remove(i);
|
||||
this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
||||
this.playerTicketManager.update(i, Integer.MAX_VALUE, false);
|
||||
//this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 28 Aug 2020 12:33:47 -0700
|
||||
Subject: [PATCH] Don't lookup fluid state when raytracing
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sun, 27 Sep 2020 16:25:24 +0200
|
||||
Subject: [PATCH] Don't mark dirty in invalid locations (SPIGOT-6086)
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
}
|
||||
|
||||
public void blockChanged(BlockPos pos) {
|
||||
+ if (!pos.isInsideBuildHeightAndWorldBoundsHorizontal(levelHeightAccessor)) return; // Paper - SPIGOT-6086 for all invalid locations; avoid acquiring locks
|
||||
LevelChunk chunk = this.getTickingChunk();
|
||||
|
||||
if (chunk != null) {
|
@ -31,8 +31,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
public void onTickingStart(Entity entity) {
|
||||
+ if (entity instanceof net.minecraft.world.entity.Marker) return; // Paper - Don't tick markers
|
||||
ServerLevel.this.entityTickList.add(entity);
|
||||
ServerLevel.this.entityManager.addNavigatorsIfPathingToRegion(entity); // Paper - optimise notify
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||
|
@ -41,9 +41,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
public static void onEntityPreAdd(final ServerLevel level, final Entity entity) {
|
||||
-
|
||||
+ // Paper start - duplicate uuid resolving
|
||||
+ if (net.minecraft.server.level.ChunkMap.checkDupeUUID(level, entity)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (net.minecraft.world.level.Level.DEBUG_ENTITIES && ((Entity) entity).level.paperConfig().entities.spawning.duplicateUuid.mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.NOTHING) {
|
||||
+ if (((Entity) entity).addedToWorldStack != null) {
|
||||
+ ((Entity) entity).addedToWorldStack.printStackTrace();
|
||||
+ }
|
||||
+ net.minecraft.server.level.ServerLevel.getAddToWorldStackTrace((Entity) entity).printStackTrace();
|
||||
+ }
|
||||
+ // Paper end - duplicate uuid resolving
|
||||
}
|
||||
|
||||
public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) {
|
||||
@ -60,7 +68,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}));
|
||||
// CraftBukkit end
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
});
|
||||
throw new UnsupportedOperationException(); // Paper - rewrite chunk system
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
@ -107,32 +115,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+ // Paper end
|
||||
public CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> prepareTickingChunk(ChunkHolder holder) {
|
||||
ChunkPos chunkcoordintpair = holder.getPos();
|
||||
CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(chunkcoordintpair, 1, (i) -> {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
|
||||
private boolean addEntityUuid(T entity) {
|
||||
if (!this.knownUuids.add(entity.getUUID())) {
|
||||
+ // Paper start
|
||||
+ T conflict = this.visibleEntityStorage.getEntity(entity.getUUID());
|
||||
+ if (conflict != null && ((Entity) conflict).isRemoved()) {
|
||||
+ stopTracking(conflict); // remove the existing entity
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity);
|
||||
+ // Paper start
|
||||
+ if (net.minecraft.world.level.Level.DEBUG_ENTITIES && ((Entity) entity).level.paperConfig().entities.spawning.duplicateUuid.mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.NOTHING) {
|
||||
+ if (((Entity) entity).addedToWorldStack != null) {
|
||||
+ ((Entity) entity).addedToWorldStack.printStackTrace();
|
||||
+ }
|
||||
+ net.minecraft.server.level.ServerLevel.getAddToWorldStackTrace((Entity) entity).printStackTrace();
|
||||
+ }
|
||||
+ // Paper end
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
throw new UnsupportedOperationException(); // Paper - rewrite chunk system
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+ public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
|
||||
+ // Paper end
|
||||
if (this.position.x != x || this.position.y != y || this.position.z != z) {
|
||||
this.position = new Vec3(x, y, z);
|
||||
int i = Mth.floor(x);
|
||||
// Paper start - rewrite chunk system
|
||||
if (this.updatingSectionStatus) {
|
||||
LOGGER.error("Refusing to update position for entity " + this + " to position " + new Vec3(x, y, z) + " since it is processing a section status update", new Throwable());
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
this.levelCallback.onMove();
|
||||
}
|
||||
|
@ -557,8 +557,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, worldHeight, villagerActivationRange );
|
||||
+ // Paper end
|
||||
|
||||
world.getEntities().get(maxBB, ActivationRange::activateEntity);
|
||||
}
|
||||
// Paper start
|
||||
java.util.List<Entity> entities = world.getEntities((Entity)null, maxBB, null);
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
* @param entity
|
||||
* @return
|
||||
@ -621,8 +621,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
{
|
||||
- return true;
|
||||
+ return 20; // Paper
|
||||
}
|
||||
- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() )
|
||||
+ }
|
||||
+ // Paper start
|
||||
+ if (entity instanceof Bee) {
|
||||
+ Bee bee = (Bee)entity;
|
||||
@ -650,7 +649,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return config.villagersWorkImmunityFor;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() )
|
||||
+ if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() )
|
||||
{
|
||||
- return true;
|
||||
@ -678,11 +678,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // Paper start
|
||||
+ if (entity instanceof Mob && ((Mob) entity).targetSelector.hasTasks() ) {
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
+ if (entity instanceof Pillager) {
|
||||
+ Pillager pillager = (Pillager) entity;
|
||||
+ // TODO:?
|
||||
}
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
// SPIGOT-6644: Otherwise the target refresh tick will be missed
|
||||
|
@ -38,21 +38,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
@@ -0,0 +0,0 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
||||
|
||||
} else {
|
||||
ListTag listTag = new ListTag();
|
||||
+ final java.util.Map<net.minecraft.world.entity.EntityType<?>, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper
|
||||
dataList.getEntities().forEach((entity) -> {
|
||||
+ // Paper start
|
||||
+ final EntityType<?> entityType = entity.getType();
|
||||
+ final int saveLimit = this.level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
||||
+ if (saveLimit > -1) {
|
||||
+ if (savedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) {
|
||||
+ return;
|
||||
+ }
|
||||
+ savedEntityCounts.merge(entityType, 1, Integer::sum);
|
||||
return null;
|
||||
}
|
||||
ListTag listTag = new ListTag();
|
||||
+ final java.util.Map<net.minecraft.world.entity.EntityType<?>, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper
|
||||
entities.forEach((entity) -> { // diff here: use entities parameter
|
||||
+ // Paper start
|
||||
+ final EntityType<?> entityType = entity.getType();
|
||||
+ final int saveLimit = level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
||||
+ if (saveLimit > -1) {
|
||||
+ if (savedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
if (entity.save(compoundTag)) {
|
||||
listTag.add(compoundTag);
|
||||
+ savedEntityCounts.merge(entityType, 1, Integer::sum);
|
||||
+ }
|
||||
+ // Paper end
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
if (entity.save(compoundTag)) {
|
||||
listTag.add(compoundTag);
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 04:20:44 -0700
|
||||
Subject: [PATCH] Execute chunk tasks mid-tick
|
||||
|
||||
@ -119,7 +119,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
LevelChunk chunk1 = iterator1.next();
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
|
||||
if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) {
|
||||
if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - the chunk is known ticking
|
||||
this.level.tickChunk(chunk1, k);
|
||||
+ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper
|
||||
}
|
||||
|
@ -64,9 +64,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
private float averageSentPackets;
|
||||
private int tickCount;
|
||||
private boolean handlingFault;
|
||||
}
|
||||
}
|
||||
// Paper end - add pending task queue
|
||||
+ // Paper start - NetworkClient implementation
|
||||
+ public int protocolVersion;
|
||||
+ public java.net.InetSocketAddress virtualHost;
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 13 Jul 2020 06:22:54 -0700
|
||||
Subject: [PATCH] Fix AdvancementDataPlayer leak due from quitting early in
|
||||
login
|
||||
|
@ -1,73 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 18 Apr 2020 04:36:11 -0400
|
||||
Subject: [PATCH] Fix Chunk Post Processing deadlock risk
|
||||
|
||||
See: https://gist.github.com/aikar/dd22bbd2a3d78a2fd3d92e95e9f28dc6
|
||||
|
||||
as part of post processing a chunk, we can call ChunkConverter.
|
||||
|
||||
ChunkConverter then kicks off major physics updates, and when blocks
|
||||
that have connections across chunk boundaries occur, a recursive risk
|
||||
can occur where A updates a block that triggers a physics request.
|
||||
|
||||
That physics request may trigger a chunk request, that then enqueues
|
||||
a task into the Mailbox ChunkTaskQueueSorter.
|
||||
|
||||
If anything requests that same chunk that is in the middle of conversion,
|
||||
it's mailbox queue is going to be held up, so the subsequent chunk request
|
||||
will be unable to proceed.
|
||||
|
||||
We delay post processing of Chunk.A() 1 "pass" by re stuffing it back into
|
||||
the executor so that the mailbox ChunkQueue is now considered empty.
|
||||
|
||||
This successfully fixed a reoccurring and highly reproducible crash
|
||||
for heightmaps.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
};
|
||||
// CraftBukkit end
|
||||
|
||||
+ final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper
|
||||
// Paper start - distance maps
|
||||
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
});
|
||||
CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> completablefuture1 = completablefuture.thenApplyAsync((either) -> {
|
||||
return either.mapLeft((list) -> {
|
||||
- return (LevelChunk) list.get(list.size() / 2);
|
||||
- });
|
||||
- }, (runnable) -> {
|
||||
- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable));
|
||||
- }).thenApplyAsync((either) -> {
|
||||
- return either.ifLeft((chunk) -> {
|
||||
+ // Paper start - revert 1.18.2 diff
|
||||
+ final LevelChunk chunk = (LevelChunk) list.get(list.size() / 2);
|
||||
chunk.postProcessGeneration();
|
||||
this.level.startTickingChunk(chunk);
|
||||
+ return chunk;
|
||||
});
|
||||
- }, this.mainThreadExecutor);
|
||||
+ }, (runnable) -> {
|
||||
+ this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, () -> ChunkMap.this.chunkLoadConversionCallbackExecutor.execute(runnable))); // Paper - delay running Chunk post processing until outside of the sorter to prevent a deadlock scenario when post processing causes another chunk request.
|
||||
+ }); // Paper end - revert 1.18.2 diff
|
||||
|
||||
completablefuture1.thenAcceptAsync((either) -> {
|
||||
either.ifLeft((chunk) -> {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
return super.pollTask() || execChunkTask; // Paper
|
||||
}
|
||||
} finally {
|
||||
+ chunkMap.chunkLoadConversionCallbackExecutor.run(); // Paper - Add chunk load conversion callback executor to prevent deadlock due to recursion in the chunk task queue sorter
|
||||
chunkMap.callbackExecutor.run();
|
||||
}
|
||||
// CraftBukkit end
|
@ -1,43 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 13 May 2019 21:10:59 -0700
|
||||
Subject: [PATCH] Fix CraftServer#isPrimaryThread and MinecraftServer
|
||||
isMainThread
|
||||
|
||||
md_5 changed it so he could shut down the server asynchronously
|
||||
from watchdog, although we have patches that prevent that type
|
||||
of behavior for this exact reason.
|
||||
|
||||
md_5 also placed code in PlayerConnectionUtils that would have
|
||||
solved https://bugs.mojang.com/browse/MC-142590, making the change
|
||||
to MinecraftServer#isMainThread irrelevant.
|
||||
By reverting his change to MinecraftServer#isMainThread packet
|
||||
handling that should have been handled synchronously will be handled
|
||||
synchronously when the server gets shut down.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
@Override
|
||||
public boolean isSameThread() {
|
||||
- return super.isSameThread() || this.isStopped(); // CraftBukkit - MC-142590
|
||||
+ return super.isSameThread() /*|| this.isStopped()*/; // CraftBukkit - MC-142590 // Paper - causes issues elsewhere
|
||||
}
|
||||
|
||||
public boolean isDebugging() {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public boolean isPrimaryThread() {
|
||||
- return Thread.currentThread().equals(console.serverThread) || this.console.hasStopped() || !org.spigotmc.AsyncCatcher.enabled; // All bets are off if we have shut down (e.g. due to watchdog)
|
||||
+ return Thread.currentThread().equals(console.serverThread); // Paper - Fix issues with detecting main thread properly
|
||||
}
|
||||
|
||||
// Paper start
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 11 Jul 2020 05:09:28 -0700
|
||||
Subject: [PATCH] Fix GameProfileCache concurrency
|
||||
|
||||
|
@ -1,186 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 7 May 2020 19:17:36 -0400
|
||||
Subject: [PATCH] Fix Light Command
|
||||
|
||||
This lets you run /paper fixlight <chunkRadius> (max 5) to automatically
|
||||
fix all light data in the chunks.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -0,0 +0,0 @@ package io.papermc.paper.command;
|
||||
|
||||
import io.papermc.paper.command.subcommands.ChunkDebugCommand;
|
||||
import io.papermc.paper.command.subcommands.EntityCommand;
|
||||
+import io.papermc.paper.command.subcommands.FixLightCommand;
|
||||
import io.papermc.paper.command.subcommands.HeapDumpCommand;
|
||||
import io.papermc.paper.command.subcommands.ReloadCommand;
|
||||
import io.papermc.paper.command.subcommands.VersionCommand;
|
||||
@@ -0,0 +0,0 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("reload"), new ReloadCommand());
|
||||
commands.put(Set.of("version"), new VersionCommand());
|
||||
commands.put(Set.of("debug", "chunkinfo"), new ChunkDebugCommand());
|
||||
+ commands.put(Set.of("fixlight"), new FixLightCommand());
|
||||
|
||||
return commands.entrySet().stream()
|
||||
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
||||
diff --git a/src/main/java/io/papermc/paper/command/subcommands/FixLightCommand.java b/src/main/java/io/papermc/paper/command/subcommands/FixLightCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/subcommands/FixLightCommand.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.command.subcommands;
|
||||
+
|
||||
+import io.papermc.paper.command.PaperSubcommand;
|
||||
+import java.util.ArrayDeque;
|
||||
+import java.util.Deque;
|
||||
+import net.minecraft.server.MCUtil;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ChunkHolder;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.server.level.ThreadedLevelLightEngine;
|
||||
+import net.minecraft.world.level.ChunkPos;
|
||||
+import net.minecraft.world.level.chunk.LevelChunk;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class FixLightCommand implements PaperSubcommand {
|
||||
+ @Override
|
||||
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ this.doFixLight(sender, args);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private void doFixLight(final CommandSender sender, final String[] args) {
|
||||
+ if (!(sender instanceof Player)) {
|
||||
+ sender.sendMessage(text("Only players can use this command", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+ @Nullable Runnable post = null;
|
||||
+ int radius = 2;
|
||||
+ if (args.length > 0) {
|
||||
+ try {
|
||||
+ final int parsed = Integer.parseInt(args[0]);
|
||||
+ if (parsed < 0) {
|
||||
+ sender.sendMessage(text("Radius cannot be negative!", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+ final int maxRadius = 5;
|
||||
+ radius = Math.min(maxRadius, parsed);
|
||||
+ if (radius != parsed) {
|
||||
+ post = () -> sender.sendMessage(text("Radius '" + parsed + "' was not in the required range [0, " + maxRadius + "], it was lowered to the maximum (" + maxRadius + " chunks).", RED));
|
||||
+ }
|
||||
+ } catch (final Exception e) {
|
||||
+ sender.sendMessage(text("'" + args[0] + "' is not a valid number.", RED));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ CraftPlayer player = (CraftPlayer) sender;
|
||||
+ ServerPlayer handle = player.getHandle();
|
||||
+ ServerLevel world = (ServerLevel) handle.level;
|
||||
+ ThreadedLevelLightEngine lightengine = world.getChunkSource().getLightEngine();
|
||||
+
|
||||
+ net.minecraft.core.BlockPos center = MCUtil.toBlockPosition(player.getLocation());
|
||||
+ Deque<ChunkPos> queue = new ArrayDeque<>(MCUtil.getSpiralOutChunks(center, radius));
|
||||
+ updateLight(sender, world, lightengine, queue, post);
|
||||
+ }
|
||||
+
|
||||
+ private void updateLight(
|
||||
+ final CommandSender sender,
|
||||
+ final ServerLevel world,
|
||||
+ final ThreadedLevelLightEngine lightengine,
|
||||
+ final Deque<ChunkPos> queue,
|
||||
+ final @Nullable Runnable done
|
||||
+ ) {
|
||||
+ @Nullable ChunkPos coord = queue.poll();
|
||||
+ if (coord == null) {
|
||||
+ sender.sendMessage(text("All Chunks Light updated", GREEN));
|
||||
+ if (done != null) {
|
||||
+ done.run();
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ world.getChunkSource().getChunkAtAsynchronously(coord.x, coord.z, false, false).whenCompleteAsync((either, ex) -> {
|
||||
+ if (ex != null) {
|
||||
+ sender.sendMessage(text("Error loading chunk " + coord, RED));
|
||||
+ updateLight(sender, world, lightengine, queue, done);
|
||||
+ return;
|
||||
+ }
|
||||
+ @Nullable LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null);
|
||||
+ if (chunk == null) {
|
||||
+ updateLight(sender, world, lightengine, queue, done);
|
||||
+ return;
|
||||
+ }
|
||||
+ lightengine.setTaskPerBatch(world.paperConfig().misc.lightQueueSize + 16 * 256); // ensure full chunk can fit into queue
|
||||
+ sender.sendMessage(text("Updating Light " + coord));
|
||||
+ int cx = chunk.getPos().x << 4;
|
||||
+ int cz = chunk.getPos().z << 4;
|
||||
+ for (int y = 0; y < world.getHeight(); y++) {
|
||||
+ for (int x = 0; x < 16; x++) {
|
||||
+ for (int z = 0; z < 16; z++) {
|
||||
+ net.minecraft.core.BlockPos pos = new net.minecraft.core.BlockPos(cx + x, y, cz + z);
|
||||
+ lightengine.checkBlock(pos);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ lightengine.tryScheduleUpdate();
|
||||
+ @Nullable ChunkHolder visibleChunk = world.getChunkSource().chunkMap.getVisibleChunkIfPresent(chunk.coordinateKey);
|
||||
+ if (visibleChunk != null) {
|
||||
+ world.getChunkSource().chunkMap.addLightTask(visibleChunk, () -> {
|
||||
+ MinecraftServer.getServer().processQueue.add(() -> {
|
||||
+ visibleChunk.broadcast(new net.minecraft.network.protocol.game.ClientboundLightUpdatePacket(chunk.getPos(), lightengine, null, null, true), false);
|
||||
+ updateLight(sender, world, lightengine, queue, done);
|
||||
+ });
|
||||
+ });
|
||||
+ } else {
|
||||
+ updateLight(sender, world, lightengine, queue, done);
|
||||
+ }
|
||||
+ lightengine.setTaskPerBatch(world.paperConfig().misc.lightQueueSize);
|
||||
+ }, MinecraftServer.getServer());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
private final ChunkTaskPriorityQueueSorter queueSorter;
|
||||
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
|
||||
public final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
|
||||
+ // Paper start
|
||||
+ final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mailboxLight;
|
||||
+ public void addLightTask(ChunkHolder playerchunk, Runnable run) {
|
||||
+ this.mailboxLight.tell(ChunkTaskPriorityQueueSorter.message(playerchunk, run));
|
||||
+ }
|
||||
+ // Paper end
|
||||
public final ChunkProgressListener progressListener;
|
||||
private final ChunkStatusUpdateListener chunkStatusListener;
|
||||
public final ChunkMap.ChunkDistanceManager distanceManager;
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
this.progressListener = worldGenerationProgressListener;
|
||||
this.chunkStatusListener = chunkStatusChangeListener;
|
||||
- ProcessorMailbox<Runnable> threadedmailbox1 = ProcessorMailbox.create(executor, "light");
|
||||
+ ProcessorMailbox<Runnable> lightthreaded; ProcessorMailbox<Runnable> threadedmailbox1 = lightthreaded = ProcessorMailbox.create(executor, "light"); // Paper
|
||||
|
||||
this.queueSorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(threadedmailbox, mailbox, threadedmailbox1), executor, Integer.MAX_VALUE);
|
||||
this.worldgenMailbox = this.queueSorter.getProcessor(threadedmailbox, false);
|
||||
this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false);
|
||||
+ this.mailboxLight = this.queueSorter.getProcessor(lightthreaded, false);// Paper
|
||||
this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false));
|
||||
this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
|
||||
this.overworldDataStorage = persistentStateManagerFactory;
|
@ -84,7 +84,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+
|
||||
+ public ChunkAccess getUnloadingChunk(int chunkX, int chunkZ) {
|
||||
+ ChunkHolder chunkHolder = this.pendingUnloads.get(ChunkPos.asLong(chunkX, chunkZ));
|
||||
+ ChunkHolder chunkHolder = net.minecraft.server.ChunkSystem.getUnloadingChunkHolder(this.level, chunkX, chunkZ);
|
||||
+ return chunkHolder == null ? null : chunkHolder.getAvailableChunkNow();
|
||||
+ }
|
||||
+ // Paper end
|
||||
@ -92,50 +92,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) {
|
||||
// Spigot start
|
||||
return this.anyPlayerCloseEnoughForSpawning(pos, false);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkStatus {
|
||||
return this.chunkType;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static ChunkStatus getStatus(String name) {
|
||||
+ try {
|
||||
+ // We need this otherwise we return EMPTY for invalid names
|
||||
+ ResourceLocation key = new ResourceLocation(name);
|
||||
+ return Registry.CHUNK_STATUS.getOptional(key).orElse(null);
|
||||
+ } catch (Exception ex) {
|
||||
+ return null; // invalid name
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
public static ChunkStatus byName(String id) {
|
||||
return (ChunkStatus) Registry.CHUNK_STATUS.get(ResourceLocation.tryParse(id));
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkSerializer {
|
||||
}));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static @Nullable ChunkStatus getStatus(@Nullable CompoundTag compound) {
|
||||
+ if (compound == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ // Note: Copied from below
|
||||
+ return ChunkStatus.getStatus(compound.getString("Status"));
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static ChunkStatus.ChunkType getChunkTypeFromTag(@Nullable CompoundTag nbt) {
|
||||
return nbt != null ? ChunkStatus.byName(nbt.getString("Status")).getChunkType() : ChunkStatus.ChunkType.PROTOCHUNK;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
|
@ -1,26 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 1 Feb 2021 15:35:14 -0800
|
||||
Subject: [PATCH] Fix chunks refusing to unload at low TPS
|
||||
|
||||
The full chunk future is appended to the chunk save future, but
|
||||
when moving to unloaded ticket level it is not being completed with
|
||||
the empty chunk access, so the chunk save must wait for the full
|
||||
chunk future to complete. We can simply schedule to the immediate
|
||||
executor to get this effect, rather than the main mailbox.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
return chunk;
|
||||
});
|
||||
- }, (runnable) -> {
|
||||
- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable));
|
||||
- });
|
||||
+ }, this.mainThreadExecutor); // Paper - queue to execute immediately so this doesn't delay chunk unloading
|
||||
}
|
||||
|
||||
public int getTickingGenerated() {
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 17 May 2020 23:47:33 -0700
|
||||
Subject: [PATCH] Fix for large move vectors crashing server
|
||||
|
||||
|
@ -1,74 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 5 Mar 2022 17:12:52 -0800
|
||||
Subject: [PATCH] Fix save problems on shutdown
|
||||
|
||||
- Save level.dat first, in case the shutdown is killed later
|
||||
- Force run minecraftserver tasks and the chunk source tasks
|
||||
while waiting for the chunk system to empty, as there's simply
|
||||
too much trash that could prevent them from executing during
|
||||
the chunk source tick (i.e "time left in tick" logic).
|
||||
- Set forceTicks to true, so that player packets are always
|
||||
processed so that the main process queue can be drained
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - let's be a little more intelligent around crashes
|
||||
+ // make sure level.dat saves
|
||||
+ for (ServerLevel level : this.getAllLevels()) {
|
||||
+ level.saveLevelDat();
|
||||
+ }
|
||||
+ // Paper end - let's be a little more intelligent around crashes
|
||||
+
|
||||
while (this.levels.values().stream().anyMatch((worldserver1) -> {
|
||||
return worldserver1.getChunkSource().chunkMap.hasWork();
|
||||
})) {
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
worldserver.getChunkSource().tick(() -> {
|
||||
return true;
|
||||
}, false);
|
||||
+ while (worldserver.getChunkSource().pollTask()); // Paper - drain tasks
|
||||
}
|
||||
|
||||
- this.waitUntilNextTick();
|
||||
+ this.forceTicks = true; // Paper
|
||||
+ while (this.pollTask()); // Paper - drain tasks
|
||||
}
|
||||
|
||||
this.saveAllChunks(false, true, false);
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
private boolean haveTime() {
|
||||
+ // Paper start
|
||||
+ if (this.forceTicks) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
// CraftBukkit start
|
||||
if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken
|
||||
return this.forceTicks || this.runningTask() || Util.getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
|
||||
}
|
||||
+ // Paper start
|
||||
+ this.saveLevelDat();
|
||||
+ }
|
||||
|
||||
+ public void saveLevelDat() {
|
||||
+ this.saveLevelData();
|
||||
+ // Paper end
|
||||
// CraftBukkit start - moved from MinecraftServer.saveChunks
|
||||
ServerLevel worldserver1 = this;
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 24 Jul 2020 15:56:05 -0700
|
||||
Subject: [PATCH] Fix some rails connecting improperly
|
||||
|
||||
|
@ -90,7 +90,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // Paper End
|
||||
// Spigot End
|
||||
|
||||
protected void runServer() {
|
||||
public static volatile RuntimeException chunkSystemCrash; // Paper - rewrite chunk system
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// Spigot start
|
||||
@ -99,17 +99,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
|
||||
+ lastTick = start - TICK_TIME; // Paper
|
||||
while (this.running) {
|
||||
// Paper start - rewrite chunk system
|
||||
// guarantee that nothing can stop the server from halting if it can at least still tick
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
throw this.chunkSystemCrash;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
- long i = (curTime = Util.getMillis()) - this.nextTickTime;
|
||||
+ long i = ((curTime = System.nanoTime()) / (1000L * 1000L)) - this.nextTickTime; // Paper
|
||||
|
||||
if (i > 5000L && this.nextTickTime - this.lastOverloadWarning >= 30000L) { // CraftBukkit
|
||||
long j = i / 50L;
|
||||
|
||||
if (this.server.getWarnOnOverload()) // CraftBukkit
|
||||
- MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
|
||||
+ MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
|
||||
this.nextTickTime += j * 50L;
|
||||
this.lastOverloadWarning = this.nextTickTime;
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
++MinecraftServer.currentTickLong; // Paper
|
||||
|
@ -41,5 +41,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+ // Paper end - block invalid positions
|
||||
// Paper end
|
||||
// Paper start - fix MC-4
|
||||
if (this instanceof ItemEntity) {
|
||||
// Paper start - rewrite chunk system
|
||||
if (this.updatingSectionStatus) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 4 May 2020 10:06:24 -0700
|
||||
Subject: [PATCH] Highly optimise single and multi-AABB VoxelShapes and
|
||||
collisions
|
||||
@ -1497,8 +1497,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -0,0 +0,0 @@ public abstract class BlockBehaviour {
|
||||
return this.conditionallyFullOpaque;
|
||||
}
|
||||
protected boolean isTicking;
|
||||
protected FluidState fluid;
|
||||
// Paper end
|
||||
+ // Paper start
|
||||
+ private long blockCollisionBehavior = io.papermc.paper.util.CollisionUtil.KNOWN_SPECIAL_BLOCK;
|
||||
@ -1511,10 +1511,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
public void initCache() {
|
||||
this.fluid = this.getBlock().getFluidState(this.asState()); // Paper - moved from getFluid()
|
||||
@@ -0,0 +0,0 @@ public abstract class BlockBehaviour {
|
||||
}
|
||||
this.shapeExceedsCube = this.cache == null || this.cache.largeCollisionShape; // Paper - moved from actual method to here
|
||||
this.opacityIfCached = this.cache == null || this.isConditionallyFullOpaque() ? -1 : this.cache.lightBlock; // Paper - cache opacity for light
|
||||
-
|
||||
this.opacityIfCached = this.cache == null || this.isConditionallyFullOpaque() ? -1 : this.cache.lightBlock; // Paper - starlight - cache opacity for light
|
||||
|
||||
+ // Paper start
|
||||
+ if (io.papermc.paper.util.CollisionUtil.isSpecialCollidingBlock(this)) {
|
||||
+ this.blockCollisionBehavior = io.papermc.paper.util.CollisionUtil.KNOWN_SPECIAL_BLOCK;
|
||||
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -101,8 +101,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
public void setSendViewDistance(int viewDistance) {
|
||||
throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
|
@ -1,81 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 29 May 2020 23:32:14 -0400
|
||||
Subject: [PATCH] Improve Chunk Status Transition Speed
|
||||
|
||||
When a chunk is loaded from disk that has already been generated,
|
||||
the server has to promote the chunk through the system to reach
|
||||
it's current desired status level.
|
||||
|
||||
This results in every single status transition going from the main thread
|
||||
to the world gen threads, only to discover it has no work it actually
|
||||
needs to do.... and then it returns back to main.
|
||||
|
||||
This back and forth costs a lot of time and can really delay chunk loads
|
||||
when the server is under high TPS due to their being a lot of time in
|
||||
between chunk load times, as well as hogs up the chunk threads from doing
|
||||
actual generation and light work.
|
||||
|
||||
Additionally, the whole task system uses a lot of CPU on the server threads anyways.
|
||||
|
||||
So by optimizing status transitions for status's that are already complete,
|
||||
we can run them to the desired level while on main thread (where it has
|
||||
to happen anyways) instead of ever jumping to world gen thread.
|
||||
|
||||
This will improve chunk loading effeciency to be reduced down to the following
|
||||
scenario / path:
|
||||
|
||||
1) MAIN: Chunk Requested, Load Request sent to ChunkTaskManager / IO Queue
|
||||
2) IO: Once position in queue comes, submit read IO data and schedule to chunk task thread
|
||||
3) CHUNK: Once IO is loaded and position in queue comes, deserialize the chunk data, process conversions, submit to main queue
|
||||
4) MAIN: next Chunk Task process (Mid Tick or End Of Tick), load chunk data into world (POI, main thread tasks)
|
||||
5) MAIN: process status transitions all the way to LIGHT, light schedules Threaded task
|
||||
6) SERVER: Light tasks register light enablement for chunk and any lighting needing to be done
|
||||
7) MAIN: Task returns to main, finish processing to FULL/TICKING status
|
||||
|
||||
Previously would have hopped to SERVER around 12+ times there extra.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
// Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
long lastAutoSaveTime; // Paper - incremental autosave
|
||||
long inactiveTimeStart; // Paper - incremental autosave
|
||||
+ // Paper start - optimize chunk status progression without jumping through thread pool
|
||||
+ public boolean canAdvanceStatus() {
|
||||
+ ChunkStatus status = getChunkHolderStatus();
|
||||
+ ChunkAccess chunk = getAvailableChunkNow();
|
||||
+ return chunk != null && (status == null || chunk.getStatus().isOrAfter(getNextStatus(status)));
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
|
||||
this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return either.mapLeft((list) -> {
|
||||
return (LevelChunk) list.get(list.size() / 2);
|
||||
});
|
||||
- }, this.mainThreadExecutor);
|
||||
+ }, this.mainInvokingExecutor); // Paper
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return "chunkGenerate " + requiredStatus.getName();
|
||||
});
|
||||
Executor executor = (runnable) -> {
|
||||
+ // Paper start - optimize chunk status progression without jumping through thread pool
|
||||
+ if (holder.canAdvanceStatus()) {
|
||||
+ this.mainInvokingExecutor.execute(runnable);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.worldgenMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable));
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 2 Aug 2021 10:10:40 +0200
|
||||
Subject: [PATCH] Improve boat collision performance
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Jul 2020 20:46:50 -0700
|
||||
Subject: [PATCH] Improve inlinig for some hot IBlockData methods
|
||||
|
||||
@ -9,9 +9,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -0,0 +0,0 @@ public abstract class BlockBehaviour {
|
||||
return this.shapeExceedsCube;
|
||||
return this.conditionallyFullOpaque;
|
||||
}
|
||||
// Paper end
|
||||
// Paper end - starlight
|
||||
+ // Paper start
|
||||
+ protected boolean isTicking;
|
||||
+ protected FluidState fluid;
|
||||
|
@ -92,7 +92,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
||||
AtomicReference<S> atomicreference = new AtomicReference();
|
||||
Thread thread = new Thread(() -> {
|
||||
Thread thread = new io.papermc.paper.util.TickThread(() -> { // Paper - rewrite chunk system
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// CraftBukkit start
|
||||
@ -127,7 +127,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
// Spigot end
|
||||
+ // Paper start - move final shutdown items here
|
||||
+ LOGGER.info("Flushing Chunk IO");
|
||||
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper
|
||||
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
|
||||
+ LOGGER.info("Closing Thread Pool");
|
||||
+ Util.shutdownExecutors(); // Paper
|
||||
+ LOGGER.info("Closing Server");
|
||||
@ -268,18 +268,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
SkullBlockEntity.clear();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
MutableBoolean mutableboolean = new MutableBoolean();
|
||||
|
||||
do {
|
||||
+ boolean isShuttingDown = level.getServer().hasStopped(); // Paper
|
||||
mutableboolean.setFalse();
|
||||
list.stream().map((playerchunk) -> {
|
||||
CompletableFuture completablefuture;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@ -329,19 +317,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
// Paper start - Prevent tile entity and entity crashes
|
||||
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
||||
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public boolean isPrimaryThread() {
|
||||
- return Thread.currentThread().equals(console.serverThread); // Paper - Fix issues with detecting main thread properly
|
||||
+ return Thread.currentThread().equals(console.serverThread) || Thread.currentThread().equals(net.minecraft.server.MinecraftServer.getServer().shutdownThread); // Paper - Fix issues with detecting main thread properly, the only time Watchdog will be used is during a crash shutdown which is a "try our best" scenario
|
||||
}
|
||||
|
||||
// Paper start
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@ -509,14 +484,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.Bukkit;
|
||||
public class WatchdogThread extends Thread
|
||||
public final class WatchdogThread extends io.papermc.paper.util.TickThread // Paper - rewrite chunk system
|
||||
{
|
||||
|
||||
+ public static final boolean DISABLE_WATCHDOG = Boolean.getBoolean("disable.watchdog"); // Paper
|
||||
private static WatchdogThread instance;
|
||||
private long timeoutTime;
|
||||
private boolean restart;
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
{
|
||||
if ( WatchdogThread.instance == null )
|
||||
{
|
||||
@ -524,7 +499,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
|
||||
WatchdogThread.instance.start();
|
||||
} else
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
// Paper start
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
long currentTime = WatchdogThread.monotonicMillis();
|
||||
@ -541,16 +516,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
lastEarlyWarning = currentTime;
|
||||
if (isLongTimeout) {
|
||||
// Paper end
|
||||
@@ -0,0 +0,0 @@ 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
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.dumpAllChunkLoadInfo(); // Paper
|
||||
- WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
+ WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( server.serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
||||
// Paper start - Only print full dump on long timeouts
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
|
||||
if ( isLongTimeout )
|
||||
{
|
||||
|
@ -116,7 +116,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
// private final Map<UUID, AdvancementDataPlayer> advancements;
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
public void placeNewPlayer(Connection connection, ServerPlayer player) {
|
||||
player.isRealPlayer = true; // Paper - Chunk priority
|
||||
player.isRealPlayer = true; // Paper
|
||||
player.loginTime = System.currentTimeMillis(); // Paper
|
||||
+ // Paper start
|
||||
+ ServerPlayer prev = pendingPlayers.put(player.getUUID(), player);
|
||||
|
@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
|
||||
@@ -0,0 +0,0 @@ public class AsyncCatcher
|
||||
{
|
||||
if ( (AsyncCatcher.enabled || io.papermc.paper.util.TickThread.STRICT_THREAD_CHECKS) && Thread.currentThread() != MinecraftServer.getServer().serverThread ) // Paper
|
||||
if ( !io.papermc.paper.util.TickThread.isTickThread() ) // Paper // Paper - rewrite chunk system
|
||||
{
|
||||
+ MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper
|
||||
throw new IllegalStateException( "Asynchronous " + reason + "!" );
|
||||
|
@ -31,9 +31,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
|
||||
// Paper end
|
||||
return;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ // Paper start - fix MC-4
|
||||
+ if (this instanceof ItemEntity) {
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixEntityPositionDesync) {
|
||||
|
@ -856,6 +856,137 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return this.map.values().iterator();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/util/maplist/ReferenceList.java b/src/main/java/com/destroystokyo/paper/util/maplist/ReferenceList.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/util/maplist/ReferenceList.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package com.destroystokyo.paper.util.maplist;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
||||
+import java.util.Arrays;
|
||||
+import java.util.Iterator;
|
||||
+import java.util.NoSuchElementException;
|
||||
+
|
||||
+/**
|
||||
+ * @author Spottedleaf
|
||||
+ */
|
||||
+public final class ReferenceList<E> implements Iterable<E> {
|
||||
+
|
||||
+ protected final Reference2IntOpenHashMap<E> referenceToIndex = new Reference2IntOpenHashMap<>(2, 0.8f);
|
||||
+ {
|
||||
+ this.referenceToIndex.defaultReturnValue(Integer.MIN_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ protected static final Object[] EMPTY_LIST = new Object[0];
|
||||
+
|
||||
+ protected Object[] references = EMPTY_LIST;
|
||||
+ protected int count;
|
||||
+
|
||||
+ public int size() {
|
||||
+ return this.count;
|
||||
+ }
|
||||
+
|
||||
+ public boolean contains(final E obj) {
|
||||
+ return this.referenceToIndex.containsKey(obj);
|
||||
+ }
|
||||
+
|
||||
+ public boolean remove(final E obj) {
|
||||
+ final int index = this.referenceToIndex.removeInt(obj);
|
||||
+ if (index == Integer.MIN_VALUE) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ // move the object at the end to this index
|
||||
+ final int endIndex = --this.count;
|
||||
+ final E end = (E)this.references[endIndex];
|
||||
+ if (index != endIndex) {
|
||||
+ // not empty after this call
|
||||
+ this.referenceToIndex.put(end, index); // update index
|
||||
+ }
|
||||
+ this.references[index] = end;
|
||||
+ this.references[endIndex] = null;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public boolean add(final E obj) {
|
||||
+ final int count = this.count;
|
||||
+ final int currIndex = this.referenceToIndex.putIfAbsent(obj, count);
|
||||
+
|
||||
+ if (currIndex != Integer.MIN_VALUE) {
|
||||
+ return false; // already in this list
|
||||
+ }
|
||||
+
|
||||
+ Object[] list = this.references;
|
||||
+
|
||||
+ if (list.length == count) {
|
||||
+ // resize required
|
||||
+ list = this.references = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative
|
||||
+ }
|
||||
+
|
||||
+ list[count] = obj;
|
||||
+ this.count = count + 1;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public E getChecked(final int index) {
|
||||
+ if (index < 0 || index >= this.count) {
|
||||
+ throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count);
|
||||
+ }
|
||||
+ return (E)this.references[index];
|
||||
+ }
|
||||
+
|
||||
+ public E getUnchecked(final int index) {
|
||||
+ return (E)this.references[index];
|
||||
+ }
|
||||
+
|
||||
+ public Object[] getRawData() {
|
||||
+ return this.references;
|
||||
+ }
|
||||
+
|
||||
+ public void clear() {
|
||||
+ this.referenceToIndex.clear();
|
||||
+ Arrays.fill(this.references, 0, this.count, null);
|
||||
+ this.count = 0;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Iterator<E> iterator() {
|
||||
+ return new Iterator<>() {
|
||||
+ private E lastRet;
|
||||
+ private int current;
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNext() {
|
||||
+ return this.current < ReferenceList.this.count;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public E next() {
|
||||
+ if (this.current >= ReferenceList.this.count) {
|
||||
+ throw new NoSuchElementException();
|
||||
+ }
|
||||
+ return this.lastRet = (E)ReferenceList.this.references[this.current++];
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void remove() {
|
||||
+ final E lastRet = this.lastRet;
|
||||
+
|
||||
+ if (lastRet == null) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ this.lastRet = null;
|
||||
+
|
||||
+ ReferenceList.this.remove(lastRet);
|
||||
+ --this.current;
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
@ -4544,6 +4675,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+import net.minecraft.server.level.ChunkHolder;
|
||||
+import net.minecraft.server.level.ChunkMap;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.server.level.TicketType;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.level.ChunkPos;
|
||||
@ -4775,30 +4907,54 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static void onChunkBorder(LevelChunk chunk, ChunkHolder holder) {
|
||||
+ public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+ chunk.playerChunk = holder;
|
||||
+ }
|
||||
+
|
||||
+ public static void onChunkNotBorder(LevelChunk chunk, ChunkHolder holder) {
|
||||
+ public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ public static void onChunkTicking(LevelChunk chunk, ChunkHolder holder) {
|
||||
+ public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+ chunk.level.getChunkSource().tickingChunks.add(chunk);
|
||||
+ }
|
||||
+
|
||||
+ public static void onChunkNotTicking(LevelChunk chunk, ChunkHolder holder) {
|
||||
+ public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+ chunk.level.getChunkSource().tickingChunks.remove(chunk);
|
||||
+ }
|
||||
+
|
||||
+ public static void onChunkEntityTicking(LevelChunk chunk, ChunkHolder holder) {
|
||||
+ public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+ chunk.level.getChunkSource().entityTickingChunks.add(chunk);
|
||||
+ }
|
||||
+
|
||||
+ public static void onChunkNotEntityTicking(LevelChunk chunk, ChunkHolder holder) {
|
||||
+ public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+ chunk.level.getChunkSource().entityTickingChunks.remove(chunk);
|
||||
+ }
|
||||
+
|
||||
+ public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) {
|
||||
+ return level.chunkSource.chunkMap.getUnloadingChunkHolder(chunkX, chunkZ);
|
||||
+ }
|
||||
+
|
||||
+ public static int getSendViewDistance(final ServerPlayer player) {
|
||||
+ return getLoadViewDistance(player);
|
||||
+ }
|
||||
+
|
||||
+ public static int getLoadViewDistance(final ServerPlayer player) {
|
||||
+ final ServerLevel level = player.getLevel();
|
||||
+ if (level == null) {
|
||||
+ return Bukkit.getViewDistance() + 1;
|
||||
+ }
|
||||
+ return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1;
|
||||
+ }
|
||||
+
|
||||
+ public static int getTickViewDistance(final ServerPlayer player) {
|
||||
+ final ServerLevel level = player.getLevel();
|
||||
+ if (level == null) {
|
||||
+ return Bukkit.getSimulationDistance();
|
||||
+ }
|
||||
+ return level.chunkSource.chunkMap.distanceManager.getSimulationDistance();
|
||||
+ }
|
||||
+
|
||||
+ private ChunkSystem() {
|
||||
+ throw new RuntimeException();
|
||||
+ }
|
||||
@ -5904,6 +6060,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
|
||||
protected void purgeStaleTickets() {
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
this.playerTicketManager.updateViewDistance(viewDistance);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public int getSimulationDistance() {
|
||||
+ return this.simulationDistance;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void updateSimulationDistance(int simulationDistance) {
|
||||
if (simulationDistance != this.simulationDistance) {
|
||||
this.simulationDistance = simulationDistance;
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
}
|
||||
|
||||
@ -6339,6 +6508,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
|
||||
// CraftBukkit end
|
||||
|
||||
+ public boolean isRealPlayer; // Paper
|
||||
+ public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||
+
|
||||
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, @Nullable ProfilePublicKey publicKey) {
|
||||
@ -6396,6 +6566,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())).getBlockState(pos);
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void placeNewPlayer(Connection connection, ServerPlayer player) {
|
||||
+ player.isRealPlayer = true; // Paper
|
||||
GameProfile gameprofile = player.getGameProfile();
|
||||
GameProfileCache usercache = this.server.getProfileCache();
|
||||
Optional<GameProfile> optional = usercache.get(gameprofile.getId());
|
||||
diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
@ -6864,7 +7046,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
// CraftBukkit end
|
||||
|
||||
+ // Paper start
|
||||
+ public final com.destroystokyo.paper.util.maplist.EntityList entities = new com.destroystokyo.paper.util.maplist.EntityList();
|
||||
+ public @Nullable ChunkHolder playerChunk;
|
||||
+
|
||||
+ static final int NEIGHBOUR_CACHE_RADIUS = 3;
|
||||
|
@ -1,48 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
Date: Fri, 24 Apr 2020 09:06:15 -0700
|
||||
Subject: [PATCH] Make CallbackExecutor strict again
|
||||
|
||||
The correct fix for double scheduling is to avoid it. The reason
|
||||
this class is used is because double scheduling causes issues
|
||||
elsewhere, and it acts as an explicit detector of what double
|
||||
schedules. Effectively, use the callback executor as a tool of
|
||||
finding issues rather than hiding these issues.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public final CallbackExecutor callbackExecutor = new CallbackExecutor();
|
||||
public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable {
|
||||
|
||||
- private final java.util.Queue<Runnable> queue = new java.util.ArrayDeque<>();
|
||||
+ private Runnable queued; // Paper - revert CB changes
|
||||
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
- this.queue.add(runnable);
|
||||
+ // Paper start - revert CB changes
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Callback Executor execute");
|
||||
+ if (this.queued != null) {
|
||||
+ LOGGER.error("Failed to schedule runnable", new IllegalStateException("Already queued"));
|
||||
+ throw new IllegalStateException("Already queued");
|
||||
+ }
|
||||
+ this.queued = runnable;
|
||||
+ // Paper end - revert CB changes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
- Runnable task;
|
||||
- while ((task = this.queue.poll()) != null) {
|
||||
+ // Paper start - revert CB changes
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Callback Executor execute");
|
||||
+ Runnable task = this.queued;
|
||||
+ if (task != null) {
|
||||
+ this.queued = null;
|
||||
+ // Paper end - revert CB changes
|
||||
task.run();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 20 Sep 2020 16:10:49 -0700
|
||||
Subject: [PATCH] Make sure inlined getChunkAt has inlined logic for loaded
|
||||
chunks
|
||||
|
@ -1,36 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Brokkonaut <hannos17@gmx.de>
|
||||
Date: Tue, 7 Feb 2017 16:55:35 -0600
|
||||
Subject: [PATCH] Make targetSize more aggressive in the chunk unload queue
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.entityMap = new Int2ObjectOpenHashMap();
|
||||
this.chunkTypeCache = new Long2ByteOpenHashMap();
|
||||
this.chunkSaveCooldowns = new Long2LongOpenHashMap();
|
||||
- this.unloadQueue = Queues.newConcurrentLinkedQueue();
|
||||
+ this.unloadQueue = new com.destroystokyo.paper.utils.CachedSizeConcurrentLinkedQueue<>(); // Paper - need constant-time size()
|
||||
this.structureTemplateManager = structureTemplateManager;
|
||||
Path path = session.getDimensionPath(world.dimension());
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
private void processUnloads(BooleanSupplier shouldKeepTicking) {
|
||||
LongIterator longiterator = this.toDrop.iterator();
|
||||
-
|
||||
for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) {
|
||||
long j = longiterator.nextLong();
|
||||
ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
}
|
||||
|
||||
- int k = Math.max(0, this.unloadQueue.size() - 2000);
|
||||
+ int k = Math.max(100, this.unloadQueue.size() - 2000); // Paper - Unload more than just up to queue size 2000
|
||||
|
||||
Runnable runnable;
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Jul 2020 22:48:48 -0700
|
||||
Subject: [PATCH] Manually inline methods in BlockPosition
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 19 Jul 2020 15:17:01 -0700
|
||||
Subject: [PATCH] Name craft scheduler threads according to the plugin using
|
||||
them
|
||||
|
@ -10,14 +10,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
@@ -0,0 +0,0 @@ public class EnderDragon extends Mob implements Enemy {
|
||||
if (this.dragonDeathTime == 1 && !this.isSilent()) {
|
||||
// CraftBukkit start - Use relative location for far away sounds
|
||||
// this.world.b(1028, this.getChunkCoordinates(), 0);
|
||||
- int viewDistance = ((ServerLevel) this.level).getCraftServer().getViewDistance() * 16;
|
||||
int viewDistance = ((ServerLevel) this.level).getCraftServer().getViewDistance() * 16;
|
||||
- for (net.minecraft.server.level.ServerPlayer player : this.level.getServer().getPlayerList().players) {
|
||||
+ //int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16; // Paper - updated to use worlds actual view distance incase we have to uncomment this due to removal of player view distance API
|
||||
+ for (net.minecraft.server.level.ServerPlayer player : (List<net.minecraft.server.level.ServerPlayer>) ((ServerLevel)level).players()) {
|
||||
+ final int viewDistance = player.getViewDistance(); // TODO apply view distance api patch
|
||||
double deltaX = this.getX() - player.getX();
|
||||
double deltaZ = this.getZ() - player.getZ();
|
||||
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
|
||||
@ -26,14 +23,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
|
||||
@@ -0,0 +0,0 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob
|
||||
if (!this.isSilent()) {
|
||||
// CraftBukkit start - Use relative location for far away sounds
|
||||
// this.world.globalLevelEvent(1023, new BlockPosition(this), 0);
|
||||
- int viewDistance = ((ServerLevel) this.level).getCraftServer().getViewDistance() * 16;
|
||||
int viewDistance = ((ServerLevel) this.level).getCraftServer().getViewDistance() * 16;
|
||||
- for (ServerPlayer player : (List<ServerPlayer>) MinecraftServer.getServer().getPlayerList().players) {
|
||||
+ //int viewDistance = ((ServerLevel) this.level).getCraftServer().getViewDistance() * 16; // Paper - updated to use worlds actual view distance incase we have to uncomment this due to removal of player view distance API
|
||||
+ for (ServerPlayer player : (List<ServerPlayer>)this.level.players()) { // Paper
|
||||
+ final int viewDistance = player.getViewDistance(); // TODO apply view distance api patch
|
||||
double deltaX = this.getX() - player.getX();
|
||||
double deltaZ = this.getZ() - player.getZ();
|
||||
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
|
||||
|
@ -10,14 +10,6 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/j
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ import org.slf4j.Logger;
|
||||
import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
||||
import org.bukkit.entity.Player;
|
||||
// CraftBukkit end
|
||||
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
||||
|
||||
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final Entity entity;
|
||||
private final int range;
|
||||
|
@ -1,88 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Wed, 15 Apr 2020 18:23:28 -0700
|
||||
Subject: [PATCH] Optimise ArraySetSorted#removeIf
|
||||
|
||||
Remove iterator allocation and ensure the call is always O(n)
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
protected void purgeStaleTickets() {
|
||||
++this.ticketTickCounter;
|
||||
ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().fastIterator();
|
||||
+ // Paper start - use optimised removeIf
|
||||
+ long[] currChunk = new long[1];
|
||||
+ long ticketCounter = DistanceManager.this.ticketTickCounter;
|
||||
+ java.util.function.Predicate<Ticket<?>> removeIf = (ticket) -> {
|
||||
+ final boolean ret = ticket.timedOut(ticketCounter);
|
||||
+ if (ret) {
|
||||
+ this.tickingTicketsTracker.removeTicket(currChunk[0], ticket);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ };
|
||||
+ // Paper end - use optimised removeIf
|
||||
|
||||
while (objectiterator.hasNext()) {
|
||||
Entry<SortedArraySet<Ticket<?>>> entry = (Entry) objectiterator.next();
|
||||
- Iterator<Ticket<?>> iterator = ((SortedArraySet) entry.getValue()).iterator();
|
||||
- boolean flag = false;
|
||||
+ // Paper start - use optimised removeIf
|
||||
+ Iterator<Ticket<?>> iterator = null;
|
||||
+ currChunk[0] = entry.getLongKey();
|
||||
+ boolean flag = entry.getValue().removeIf(removeIf);
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
+ while (false && iterator.hasNext()) {
|
||||
+ // Paper end - use optimised removeIf
|
||||
Ticket<?> ticket = (Ticket) iterator.next();
|
||||
|
||||
if (ticket.timedOut(this.ticketTickCounter)) {
|
||||
diff --git a/src/main/java/net/minecraft/util/SortedArraySet.java b/src/main/java/net/minecraft/util/SortedArraySet.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/util/SortedArraySet.java
|
||||
+++ b/src/main/java/net/minecraft/util/SortedArraySet.java
|
||||
@@ -0,0 +0,0 @@ public class SortedArraySet<T> extends AbstractSet<T> {
|
||||
this.contents = (T[])castRawArray(new Object[initialCapacity]);
|
||||
}
|
||||
}
|
||||
+ // Paper start - optimise removeIf
|
||||
+ @Override
|
||||
+ public boolean removeIf(java.util.function.Predicate<? super T> filter) {
|
||||
+ // prev. impl used an iterator, which could be n^2 and creates garbage
|
||||
+ int i = 0, len = this.size;
|
||||
+ T[] backingArray = this.contents;
|
||||
+
|
||||
+ for (;;) {
|
||||
+ if (i >= len) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (!filter.test(backingArray[i])) {
|
||||
+ ++i;
|
||||
+ continue;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ // we only want to write back to backingArray if we really need to
|
||||
+
|
||||
+ int lastIndex = i; // this is where new elements are shifted to
|
||||
+
|
||||
+ for (; i < len; ++i) {
|
||||
+ T curr = backingArray[i];
|
||||
+ if (!filter.test(curr)) { // if test throws we're screwed
|
||||
+ backingArray[lastIndex++] = curr;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // cleanup end
|
||||
+ Arrays.fill(backingArray, lastIndex, len, null);
|
||||
+ this.size = lastIndex;
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - optimise removeIf
|
||||
|
||||
public static <T extends Comparable<T>> SortedArraySet<T> create() {
|
||||
return create(10);
|
@ -10,8 +10,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager;
|
||||
// Paper end
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
+ // Paper start - optimise getPlayerByUUID
|
||||
+ @Nullable
|
||||
|
@ -1,337 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
Date: Thu, 9 Jul 2020 13:34:59 -0700
|
||||
Subject: [PATCH] Optimise WorldServer#notify
|
||||
|
||||
Iterating over all of the navigators in the world is pretty expensive.
|
||||
Instead, only iterate over navigators in the current region that are
|
||||
eligible for repathing.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public final io.papermc.paper.chunk.SingleThreadChunkRegionManager dataRegionManager;
|
||||
|
||||
public static final class DataRegionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionData {
|
||||
+ // Paper start - optimise notify()
|
||||
+ private io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> navigators;
|
||||
+
|
||||
+ public io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> getNavigators() {
|
||||
+ return this.navigators;
|
||||
+ }
|
||||
+
|
||||
+ public boolean addToNavigators(final Mob navigator) {
|
||||
+ if (this.navigators == null) {
|
||||
+ this.navigators = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>();
|
||||
+ }
|
||||
+ return this.navigators.add(navigator);
|
||||
+ }
|
||||
+
|
||||
+ public boolean removeFromNavigators(final Mob navigator) {
|
||||
+ if (this.navigators == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return this.navigators.remove(navigator);
|
||||
+ }
|
||||
+ // Paper end - optimise notify()
|
||||
}
|
||||
|
||||
public static final class DataRegionSectionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSectionData {
|
||||
|
||||
+ // Paper start - optimise notify()
|
||||
+ private io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> navigators;
|
||||
+
|
||||
+ public io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> getNavigators() {
|
||||
+ return this.navigators;
|
||||
+ }
|
||||
+
|
||||
+ public boolean addToNavigators(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section, final Mob navigator) {
|
||||
+ if (this.navigators == null) {
|
||||
+ this.navigators = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>();
|
||||
+ }
|
||||
+ final boolean ret = this.navigators.add(navigator);
|
||||
+ if (ret) {
|
||||
+ final DataRegionData data = (DataRegionData)section.getRegion().regionData;
|
||||
+ if (!data.addToNavigators(navigator)) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ public boolean removeFromNavigators(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section, final Mob navigator) {
|
||||
+ if (this.navigators == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ final boolean ret = this.navigators.remove(navigator);
|
||||
+ if (ret) {
|
||||
+ final DataRegionData data = (DataRegionData)section.getRegion().regionData;
|
||||
+ if (!data.removeFromNavigators(navigator)) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Paper end - optimise notify()
|
||||
+
|
||||
@Override
|
||||
public void removeFromRegion(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section,
|
||||
final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region from) {
|
||||
final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
|
||||
final DataRegionData fromData = (DataRegionData)from.regionData;
|
||||
+ // Paper start - optimise notify()
|
||||
+ if (sectionData.navigators != null) {
|
||||
+ for (final Iterator<Mob> iterator = sectionData.navigators.unsafeIterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) {
|
||||
+ if (!fromData.removeFromNavigators(iterator.next())) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise notify()
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
|
||||
final DataRegionData oldRegionData = oldRegion == null ? null : (DataRegionData)oldRegion.regionData;
|
||||
final DataRegionData newRegionData = (DataRegionData)newRegion.regionData;
|
||||
+ // Paper start - optimise notify()
|
||||
+ if (sectionData.navigators != null) {
|
||||
+ for (final Iterator<Mob> iterator = sectionData.navigators.unsafeIterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) {
|
||||
+ if (!newRegionData.addToNavigators(iterator.next())) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise notify()
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
public void tickNonPassenger(Entity entity) {
|
||||
// Paper start - log detailed entity tick information
|
||||
io.papermc.paper.util.TickThread.ensureTickThread("Cannot tick an entity off-main");
|
||||
+ if (!entity.isRemoved()) this.entityManager.updateNavigatorsInRegion(entity); // Paper - optimise notify
|
||||
try {
|
||||
if (currentlyTickingEntity.get() == null) {
|
||||
currentlyTickingEntity.lazySet(entity);
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) {
|
||||
List<PathNavigation> list = new ObjectArrayList();
|
||||
- Iterator iterator = this.navigatingMobs.iterator();
|
||||
+ // Paper start - optimise notify()
|
||||
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region region = this.getChunkSource().chunkMap.dataRegionManager.getRegion(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
+ if (region == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Mob> navigatorsFromRegion = ((ChunkMap.DataRegionData)region.regionData).getNavigators();
|
||||
+ if (navigatorsFromRegion == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Mob> iterator = navigatorsFromRegion.iterator();
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
+ try { while (iterator.hasNext()) { // Paper end - optimise notify()
|
||||
// CraftBukkit start - fix SPIGOT-6362
|
||||
Mob entityinsentient;
|
||||
try {
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
try {
|
||||
this.isUpdatingNavigations = true;
|
||||
- iterator = list.iterator();
|
||||
+ // Paper start - optimise notify()
|
||||
+ Iterator<PathNavigation> navigationIterator = list.iterator();
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
- PathNavigation navigationabstract1 = (PathNavigation) iterator.next();
|
||||
+ while (navigationIterator.hasNext()) {
|
||||
+ PathNavigation navigationabstract1 = navigationIterator.next();
|
||||
+ // Paper end - optimise notify()
|
||||
|
||||
navigationabstract1.recomputePath();
|
||||
}
|
||||
} finally {
|
||||
this.isUpdatingNavigations = false;
|
||||
}
|
||||
+ // Paper start - optimise notify()
|
||||
+ } finally {
|
||||
+ iterator.finishedIterating();
|
||||
+ }
|
||||
+ // Paper end - optimise notify()
|
||||
|
||||
}
|
||||
} // Paper
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
public void onTickingStart(Entity entity) {
|
||||
ServerLevel.this.entityTickList.add(entity);
|
||||
+ ServerLevel.this.entityManager.addNavigatorsIfPathingToRegion(entity); // Paper - optimise notify
|
||||
}
|
||||
|
||||
public void onTickingEnd(Entity entity) {
|
||||
ServerLevel.this.entityTickList.remove(entity);
|
||||
+ ServerLevel.this.entityManager.removeNavigatorsFromData(entity); // Paper - optimise notify
|
||||
// Paper start - Reset pearls when they stop being ticked
|
||||
if (paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) {
|
||||
pearl.cachedOwner = null;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public abstract class PathNavigation {
|
||||
private static final int MAX_TIME_RECOMPUTE = 20;
|
||||
- protected final Mob mob;
|
||||
+ protected final Mob mob; public final Mob getEntity() { return this.mob; } // Paper - public accessor
|
||||
protected final Level level;
|
||||
@Nullable
|
||||
protected Path path;
|
||||
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
|
||||
protected long lastTimeoutCheck;
|
||||
protected double timeoutLimit;
|
||||
protected float maxDistanceToWaypoint = 0.5F;
|
||||
- protected boolean hasDelayedRecomputation;
|
||||
+ protected boolean hasDelayedRecomputation; protected final boolean needsPathRecalculation() { return this.hasDelayedRecomputation; } // Paper - public accessor
|
||||
protected long timeLastRecompute;
|
||||
protected NodeEvaluator nodeEvaluator;
|
||||
@Nullable
|
||||
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
|
||||
public boolean shouldRecomputePath(BlockPos pos) {
|
||||
if (this.hasDelayedRecomputation) {
|
||||
return false;
|
||||
- } else if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) {
|
||||
+ } else if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) { // Paper - diff on change - needed for isViableForPathRecalculationChecking()
|
||||
Node node = this.path.getEndNode();
|
||||
Vec3 vec3 = new Vec3(((double)node.x + this.mob.getX()) / 2.0D, ((double)node.y + this.mob.getY()) / 2.0D, ((double)node.z + this.mob.getZ()) / 2.0D);
|
||||
return pos.closerToCenterThan(vec3, (double)(this.path.getNodeCount() - this.path.getNextNodeIndex()));
|
||||
@@ -0,0 +0,0 @@ public abstract class PathNavigation {
|
||||
public boolean isStuck() {
|
||||
return this.isStuck;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public boolean isViableForPathRecalculationChecking() {
|
||||
+ return !this.needsPathRecalculation() &&
|
||||
+ (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
+ // Paper start - optimise notify()
|
||||
+ public final void removeNavigatorsFromData(Entity entity, final int chunkX, final int chunkZ) {
|
||||
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
||||
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(chunkX, chunkZ);
|
||||
+ if (section != null) {
|
||||
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
||||
+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public final void removeNavigatorsFromData(Entity entity) {
|
||||
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ BlockPos entityPos = entity.blockPosition();
|
||||
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
||||
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4);
|
||||
+ if (section != null) {
|
||||
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
||||
+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public final void addNavigatorsIfPathingToRegion(Entity entity) {
|
||||
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ BlockPos entityPos = entity.blockPosition();
|
||||
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
||||
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4);
|
||||
+ if (section != null) {
|
||||
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
||||
+ if (((net.minecraft.world.entity.Mob)entity).getNavigation().isViableForPathRecalculationChecking()) {
|
||||
+ sectionData.addToNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public final void updateNavigatorsInRegion(Entity entity) {
|
||||
+ if (!(entity instanceof net.minecraft.world.entity.Mob)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ BlockPos entityPos = entity.blockPosition();
|
||||
+ io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section =
|
||||
+ this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.getRegionSection(entityPos.getX() >> 4, entityPos.getZ() >> 4);
|
||||
+ if (section != null) {
|
||||
+ net.minecraft.server.level.ChunkMap.DataRegionSectionData sectionData = (net.minecraft.server.level.ChunkMap.DataRegionSectionData)section.sectionData;
|
||||
+ if (((net.minecraft.world.entity.Mob)entity).getNavigation().isViableForPathRecalculationChecking()) {
|
||||
+ sectionData.addToNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
||||
+ } else {
|
||||
+ sectionData.removeFromNavigators(section, ((net.minecraft.world.entity.Mob)entity));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise notify()
|
||||
+
|
||||
void removeSectionIfEmpty(long sectionPos, EntitySection<T> section) {
|
||||
if (section.isEmpty()) {
|
||||
this.sectionStorage.remove(sectionPos);
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
@Override
|
||||
public void onMove() {
|
||||
BlockPos blockposition = this.entity.blockPosition();
|
||||
- long i = SectionPos.asLong(blockposition);
|
||||
+ long i = SectionPos.asLong(blockposition); final long newSectionPos = i; // Paper - diff on change, new position section
|
||||
|
||||
if (i != this.currentSectionKey) {
|
||||
PersistentEntitySectionManager.this.entitySliceManager.moveEntity((Entity)this.entity); // Paper
|
||||
- Visibility visibility = this.currentSection.getStatus();
|
||||
+ Visibility visibility = this.currentSection.getStatus(); final Visibility oldVisibility = visibility; // Paper - diff on change - this should be OLD section visibility
|
||||
+ // Paper start
|
||||
+ int shift = PersistentEntitySectionManager.this.entitySliceManager.world.getChunkSource().chunkMap.dataRegionManager.regionChunkShift;
|
||||
+ int oldChunkX = io.papermc.paper.util.CoordinateUtils.getChunkSectionX(this.currentSectionKey);
|
||||
+ int oldChunkZ = io.papermc.paper.util.CoordinateUtils.getChunkSectionZ(this.currentSectionKey);
|
||||
+ int oldRegionX = oldChunkX >> shift;
|
||||
+ int oldRegionZ = oldChunkZ >> shift;
|
||||
+
|
||||
+ int newRegionX = io.papermc.paper.util.CoordinateUtils.getChunkSectionX(newSectionPos) >> shift;
|
||||
+ int newRegionZ = io.papermc.paper.util.CoordinateUtils.getChunkSectionZ(newSectionPos) >> shift;
|
||||
+
|
||||
+ if (oldRegionX != newRegionX || oldRegionZ != newRegionZ) {
|
||||
+ PersistentEntitySectionManager.this.removeNavigatorsFromData((Entity)this.entity, oldChunkX, oldChunkZ);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
if (!this.currentSection.remove(this.entity)) {
|
||||
PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (moving to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), i});
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
entitysection.add(this.entity);
|
||||
this.currentSection = entitysection;
|
||||
this.currentSectionKey = i;
|
||||
+ // Paper start
|
||||
+ if ((oldRegionX != newRegionX || oldRegionZ != newRegionZ) && oldVisibility.isTicking() && entitysection.getStatus().isTicking()) {
|
||||
+ PersistentEntitySectionManager.this.addNavigatorsIfPathingToRegion((Entity)this.entity);
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.updateStatus(visibility, entitysection.getStatus());
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 7 May 2020 05:48:54 -0700
|
||||
Subject: [PATCH] Optimise chunk tick iteration
|
||||
|
||||
@ -75,14 +75,23 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/j
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
||||
import org.bukkit.entity.Player;
|
||||
// CraftBukkit end
|
||||
|
||||
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
||||
+
|
||||
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
|
||||
|
||||
private static final byte CHUNK_TYPE_REPLACEABLE = -1;
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
private final Queue<Runnable> unloadQueue;
|
||||
int viewDistance;
|
||||
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper
|
||||
+ public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
|
||||
|
||||
// CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback()
|
||||
public final CallbackExecutor callbackExecutor = new CallbackExecutor();
|
||||
// Paper - rewrite chunk system
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@ -147,14 +156,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
ChunkPos chunkcoordintpair = chunk1.getPos();
|
||||
|
||||
- if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ if ((true || this.level.isNaturalSpawningAllowed(chunkcoordintpair)) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning // Paper - the chunk is known ticking
|
||||
chunk1.incrementInhabitedTime(j);
|
||||
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration
|
||||
NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1);
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
- if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) {
|
||||
+ if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - the chunk is known ticking
|
||||
this.level.tickChunk(chunk1, k);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 2 Jul 2020 12:02:43 -0700
|
||||
Subject: [PATCH] Optimise collision checking in player move packet handling
|
||||
|
||||
|
@ -879,15 +879,6 @@ diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
||||
public static final int VILLAGE_SECTION_SIZE = 1;
|
||||
private final PoiManager.DistanceTracker distanceTracker;
|
||||
private final LongSet loadedChunks = new LongOpenHashSet();
|
||||
- private final net.minecraft.server.level.ServerLevel world; // Paper
|
||||
+ public final net.minecraft.server.level.ServerLevel world; // Paper // Paper public
|
||||
|
||||
public PoiManager(Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) {
|
||||
super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world);
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
||||
}
|
||||
|
||||
@ -982,7 +973,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ private final Map<Holder<PoiType>, Set<PoiRecord>> byType = Maps.newHashMap(); public final Map<Holder<PoiType>, Set<PoiRecord>> getData() { return this.byType; } // Paper - public accessor
|
||||
private final Runnable setDirty;
|
||||
private boolean isValid;
|
||||
|
||||
public final Optional<PoiSection> noAllocateOptional = Optional.of(this); // Paper - rewrite chunk system
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
|
@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
gameprofilerfiller.incrementCounter("getChunk");
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
if (Thread.currentThread() != this.mainThread) {
|
||||
if (!io.papermc.paper.util.TickThread.isTickThread()) { // Paper - rewrite chunk system
|
||||
return null;
|
||||
} else {
|
||||
- this.level.getProfiler().incrementCounter("getChunkNow");
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Wed, 3 Jun 2020 11:37:13 -0700
|
||||
Subject: [PATCH] Optimise getType calls
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 27 Aug 2020 16:22:52 -0700
|
||||
Subject: [PATCH] Optimise nearby player lookups
|
||||
|
||||
@ -43,27 +43,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper
|
||||
public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
|
||||
|
||||
// Paper - rewrite chunk system
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40;
|
||||
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1);
|
||||
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED = GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE * GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE;
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap;
|
||||
+ // Paper end - optimise checkDespawn
|
||||
+
|
||||
// CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback()
|
||||
public final CallbackExecutor callbackExecutor = new CallbackExecutor();
|
||||
public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable {
|
||||
|
||||
// Paper start - distance maps
|
||||
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player)));
|
||||
}
|
||||
// Paper end - use distance map to optimise entity tracker
|
||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||
this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.add(player, chunkX, chunkZ, this.distanceManager.getSimulationDistance());
|
||||
}
|
||||
|
||||
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.playerMobSpawnMap.remove(player);
|
||||
this.playerChunkTickRangeMap.remove(player);
|
||||
@ -73,13 +72,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.remove(player);
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player)));
|
||||
}
|
||||
// Paper end - use distance map to optimise entity tracker
|
||||
this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.update(player, chunkX, chunkZ, this.distanceManager.getSimulationDistance());
|
||||
}
|
||||
// Paper end
|
||||
// Paper start
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 22 Sep 2020 01:49:19 -0700
|
||||
Subject: [PATCH] Optimise non-flush packet sending
|
||||
|
||||
|
@ -26,5 +26,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
+ // Paper end
|
||||
// CraftBukkit end
|
||||
return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE));
|
||||
return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -0,0 +0,0 @@ public abstract class BlockBehaviour {
|
||||
this.emissiveRendering = blockbase_info.emissiveRendering;
|
||||
this.offsetType = (BlockBehaviour.OffsetType) blockbase_info.offsetType.apply(this.asState());
|
||||
this.conditionallyFullOpaque = this.isOpaque() & this.isTransparentOnSomeFaces(); // Paper
|
||||
}
|
||||
+ // Paper start - impl cached craft block data, lazy load to fix issue with loading at the wrong time
|
||||
+ private org.bukkit.craftbukkit.block.data.CraftBlockData cachedCraftBlockData;
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 17:53:29 -0700
|
||||
Subject: [PATCH] Optimize GoalSelector Goal.Flag Set operations
|
||||
|
||||
|
@ -185,6 +185,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
|
||||
- private void flushQueue() {
|
||||
- try { // Paper - add pending task queue
|
||||
- if (this.channel != null && this.channel.isOpen()) {
|
||||
- Queue queue = this.queue;
|
||||
-
|
||||
@ -209,6 +210,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ return false;
|
||||
+ }
|
||||
+ private boolean processQueue() {
|
||||
+ try { // Paper - add pending task queue
|
||||
+ if (this.queue.isEmpty()) return true;
|
||||
+ // If we are on main, we are safe here in that nothing else should be processing queue off main anymore
|
||||
+ // But if we are not on main due to login/status, the parent is synchronized on packetQueue
|
||||
@ -230,6 +232,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
}
|
||||
+ return true;
|
||||
} finally { // Paper start - add pending task queue
|
||||
Runnable r;
|
||||
while ((r = this.pendingTasks.poll()) != null) {
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
} // Paper end - add pending task queue
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
|
@ -1,69 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 16 Apr 2020 16:13:59 -0700
|
||||
Subject: [PATCH] Optimize ServerLevels chunk level checking methods
|
||||
|
||||
These can be hot functions (i.e entity ticking and block ticking),
|
||||
so inline where possible, and avoid the abstraction of the
|
||||
Either class.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
|
||||
private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) {
|
||||
- return this.areEntitiesLoaded(chunkPos) && this.chunkSource.isPositionTicking(chunkPos);
|
||||
+ // Paper start - optimize is ticking ready type functions
|
||||
+ ChunkHolder chunkHolder = this.chunkSource.chunkMap.getVisibleChunkIfPresent(chunkPos);
|
||||
+ return chunkHolder != null && this.chunkSource.isPositionTicking(chunkPos) && chunkHolder.isTickingReady() && this.areEntitiesLoaded(chunkPos);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public boolean isPositionEntityTicking(BlockPos pos) {
|
||||
- return this.entityManager.canPositionTick(pos) && this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(ChunkPos.asLong(pos));
|
||||
+ return this.entityManager.canPositionTick(ChunkPos.asLong(pos)) && this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(ChunkPos.asLong(pos)); // Paper
|
||||
}
|
||||
|
||||
public boolean isNaturalSpawningAllowed(BlockPos pos) {
|
||||
- return this.entityManager.canPositionTick(pos);
|
||||
+ return this.entityManager.canPositionTick(ChunkPos.asLong(pos)); // Paper
|
||||
}
|
||||
|
||||
public boolean isNaturalSpawningAllowed(ChunkPos pos) {
|
||||
- return this.entityManager.canPositionTick(pos);
|
||||
+ return this.entityManager.canPositionTick(pos.toLong()); // Paper
|
||||
}
|
||||
|
||||
private final class EntityCallbacks implements LevelCallback<Entity> {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ChunkPos.java b/src/main/java/net/minecraft/world/level/ChunkPos.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ChunkPos.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ChunkPos.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkPos {
|
||||
}
|
||||
|
||||
public static long asLong(BlockPos pos) {
|
||||
- return asLong(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
|
||||
+ return (((long)pos.getX() >> 4) & 4294967295L) | ((((long)pos.getZ() >> 4) & 4294967295L) << 32); // Paper - inline
|
||||
}
|
||||
|
||||
public static int getX(long pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
public LevelEntityGetter<T> getEntityGetter() {
|
||||
return this.entityGetter;
|
||||
}
|
||||
+ // Paper start
|
||||
+ public final boolean canPositionTick(long position) {
|
||||
+ return this.chunkVisibility.get(position).isTicking();
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public boolean canPositionTick(BlockPos pos) {
|
||||
return ((Visibility) this.chunkVisibility.get(ChunkPos.asLong(pos))).isTicking();
|
@ -30,23 +30,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public final io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder; // Paper - rewrite chunk system
|
||||
|
||||
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ // cached here to avoid a map lookup
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange;
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInChunkTickRange;
|
||||
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
+
|
||||
public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
|
||||
this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
|
||||
this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
|
||||
public ChunkHolder(ChunkPos pos, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.PlayerProvider playersWatchingChunkProvider, io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder) { // Paper - rewrite chunk system
|
||||
this.newChunkHolder = newChunkHolder; // Paper - rewrite chunk system
|
||||
this.chunkToSaveHistory = null;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper
|
||||
// Paper start - distance maps
|
||||
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
||||
public final io.papermc.paper.chunk.PlayerChunkLoader playerChunkManager = new io.papermc.paper.chunk.PlayerChunkLoader(this, this.pooledLinkedPlayerHashSets); // Paper - replace chunk loader
|
||||
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ // A note about the naming used here:
|
||||
+ // Previously, mojang used a "spawn range" of 8 for controlling both ticking and
|
||||
@ -60,16 +62,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
|
||||
void addPlayerToDistanceMaps(ServerPlayer player) {
|
||||
this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader
|
||||
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||
+ this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.add(player, chunkX, chunkZ, this.distanceManager.getSimulationDistance());
|
||||
this.playerMobDistanceMap.add(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player));
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||
this.playerChunkManager.removePlayer(player); // Paper - replace chunk loader
|
||||
|
||||
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ this.playerMobSpawnMap.remove(player);
|
||||
@ -79,13 +82,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.remove(player);
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||
this.playerChunkManager.updatePlayer(player); // Paper - replace chunk loader
|
||||
+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.update(player, chunkX, chunkZ, this.distanceManager.getSimulationDistance());
|
||||
this.playerMobDistanceMap.update(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player));
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.regionManagers.add(this.dataRegionManager);
|
||||
// Paper end
|
||||
@ -210,43 +213,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
private static final int BLOCK_TICKING_LEVEL_THRESHOLD = 33;
|
||||
final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap();
|
||||
public final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets = new Long2ObjectOpenHashMap();
|
||||
private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker();
|
||||
// Paper - rewrite chunk system
|
||||
- private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
|
||||
+ public static final int MOB_SPAWN_RANGE = 8; // private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used
|
||||
private final TickingTracker tickingTicketsTracker = new TickingTracker();
|
||||
private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33);
|
||||
// Paper start use a queue, but still keep unique requirement
|
||||
+ public static final int MOB_SPAWN_RANGE = 8; // private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); // Paper - no longer used
|
||||
//private final TickingTracker tickingTicketsTracker = new TickingTracker(); // Paper - no longer used
|
||||
//private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33); // Paper - no longer used
|
||||
// Paper - rewrite chunk system
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k);
|
||||
long i = chunkcoordintpair.toLong();
|
||||
|
||||
public boolean runAllUpdates(ChunkMap chunkStorage) {
|
||||
- this.naturalSpawnChunkCounter.runAllUpdates();
|
||||
+ //this.f.a(); // Paper - no longer used
|
||||
this.tickingTicketsTracker.runAllUpdates();
|
||||
org.spigotmc.AsyncCatcher.catchOp("DistanceManagerTick"); // Paper
|
||||
this.playerTicketManager.runAllUpdates();
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
((ObjectSet) this.playersPerChunk.computeIfAbsent(i, (j) -> {
|
||||
return new ObjectOpenHashSet();
|
||||
})).add(player);
|
||||
// Paper - no longer used
|
||||
- this.naturalSpawnChunkCounter.update(i, 0, true);
|
||||
+ //this.f.update(i, 0, true); // Paper - no longer used
|
||||
this.playerTicketManager.update(i, 0, true);
|
||||
this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair);
|
||||
+ //this.naturalSpawnChunkCounter.update(i, 0, true); // Paper - no longer used
|
||||
//this.playerTicketManager.update(i, 0, true); // Paper - no longer used
|
||||
//this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully.
|
||||
if (objectset == null || objectset.isEmpty()) { // Paper
|
||||
this.playersPerChunk.remove(i);
|
||||
- this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
||||
+ //this.f.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
||||
this.playerTicketManager.update(i, Integer.MAX_VALUE, false);
|
||||
this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair);
|
||||
+ // this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
||||
//this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
||||
//this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
// Paper end
|
||||
}
|
||||
|
||||
public int getNaturalSpawnChunkCount() {
|
||||
- this.naturalSpawnChunkCounter.runAllUpdates();
|
||||
@ -343,9 +337,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
|
||||
// CraftBukkit end
|
||||
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
||||
|
||||
public boolean isRealPlayer; // Paper
|
||||
+ public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
|
||||
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||
|
||||
|
@ -43,7 +43,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
return () -> {
|
||||
return this.getIndirectPassengersStream().iterator();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
public boolean hasExactlyOnePlayerPassenger() {
|
||||
+ if (this.passengers.isEmpty()) { return false; } // Paper
|
||||
|
@ -58,8 +58,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||
@@ -0,0 +0,0 @@ public class EmptyLevelChunk extends LevelChunk {
|
||||
this.biome = holder;
|
||||
}
|
||||
public void setBlockEmptinessMap(final boolean[] emptinessMap) {}
|
||||
// Paper end - starlight
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
|
@ -438,7 +438,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+package io.papermc.paper.configuration;
|
||||
+
|
||||
+import co.aikar.timings.MinecraftTimings;
|
||||
+import com.destroystokyo.paper.io.chunk.ChunkTaskManager;
|
||||
+import io.papermc.paper.configuration.constraint.Constraint;
|
||||
+import io.papermc.paper.configuration.constraint.Constraints;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
@ -604,15 +603,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ public boolean saveEmptyScoreboardTeams = false;
|
||||
+ }
|
||||
+
|
||||
+ public AsyncChunks asyncChunks;
|
||||
+ public ChunkSystem chunkSystem;
|
||||
+
|
||||
+ public class AsyncChunks extends ConfigurationPart.Post {
|
||||
+ public int threads = -1;
|
||||
+ public transient boolean asyncChunks = false;
|
||||
+ public class ChunkSystem extends ConfigurationPart.Post {
|
||||
+
|
||||
+ public int ioThreads = -1;
|
||||
+ public int workerThreads = -1;
|
||||
+ public String genParallelism = "default";
|
||||
+
|
||||
+ @Override
|
||||
+ public void postProcess() {
|
||||
+ ChunkTaskManager.processConfiguration(this);
|
||||
+ io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.init(this);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
|
@ -18,8 +18,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
import io.papermc.paper.command.subcommands.FixLightCommand;
|
||||
import io.papermc.paper.command.subcommands.HeapDumpCommand;
|
||||
@@ -0,0 +0,0 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("debug", "chunkinfo"), new ChunkDebugCommand());
|
||||
commands.put(Set.of("fixlight"), new FixLightCommand());
|
||||
commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand());
|
||||
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
|
||||
+ commands.put(Set.of("dumpitem"), new DumpItemCommand());
|
||||
|
||||
|
@ -1,112 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <1254957+zachbr@users.noreply.github.com>
|
||||
Date: Mon, 6 May 2019 01:29:25 -0400
|
||||
Subject: [PATCH] Per-Player View Distance API placeholders
|
||||
|
||||
I hope to look at this more in-depth soon. It appears doable.
|
||||
However this should not block the update.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
|
||||
return (CraftPlayer) super.getBukkitEntity();
|
||||
}
|
||||
// CraftBukkit end
|
||||
+
|
||||
+ public final int getViewDistance() { return this.getLevel().getChunkSource().chunkMap.viewDistance - 1; } // Paper - placeholder
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
return world.spigotConfig.simulationDistance;
|
||||
}
|
||||
// Spigot end
|
||||
+ // Paper start - view distance api
|
||||
+ @Override
|
||||
+ public void setViewDistance(int viewDistance) {
|
||||
+ throw new UnsupportedOperationException(); //TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSimulationDistance(int simulationDistance) {
|
||||
+ throw new UnsupportedOperationException(); //TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getNoTickViewDistance() {
|
||||
+ throw new UnsupportedOperationException(); //TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setNoTickViewDistance(int viewDistance) {
|
||||
+ throw new UnsupportedOperationException(); //TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getSendViewDistance() {
|
||||
+ throw new UnsupportedOperationException(); //TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSendViewDistance(int viewDistance) {
|
||||
+ throw new UnsupportedOperationException(); //TODO
|
||||
+ }
|
||||
+ // Paper end - view distance api
|
||||
|
||||
// Spigot start
|
||||
private final org.bukkit.World.Spigot spigot = new org.bukkit.World.Spigot()
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public int getViewDistance() {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setViewDistance(int viewDistance) {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getSimulationDistance() {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSimulationDistance(int simulationDistance) {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getNoTickViewDistance() {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setNoTickViewDistance(int viewDistance) {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getSendViewDistance() {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSendViewDistance(int viewDistance) {
|
||||
+ throw new UnsupportedOperationException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
|
||||
+ }
|
||||
// Paper end
|
||||
|
||||
@Override
|
@ -76,5 +76,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
// CraftBukkit end
|
||||
+ public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
||||
|
||||
public boolean isRealPlayer; // Paper
|
||||
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
Date: Thu, 18 Jun 2020 18:23:20 -0700
|
||||
Subject: [PATCH] Prevent unload() calls removing tickets for sync loads
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||
}
|
||||
|
||||
public void removeTicketsOnClosing() {
|
||||
- ImmutableSet<TicketType<?>> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.LIGHT, TicketType.FUTURE_AWAIT, TicketType.ASYNC_LOAD); // Paper - add additional tickets to preserve
|
||||
+ ImmutableSet<TicketType<?>> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.LIGHT, TicketType.FUTURE_AWAIT, TicketType.ASYNC_LOAD, TicketType.REQUIRED_LOAD); // Paper - add additional tickets to preserve
|
||||
ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().fastIterator();
|
||||
|
||||
while (objectiterator.hasNext()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
return completablefuture;
|
||||
}
|
||||
|
||||
+ private long syncLoadCounter; // Paper - prevent plugin unloads from removing our ticket
|
||||
+
|
||||
private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
|
||||
// Paper start - add isUrgent - old sig left in place for dirty nms plugins
|
||||
return getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create, false);
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
ChunkHolder.FullChunkStatus currentChunkState = ChunkHolder.getFullChunkStatus(playerchunk.getTicketLevel());
|
||||
currentlyUnloading = (oldChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !currentChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER));
|
||||
}
|
||||
+ final Long identifier; // Paper - prevent plugin unloads from removing our ticket
|
||||
if (create && !currentlyUnloading) {
|
||||
// CraftBukkit end
|
||||
this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
|
||||
+ identifier = Long.valueOf(this.syncLoadCounter++); // Paper - prevent plugin unloads from removing our ticket
|
||||
+ this.distanceManager.addTicket(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Paper - prevent plugin unloads from removing our ticket
|
||||
if (isUrgent) this.distanceManager.markUrgent(chunkcoordintpair); // Paper - Chunk priority
|
||||
if (this.chunkAbsent(playerchunk, l)) {
|
||||
ProfilerFiller gameprofilerfiller = this.level.getProfiler();
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
playerchunk = this.getVisibleChunkIfPresent(k);
|
||||
gameprofilerfiller.pop();
|
||||
if (this.chunkAbsent(playerchunk, l)) {
|
||||
+ this.distanceManager.removeTicket(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Paper
|
||||
throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added"));
|
||||
}
|
||||
}
|
||||
- }
|
||||
|
||||
+ } else { identifier = null; } // Paper - prevent plugin unloads from removing our ticket
|
||||
// Paper start - Chunk priority
|
||||
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.chunkAbsent(playerchunk, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.getOrScheduleFuture(leastStatus, this.chunkMap);
|
||||
+ // Paper start - prevent plugin unloads from removing our ticket
|
||||
+ if (create && !currentlyUnloading) {
|
||||
+ future.thenAcceptAsync((either) -> {
|
||||
+ ServerChunkCache.this.distanceManager.removeTicket(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier);
|
||||
+ }, ServerChunkCache.this.mainThreadProcessor);
|
||||
+ }
|
||||
+ // Paper end - prevent plugin unloads from removing our ticket
|
||||
if (isUrgent) {
|
||||
future.thenAccept(either -> this.distanceManager.clearUrgent(chunkcoordintpair));
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
@@ -0,0 +0,0 @@ public class TicketType<T> {
|
||||
public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
|
||||
public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
|
||||
public static final TicketType<Long> DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper
|
||||
+ public static final TicketType<Long> REQUIRED_LOAD = create("required_load", Long::compareTo); // Paper - make sure getChunkAt does not fail
|
||||
|
||||
public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) {
|
||||
return new TicketType<>(name, argumentComparator, 0L);
|
@ -38,4 +38,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ // Paper - move up
|
||||
|
||||
this.getServer().prepareLevels(internal.getChunkSource().chunkMap.progressListener, internal);
|
||||
internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API
|
||||
//internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API // Paper - rewrite chunk system
|
||||
|
@ -1,5 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 18:35:09 -0700
|
||||
Subject: [PATCH] Reduce Either Optional allocation
|
||||
|
||||
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren