mirror of
https://github.com/PaperMC/Paper.git
synced 2025-03-02 11:22:01 +01:00
Async chunk api/io/loading (#2308)
This commit is contained in:
parent
467ebc7cff
commit
7f4d6050fd
@ -1,61 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 May 2019 12:29:24 -0700
|
||||
Subject: [PATCH] Async Chunk placeholder
|
||||
|
||||
Until we figure out Mojang's ticket system.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 91b65fde0..afdb6956b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -0,0 +0,0 @@ import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
+import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSortedSet;
|
||||
@@ -0,0 +0,0 @@ public class CraftWorld implements World {
|
||||
return (nearest == null) ? null : new Location(this, nearest.getX(), nearest.getY(), nearest.getZ());
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private Chunk getChunkAtGen(int x, int z, boolean gen) {
|
||||
+ // copied from loadChunk()
|
||||
+ // this function is identical except we do not add a plugin ticket
|
||||
+ IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, gen || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true);
|
||||
+
|
||||
+ // If generate = false, but the chunk already exists, we will get this back.
|
||||
+ if (chunk instanceof ProtoChunkExtension) {
|
||||
+ // We then cycle through again to get the full chunk immediately, rather than after the ticket addition
|
||||
+ chunk = world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, true);
|
||||
+ }
|
||||
+
|
||||
+ if (chunk instanceof net.minecraft.server.Chunk) {
|
||||
+ return ((net.minecraft.server.Chunk)chunk).bukkitChunk;
|
||||
+ }
|
||||
+
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public CompletableFuture<Chunk> getChunkAtAsync(int x, int z, boolean gen) {
|
||||
+ // TODO placeholder
|
||||
+ if (Bukkit.isPrimaryThread()) {
|
||||
+ return CompletableFuture.completedFuture(getChunkAtGen(x, z, gen));
|
||||
+ } else {
|
||||
+ CompletableFuture<Chunk> ret = new CompletableFuture<>();
|
||||
+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
|
||||
+ ret.complete(getChunkAtGen(x, z, gen));
|
||||
+ });
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
// Spigot start
|
||||
@Override
|
||||
public int getViewDistance() {
|
||||
--
|
3823
Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch
Normal file
3823
Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,7 @@ And since minecart hoppers are used _very_ rarely near we can avoid alot of sear
|
||||
Combined, this adds up a lot.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
|
||||
index d604f96c1..67dc837f4 100644
|
||||
index d604f96c16..67dc837f43 100644
|
||||
--- a/src/main/java/net/minecraft/server/Chunk.java
|
||||
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
||||
@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess {
|
||||
@ -90,7 +90,7 @@ index d604f96c1..67dc837f4 100644
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/IEntitySelector.java b/src/main/java/net/minecraft/server/IEntitySelector.java
|
||||
index 56488b78d..56739e6ed 100644
|
||||
index 56488b78dd..56739e6ed5 100644
|
||||
--- a/src/main/java/net/minecraft/server/IEntitySelector.java
|
||||
+++ b/src/main/java/net/minecraft/server/IEntitySelector.java
|
||||
@@ -0,0 +0,0 @@ public final class IEntitySelector {
|
||||
|
@ -32,7 +32,7 @@ https://bugs.mojang.com/browse/MC-141484?focusedCommentId=528273&page=com.atlass
|
||||
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/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
index 391726d99c..8db92edc36 100644
|
||||
index d704fc79c0..09efbf7250 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
@@ -0,0 +0,0 @@ public class PaperCommand extends Command {
|
||||
|
@ -6,7 +6,7 @@ Subject: [PATCH] Configurable Keep Spawn Loaded range per world
|
||||
This lets you disable it for some worlds and lower it for others.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index d8bb13693..de11a91af 100644
|
||||
index d8bb13693d..de11a91af6 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -0,0 +0,0 @@ public class PaperWorldConfig {
|
||||
@ -21,7 +21,7 @@ index d8bb13693..de11a91af 100644
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index c70ab3caf..c58f6f50d 100644
|
||||
index c70ab3caf0..c58f6f50d3 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 IAsyncTaskHandlerReentrant<TickTas
|
||||
@ -61,7 +61,7 @@ index c70ab3caf..c58f6f50d 100644
|
||||
// CraftBukkit start
|
||||
// this.nextTick = SystemUtils.getMonotonicMillis() + 10L;
|
||||
diff --git a/src/main/java/net/minecraft/server/WorldLoadListener.java b/src/main/java/net/minecraft/server/WorldLoadListener.java
|
||||
index d6762d385..7b6f5b2da 100644
|
||||
index d6762d3853..7b6f5b2da0 100644
|
||||
--- a/src/main/java/net/minecraft/server/WorldLoadListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/WorldLoadListener.java
|
||||
@@ -0,0 +0,0 @@ public interface WorldLoadListener {
|
||||
@ -72,7 +72,7 @@ index d6762d385..7b6f5b2da 100644
|
||||
+ void setChunkRadius(int radius); // Paper - allow changing chunk radius
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java b/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
|
||||
index 3868572ae..ae77805f7 100644
|
||||
index 3868572aed..ae77805f71 100644
|
||||
--- a/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
|
||||
+++ b/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
|
||||
@@ -0,0 +0,0 @@ import org.apache.logging.log4j.Logger;
|
||||
@ -103,7 +103,7 @@ index 3868572ae..ae77805f7 100644
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkcoordintpair) {
|
||||
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
index a6d0635ec..8ac49d8b9 100644
|
||||
index a6d0635ec1..8ac49d8b91 100644
|
||||
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
@@ -0,0 +0,0 @@ public class WorldServer extends World {
|
||||
@ -196,7 +196,7 @@ index a6d0635ec..8ac49d8b9 100644
|
||||
|
||||
public LongSet getForceLoadedChunks() {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 66701f1cc..080f5abc1 100644
|
||||
index b6ca8a9e94..3948de4674 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 implements World {
|
||||
|
@ -7,7 +7,7 @@ If the Bukkit generator already has a spawn, use it immediately instead
|
||||
of spending time generating one that we won't use
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
index 451ad4f32..ad4e65e48 100644
|
||||
index 84c16e2750..4497f6a601 100644
|
||||
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
@@ -0,0 +0,0 @@ public class WorldServer extends World {
|
||||
|
@ -7,7 +7,7 @@ The problem was we were checking isExpired() on the entry, but if it
|
||||
was expired at that point, then it would be null.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
|
||||
index a183bb450d..bf37c215c3 100644
|
||||
index a183bb450d..3cb443c4ff 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerList.java
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
|
@ -8,7 +8,7 @@ This patch also adds a chunk status cache on region files (note that
|
||||
its only purpose is to cache the status on DISK)
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||||
index ca5963b11..3894b0434 100644
|
||||
index ca5963b11a..3894b04342 100644
|
||||
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkProviderServer extends IChunkProvider {
|
||||
@ -43,7 +43,7 @@ index ca5963b11..3894b0434 100644
|
||||
|
||||
@Nullable
|
||||
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
||||
index e778c2e85..73f93e494 100644
|
||||
index e778c2e857..73f93e4948 100644
|
||||
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
||||
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkRegionLoader {
|
||||
@ -65,7 +65,7 @@ index e778c2e85..73f93e494 100644
|
||||
if (nbttagcompound != null) {
|
||||
ChunkStatus chunkstatus = ChunkStatus.a(nbttagcompound.getCompound("Level").getString("Status"));
|
||||
diff --git a/src/main/java/net/minecraft/server/ChunkStatus.java b/src/main/java/net/minecraft/server/ChunkStatus.java
|
||||
index dd1822d6f..e324989b4 100644
|
||||
index dd1822d6ff..e324989b46 100644
|
||||
--- a/src/main/java/net/minecraft/server/ChunkStatus.java
|
||||
+++ b/src/main/java/net/minecraft/server/ChunkStatus.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkStatus {
|
||||
@ -95,7 +95,7 @@ index dd1822d6f..e324989b4 100644
|
||||
return (ChunkStatus) IRegistry.CHUNK_STATUS.get(MinecraftKey.a(s));
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||
index 14a176d61..98590e233 100644
|
||||
index 14a176d61d..98590e233a 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
||||
@@ -0,0 +0,0 @@ public class PlayerChunk {
|
||||
@ -119,7 +119,7 @@ index 14a176d61..98590e233 100644
|
||||
|
||||
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFutureUnchecked(ChunkStatus chunkstatus) {
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
||||
index 2be6fa0f0..bdadbd436 100644
|
||||
index 2be6fa0f07..bdadbd436e 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
||||
@ -187,7 +187,7 @@ index 2be6fa0f0..bdadbd436 100644
|
||||
boolean isOutsideOfRange(ChunkCoordIntPair chunkcoordintpair) {
|
||||
// Spigot start
|
||||
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
|
||||
index ccc3d6c7a..b487e8060 100644
|
||||
index ccc3d6c7ad..b487e80602 100644
|
||||
--- a/src/main/java/net/minecraft/server/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/server/RegionFile.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
@ -246,7 +246,7 @@ index ccc3d6c7a..b487e8060 100644
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java
|
||||
index 6f34d8aea..d2b328945 100644
|
||||
index 6f34d8aea0..d2b3289450 100644
|
||||
--- a/src/main/java/net/minecraft/server/RegionFileCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/RegionFileCache.java
|
||||
@@ -0,0 +0,0 @@ public abstract class RegionFileCache implements AutoCloseable {
|
||||
@ -279,9 +279,17 @@ index 6f34d8aea..d2b328945 100644
|
||||
printOversizedLog("ChunkTooLarge even after reduction. Trying in overzealous mode.", regionfile.file, chunkX, chunkZ);
|
||||
// Eek, major fail. We have retry logic, so reduce threshholds and fall back
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 080f5abc1..f59b2e49c 100644
|
||||
index 3948de4674..20e9fd8a79 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -0,0 +0,0 @@ import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
+import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSortedSet;
|
||||
@@ -0,0 +0,0 @@ public class CraftWorld implements World {
|
||||
|
||||
@Override
|
||||
@ -365,61 +373,5 @@ index 080f5abc1..f59b2e49c 100644
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class CraftWorld implements World {
|
||||
|
||||
// Paper start
|
||||
private Chunk getChunkAtGen(int x, int z, boolean gen) {
|
||||
- // copied from loadChunk()
|
||||
- // this function is identical except we do not add a plugin ticket
|
||||
- IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, gen || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true);
|
||||
+ // Note: Copied from loadChunk()
|
||||
+ ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(x, z);
|
||||
|
||||
- // If generate = false, but the chunk already exists, we will get this back.
|
||||
- if (chunk instanceof ProtoChunkExtension) {
|
||||
- // We then cycle through again to get the full chunk immediately, rather than after the ticket addition
|
||||
- chunk = world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, true);
|
||||
- }
|
||||
+ if (!gen) {
|
||||
+
|
||||
+ IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(x, z);
|
||||
+ if (immediate == null) {
|
||||
+ immediate = world.getChunkProvider().playerChunkMap.getUnloadingChunk(x, z);
|
||||
+ }
|
||||
+ if (immediate != null) {
|
||||
+ if (!(immediate instanceof ProtoChunkExtension) && !(immediate instanceof net.minecraft.server.Chunk)) {
|
||||
+ return null; // not full status
|
||||
+ }
|
||||
+ return world.getChunkAt(x, z).bukkitChunk; // make sure we're at ticket level 33 or lower
|
||||
+ }
|
||||
+
|
||||
+ net.minecraft.server.RegionFile file;
|
||||
+ try {
|
||||
+ file = world.getChunkProvider().playerChunkMap.getRegionFile(chunkPos, false);
|
||||
+ } catch (IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+
|
||||
+ ChunkStatus status = file.getStatusIfCached(x, z);
|
||||
+ if (!file.chunkExists(chunkPos) || (status != null && status != ChunkStatus.FULL)) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, ChunkStatus.EMPTY, true);
|
||||
+ if (!(chunk instanceof ProtoChunkExtension) && !(chunk instanceof net.minecraft.server.Chunk)) {
|
||||
+ return null;
|
||||
+ }
|
||||
|
||||
- if (chunk instanceof net.minecraft.server.Chunk) {
|
||||
- return ((net.minecraft.server.Chunk)chunk).bukkitChunk;
|
||||
+ // fall through to load
|
||||
+ // we load at empty so we don't double-load chunk data in this case
|
||||
}
|
||||
|
||||
- return null;
|
||||
+ return world.getChunkAt(x, z).bukkitChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
--
|
@ -12,7 +12,7 @@ issue in 1.8-1.12.
|
||||
Originally solved by Gnembon on MC-5694 at bugs.mojang.com
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerInteractManager.java b/src/main/java/net/minecraft/server/PlayerInteractManager.java
|
||||
index e5e9de542..c96564a59 100644
|
||||
index e5e9de542b..c96564a59b 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerInteractManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerInteractManager.java
|
||||
@@ -0,0 +0,0 @@ public class PlayerInteractManager {
|
||||
|
@ -5,7 +5,7 @@ Subject: [PATCH] Implement alternative item-despawn-rate
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 318a470ee..e7bbeef74 100644
|
||||
index 318a470eea..e7bbeef74d 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -0,0 +0,0 @@
|
||||
@ -80,7 +80,7 @@ index 318a470ee..e7bbeef74 100644
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java
|
||||
index 209169895..97e379090 100644
|
||||
index 2091698953..97e3790908 100644
|
||||
--- a/src/main/java/net/minecraft/server/EntityItem.java
|
||||
+++ b/src/main/java/net/minecraft/server/EntityItem.java
|
||||
@@ -0,0 +0,0 @@ import java.util.List;
|
||||
|
@ -357,6 +357,31 @@ index 0dda7aaf69..4e20cfba41 100644
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/RegionFileSection.java b/src/main/java/net/minecraft/server/RegionFileSection.java
|
||||
index a343a7b31d..4b3e0c0f01 100644
|
||||
--- a/src/main/java/net/minecraft/server/RegionFileSection.java
|
||||
+++ b/src/main/java/net/minecraft/server/RegionFileSection.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFileSection<R extends MinecraftSerializable> extends RegionFi
|
||||
Optional<R> optional = this.d(i);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
- return (MinecraftSerializable) optional.get();
|
||||
+ return optional.get(); // Paper - decompile fix
|
||||
} else {
|
||||
- R r0 = (MinecraftSerializable) this.f.apply(() -> {
|
||||
+ R r0 = this.f.apply(() -> { // Paper - decompile fix
|
||||
this.a(i);
|
||||
});
|
||||
|
||||
@@ -0,0 +0,0 @@ public class RegionFileSection<R extends MinecraftSerializable> extends RegionFi
|
||||
for (int l = 0; l < 16; ++l) {
|
||||
long i1 = SectionPosition.a(chunkcoordintpair, l).v();
|
||||
Optional<R> optional = optionaldynamic.get(Integer.toString(l)).get().map((dynamic2) -> {
|
||||
- return (MinecraftSerializable) this.e.apply(() -> {
|
||||
+ return this.e.apply(() -> { // Paper - decompile fix
|
||||
this.a(i1);
|
||||
}, dynamic2);
|
||||
});
|
||||
diff --git a/src/main/java/net/minecraft/server/RegistryBlockID.java b/src/main/java/net/minecraft/server/RegistryBlockID.java
|
||||
index 7f89562e90..4efcb8b595 100644
|
||||
--- a/src/main/java/net/minecraft/server/RegistryBlockID.java
|
||||
@ -455,6 +480,28 @@ index c23a366b2c..0430ca5353 100644
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/VillagePlace.java b/src/main/java/net/minecraft/server/VillagePlace.java
|
||||
index b0e6ad773e..3169590641 100644
|
||||
--- a/src/main/java/net/minecraft/server/VillagePlace.java
|
||||
+++ b/src/main/java/net/minecraft/server/VillagePlace.java
|
||||
@@ -0,0 +0,0 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
|
||||
}
|
||||
|
||||
private static boolean a(ChunkSection chunksection) {
|
||||
- Stream stream = VillagePlaceType.f();
|
||||
+ Stream<IBlockData> stream = VillagePlaceType.f(); // Paper - decompile fix
|
||||
|
||||
chunksection.getClass();
|
||||
return stream.anyMatch(chunksection::a);
|
||||
@@ -0,0 +0,0 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
|
||||
|
||||
private final Predicate<? super VillagePlaceRecord> d;
|
||||
|
||||
- private Occupancy(Predicate predicate) {
|
||||
+ private Occupancy(Predicate<? super VillagePlaceRecord> predicate) { // Paper - decompile fix
|
||||
this.d = predicate;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/VillagerTrades.java b/src/main/java/net/minecraft/server/VillagerTrades.java
|
||||
index 2fbb1f8df9..8cee460bd3 100644
|
||||
--- a/src/main/java/net/minecraft/server/VillagerTrades.java
|
||||
|
@ -38,7 +38,7 @@ index 929f5c3031..ff520d9e86 100644
|
||||
public boolean asynchronous;
|
||||
public EngineMode engineMode;
|
||||
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
index 4148325a26..7faa5dd84a 100644
|
||||
index 9fd14b573e..1e5b15c2e2 100644
|
||||
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
@@ -0,0 +0,0 @@ public class WorldServer extends World {
|
||||
|
@ -6,7 +6,7 @@ Subject: [PATCH] Preserve old flush on save flag for reliable regionfiles
|
||||
Originally this patch was in paper
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
|
||||
index e6e412b7c1..b4c191d538 100644
|
||||
index b487e80602..a8c8ace46c 100644
|
||||
--- a/src/main/java/net/minecraft/server/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/server/RegionFile.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
|
313
Spigot-Server-Patches/Reduce-sync-loads.patch
Normal file
313
Spigot-Server-Patches/Reduce-sync-loads.patch
Normal file
@ -0,0 +1,313 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 19 Jul 2019 03:29:14 -0700
|
||||
Subject: [PATCH] Reduce sync loads
|
||||
|
||||
This reduces calls to getChunkAt which would load chunks.
|
||||
|
||||
This patch also adds a tool to find calls which are doing this, however
|
||||
it must be enabled by setting the startup flag -Dpaper.debug-sync-loads=true
|
||||
|
||||
To get a debug log for sync loads, the command is /paper syncloadinfo
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
index 09efbf7250..132397b3f3 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
@@ -0,0 +0,0 @@
|
||||
package com.destroystokyo.paper;
|
||||
|
||||
+import com.destroystokyo.paper.io.SyncLoadFinder;
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
+import com.google.gson.JsonObject;
|
||||
+import com.google.gson.internal.Streams;
|
||||
+import com.google.gson.stream.JsonWriter;
|
||||
import net.minecraft.server.*;
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
+import java.io.FileOutputStream;
|
||||
+import java.io.PrintStream;
|
||||
+import java.io.StringWriter;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
@@ -0,0 +0,0 @@ public class PaperCommand extends Command {
|
||||
case "chunkinfo":
|
||||
doChunkInfo(sender, args);
|
||||
break;
|
||||
+ case "syncloadinfo":
|
||||
+ this.doSyncLoadInfo(sender, args);
|
||||
+ break;
|
||||
case "ver":
|
||||
case "version":
|
||||
Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
|
||||
@@ -0,0 +0,0 @@ public class PaperCommand extends Command {
|
||||
return true;
|
||||
}
|
||||
|
||||
+ private void doSyncLoadInfo(CommandSender sender, String[] args) {
|
||||
+ if (!SyncLoadFinder.ENABLED) {
|
||||
+ sender.sendMessage(ChatColor.RED + "This command requires the server startup flag '-Dpaper.debug-sync-loads=true' to be set.");
|
||||
+ return;
|
||||
+ }
|
||||
+ File file = new File(new File(new File("."), "debug"),
|
||||
+ "sync-load-info" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt");
|
||||
+ file.getParentFile().mkdirs();
|
||||
+ sender.sendMessage(ChatColor.GREEN + "Writing sync load info to " + file.toString());
|
||||
+
|
||||
+
|
||||
+ try {
|
||||
+ final JsonObject data = SyncLoadFinder.serialize();
|
||||
+
|
||||
+ 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, "UTF-8")
|
||||
+ ) {
|
||||
+ out.print(fileData);
|
||||
+ }
|
||||
+ sender.sendMessage(ChatColor.GREEN + "Successfully written sync load information!");
|
||||
+ } catch (Throwable thr) {
|
||||
+ sender.sendMessage(ChatColor.RED + "Failed to write sync load information");
|
||||
+ thr.printStackTrace();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
private void doChunkInfo(CommandSender sender, String[] args) {
|
||||
List<org.bukkit.World> worlds;
|
||||
if (args.length < 2 || args[1].equals("*")) {
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
new file mode 100644
|
||||
index 0000000000..59aec10329
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package com.destroystokyo.paper.io;
|
||||
+
|
||||
+import com.google.gson.JsonArray;
|
||||
+import com.google.gson.JsonObject;
|
||||
+import com.mojang.datafixers.util.Pair;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
+import net.minecraft.server.World;
|
||||
+
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.WeakHashMap;
|
||||
+
|
||||
+public class SyncLoadFinder {
|
||||
+
|
||||
+ public static final boolean ENABLED = Boolean.getBoolean("paper.debug-sync-loads");
|
||||
+
|
||||
+ private static final WeakHashMap<World, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation>> SYNC_LOADS = new WeakHashMap<>();
|
||||
+
|
||||
+ private static final class SyncLoadInformation {
|
||||
+
|
||||
+ public int times;
|
||||
+
|
||||
+ public final Long2IntOpenHashMap coordinateTimes = new Long2IntOpenHashMap();
|
||||
+ }
|
||||
+
|
||||
+ public static void logSyncLoad(final World world, final int chunkX, final int chunkZ) {
|
||||
+ if (!ENABLED) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final ThrowableWithEquals stacktrace = new ThrowableWithEquals(Thread.currentThread().getStackTrace());
|
||||
+
|
||||
+ SYNC_LOADS.compute(world, (final World keyInMap, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation> map) -> {
|
||||
+ if (map == null) {
|
||||
+ map = new Object2ObjectOpenHashMap<>();
|
||||
+ }
|
||||
+
|
||||
+ map.compute(stacktrace, (ThrowableWithEquals keyInMap0, SyncLoadInformation valueInMap) -> {
|
||||
+ if (valueInMap == null) {
|
||||
+ valueInMap = new SyncLoadInformation();
|
||||
+ }
|
||||
+
|
||||
+ ++valueInMap.times;
|
||||
+
|
||||
+ valueInMap.coordinateTimes.compute(IOUtil.getCoordinateKey(chunkX, chunkZ), (Long keyInMap1, Integer valueInMap1) -> {
|
||||
+ return valueInMap1 == null ? Integer.valueOf(1) : Integer.valueOf(valueInMap1.intValue() + 1);
|
||||
+ });
|
||||
+
|
||||
+ return valueInMap;
|
||||
+ });
|
||||
+
|
||||
+ return map;
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static JsonObject serialize() {
|
||||
+ final JsonObject ret = new JsonObject();
|
||||
+
|
||||
+ final JsonArray worldsData = new JsonArray();
|
||||
+
|
||||
+ for (final Map.Entry<World, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation>> entry : SYNC_LOADS.entrySet()) {
|
||||
+ final World world = entry.getKey();
|
||||
+
|
||||
+ final JsonObject worldData = new JsonObject();
|
||||
+
|
||||
+ worldData.addProperty("name", world.getWorld().getName());
|
||||
+
|
||||
+ final List<Pair<ThrowableWithEquals, SyncLoadInformation>> data = new ArrayList<>();
|
||||
+
|
||||
+ entry.getValue().forEach((ThrowableWithEquals stacktrace, SyncLoadInformation times) -> {
|
||||
+ data.add(new Pair<>(stacktrace, times));
|
||||
+ });
|
||||
+
|
||||
+ data.sort((Pair<ThrowableWithEquals, SyncLoadInformation> pair1, Pair<ThrowableWithEquals, SyncLoadInformation> pair2) -> {
|
||||
+ return Integer.compare(pair2.getSecond().times, pair1.getSecond().times); // reverse order
|
||||
+ });
|
||||
+
|
||||
+ final JsonArray stacktraces = new JsonArray();
|
||||
+
|
||||
+ for (Pair<ThrowableWithEquals, SyncLoadInformation> pair : data) {
|
||||
+ final JsonObject stacktrace = new JsonObject();
|
||||
+
|
||||
+ stacktrace.addProperty("times", pair.getSecond().times);
|
||||
+
|
||||
+ final JsonArray traces = new JsonArray();
|
||||
+
|
||||
+ for (StackTraceElement element : pair.getFirst().stacktrace) {
|
||||
+ traces.add(String.valueOf(element));
|
||||
+ }
|
||||
+
|
||||
+ stacktrace.add("stacktrace", traces);
|
||||
+
|
||||
+ final JsonArray coordinates = new JsonArray();
|
||||
+
|
||||
+ for (Long2IntMap.Entry coordinate : pair.getSecond().coordinateTimes.long2IntEntrySet()) {
|
||||
+ final long key = coordinate.getLongKey();
|
||||
+ final int times = coordinate.getIntValue();
|
||||
+ coordinates.add("(" + IOUtil.getCoordinateX(key) + "," + IOUtil.getCoordinateZ(key) + "): " + times);
|
||||
+ }
|
||||
+
|
||||
+ stacktrace.add("coordinates", coordinates);
|
||||
+
|
||||
+ stacktraces.add(stacktrace);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ worldData.add("stacktraces", stacktraces);
|
||||
+ worldsData.add(worldData);
|
||||
+ }
|
||||
+
|
||||
+ ret.add("worlds", worldsData);
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ static final class ThrowableWithEquals {
|
||||
+
|
||||
+ private final StackTraceElement[] stacktrace;
|
||||
+ private final int hash;
|
||||
+
|
||||
+ public ThrowableWithEquals(final StackTraceElement[] stacktrace) {
|
||||
+ this.stacktrace = stacktrace;
|
||||
+ this.hash = ThrowableWithEquals.hash(stacktrace);
|
||||
+ }
|
||||
+
|
||||
+ public static int hash(final StackTraceElement[] stacktrace) {
|
||||
+ int hash = 0;
|
||||
+
|
||||
+ for (int i = 0; i < stacktrace.length; ++i) {
|
||||
+ hash *= 31;
|
||||
+ hash += stacktrace[i].hashCode();
|
||||
+ }
|
||||
+
|
||||
+ return hash;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return this.hash;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(final Object obj) {
|
||||
+ if (obj == null || obj.getClass() != this.getClass()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ final ThrowableWithEquals other = (ThrowableWithEquals)obj;
|
||||
+ final StackTraceElement[] otherStackTrace = other.stacktrace;
|
||||
+
|
||||
+ if (this.stacktrace.length != otherStackTrace.length) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (this == obj) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < this.stacktrace.length; ++i) {
|
||||
+ if (!this.stacktrace[i].equals(otherStackTrace[i])) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||||
index 9138a256bd..9f9bebdb22 100644
|
||||
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkProviderServer extends IChunkProvider {
|
||||
this.world.asyncChunkTaskManager.raisePriority(x, z, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY);
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.world, x, z);
|
||||
// Paper end
|
||||
+ com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.world, x, z); // Paper - sync load info
|
||||
this.world.timings.chunkAwait.startTiming(); // Paper
|
||||
this.serverThreadQueue.awaitTasks(completablefuture::isDone);
|
||||
com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug
|
||||
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
||||
index b81b37445c..d3a0ed52bc 100644
|
||||
--- a/src/main/java/net/minecraft/server/World.java
|
||||
+++ b/src/main/java/net/minecraft/server/World.java
|
||||
@@ -0,0 +0,0 @@ public abstract class World implements IIBlockAccess, GeneratorAccess, AutoClose
|
||||
|
||||
for (int i1 = i; i1 <= j; ++i1) {
|
||||
for (int j1 = k; j1 <= l; ++j1) {
|
||||
- Chunk chunk = this.getChunkProvider().getChunkAt(i1, j1, false);
|
||||
+ Chunk chunk = (Chunk)this.getChunkIfLoadedImmediately(i1, j1); // Paper
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.a(entity, axisalignedbb, list, predicate);
|
||||
@@ -0,0 +0,0 @@ public abstract class World implements IIBlockAccess, GeneratorAccess, AutoClose
|
||||
|
||||
for (int i1 = i; i1 < j; ++i1) {
|
||||
for (int j1 = k; j1 < l; ++j1) {
|
||||
- Chunk chunk = this.getChunkProvider().getChunkAt(i1, j1, false);
|
||||
+ Chunk chunk = (Chunk)this.getChunkIfLoadedImmediately(i1, j1); // Paper
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.a(entitytypes, axisalignedbb, list, predicate);
|
||||
@@ -0,0 +0,0 @@ public abstract class World implements IIBlockAccess, GeneratorAccess, AutoClose
|
||||
|
||||
for (int i1 = i; i1 < j; ++i1) {
|
||||
for (int j1 = k; j1 < l; ++j1) {
|
||||
- Chunk chunk = ichunkprovider.getChunkAt(i1, j1, false);
|
||||
+ Chunk chunk = (Chunk)this.getChunkIfLoadedImmediately(i1, j1); // Paper
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.a(oclass, axisalignedbb, list, predicate);
|
||||
--
|
@ -9,7 +9,7 @@ waiting for the execution queue to get to our request; We can just query
|
||||
the chunk status and get a response now, vs having to wait
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 447b4324f..3d62debc7 100644
|
||||
index 91b65fde05..b6ca8a9e94 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 implements World {
|
||||
|
@ -147,7 +147,7 @@ index 493770bf68..2be6fa0f07 100644
|
||||
if (flag) {
|
||||
List<PlayerChunk> list = (List) this.visibleChunks.values().stream().filter(PlayerChunk::hasBeenLoaded).peek(PlayerChunk::m).collect(Collectors.toList());
|
||||
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
index 1003ea50d3..4148325a26 100644
|
||||
index 8ac49d8b91..9fd14b573e 100644
|
||||
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
@@ -0,0 +0,0 @@ public class WorldServer extends World {
|
||||
|
Loading…
Reference in New Issue
Block a user