mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-29 15:49:00 +01:00
Merge pull request #2296 from Spottedleaf/fix-loadchunk-again
This commit is contained in:
commit
bf5ad877a2
4 changed files with 103 additions and 46 deletions
|
@ -1565,7 +1565,7 @@ index 761cd1355..956a47132 100644
|
|||
this.a(new PacketPlayOutMultiBlockChange(this.dirtyCount, this.dirtyBlocks, chunk), false);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
||||
index f21961d3a..f5b35b95b 100644
|
||||
index 7cb5438e4..a43927781 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 {
|
||||
|
|
|
@ -6,7 +6,7 @@ Subject: [PATCH] Fix MC-154214
|
|||
Avoid adding player tickets when they're out of range of the closest player
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
||||
index 99c7537ef..757b505ea 100644
|
||||
index 99c7537ef2..757b505eaf 100644
|
||||
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
||||
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
||||
@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance {
|
||||
|
|
|
@ -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 bff81bdb8..dab86960a 100644
|
||||
index fef44094b..539c65f85 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 {
|
||||
|
@ -134,7 +134,7 @@ index 0daf5f99e..761cd1355 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 884c8a908..e0798c1c8 100644
|
||||
index 884c8a908..e2f8b18d9 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 {
|
||||
|
@ -156,15 +156,48 @@ index 884c8a908..e0798c1c8 100644
|
|||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ this.getRegionFile(chunkcoordintpair, false).setStatus(chunkcoordintpair.x, chunkcoordintpair.z, ChunkRegionLoader.getStatus(nbttagcompound));
|
||||
+ this.updateChunkStatusOnDisk(chunkcoordintpair, nbttagcompound);
|
||||
+
|
||||
+ return nbttagcompound;
|
||||
+ // Paper end
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - chunk status cache "api"
|
||||
+ public ChunkStatus getChunkStatusOnDiskIfCached(ChunkCoordIntPair chunkPos) {
|
||||
+ RegionFile regionFile = this.getRegionFileIfLoaded(chunkPos);
|
||||
+
|
||||
+ return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z);
|
||||
+ }
|
||||
+
|
||||
+ public ChunkStatus getChunkStatusOnDisk(ChunkCoordIntPair chunkPos) throws IOException {
|
||||
+ RegionFile regionFile = this.getRegionFile(chunkPos, false);
|
||||
+
|
||||
+ if (!regionFile.chunkExists(chunkPos)) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ChunkStatus status = regionFile.getStatusIfCached(chunkPos.x, chunkPos.z);
|
||||
+
|
||||
+ if (status != null) {
|
||||
+ return status;
|
||||
+ }
|
||||
+
|
||||
+ this.readChunkData(chunkPos);
|
||||
+
|
||||
+ return regionFile.getStatusIfCached(chunkPos.x, chunkPos.z);
|
||||
+ }
|
||||
+
|
||||
+ public void updateChunkStatusOnDisk(ChunkCoordIntPair chunkPos, @Nullable NBTTagCompound compound) throws IOException {
|
||||
+ RegionFile regionFile = this.getRegionFile(chunkPos, false);
|
||||
+
|
||||
+ regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkRegionLoader.getStatus(compound));
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
// Spigot Start
|
||||
boolean isOutsideOfRange(ChunkCoordIntPair chunkcoordintpair, boolean reducedRange) {
|
||||
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
|
||||
index 2e14d8465..d610253b9 100644
|
||||
index 2e14d8465..66c8b0307 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 {
|
||||
|
@ -193,28 +226,19 @@ index 2e14d8465..d610253b9 100644
|
|||
+ final int location = this.getChunkLocation(new ChunkCoordIntPair(x, z));
|
||||
+ return this.statuses[location];
|
||||
+ }
|
||||
+
|
||||
+ public ChunkStatus getStatus(int x, int z, PlayerChunkMap playerChunkMap) throws IOException {
|
||||
+ if (this.closed) {
|
||||
+ // We've used an invalid region file.
|
||||
+ throw new java.io.EOFException("RegionFile is closed");
|
||||
+ }
|
||||
+ ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(x, z);
|
||||
+ int location = this.getChunkLocation(chunkPos);
|
||||
+ ChunkStatus cached = this.statuses[location];
|
||||
+ if (cached != null) {
|
||||
+ return cached;
|
||||
+ }
|
||||
+
|
||||
+ playerChunkMap.readChunkData(chunkPos); // This will set our status (yes it's disgusting)
|
||||
+
|
||||
+ return this.statuses[location];
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public RegionFile(File file) throws IOException {
|
||||
this.b = new RandomAccessFile(file, "rw");
|
||||
this.file = file; // Spigot // Paper - We need this earlier
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
return this.c[this.f(chunkcoordintpair)];
|
||||
}
|
||||
|
||||
+ public final boolean chunkExists(ChunkCoordIntPair chunkPos) { return this.d(chunkPos); } // Paper - OBFHELPER
|
||||
public boolean d(ChunkCoordIntPair chunkcoordintpair) {
|
||||
return this.getOffset(chunkcoordintpair) != 0;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
this.writeInt(i); // Paper - Avoid 3 io write calls
|
||||
}
|
||||
|
@ -265,7 +289,7 @@ 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 bb0f75f52..ece1a68c1 100644
|
||||
index bb0f75f52..f01e8a87e 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 {
|
||||
|
@ -284,8 +308,7 @@ index bb0f75f52..ece1a68c1 100644
|
|||
+ }
|
||||
try {
|
||||
- return world.getChunkProvider().getChunkAtIfCachedImmediately(x, z) != null || world.getChunkProvider().playerChunkMap.chunkExists(new ChunkCoordIntPair(x, z)); // Paper
|
||||
+ return world.getChunkProvider().playerChunkMap.getRegionFile(new ChunkCoordIntPair(x, z), false)
|
||||
+ .getStatus(x, z, world.getChunkProvider().playerChunkMap) == ChunkStatus.FULL;
|
||||
+ return world.getChunkProvider().playerChunkMap.getChunkStatusOnDisk(new ChunkCoordIntPair(x, z)) == ChunkStatus.FULL;
|
||||
+ // Paper end
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
|
@ -295,32 +318,50 @@ index bb0f75f52..ece1a68c1 100644
|
|||
public boolean loadChunk(int x, int z, boolean generate) {
|
||||
org.spigotmc.AsyncCatcher.catchOp( "chunk load"); // Spigot
|
||||
- IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true);
|
||||
-
|
||||
+ // Paper start - Optimize this method
|
||||
+ 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);
|
||||
- }
|
||||
+ // Paper - Optimize this method
|
||||
+ if (!generate) {
|
||||
+ net.minecraft.server.RegionFile file = world.getChunkProvider().playerChunkMap.getRegionFileIfLoaded(new ChunkCoordIntPair(x, z));
|
||||
+ if (file != null && file.getStatusIfCached(x, z) != ChunkStatus.FULL) {
|
||||
+ return false;
|
||||
+ IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(x, z);
|
||||
+ if (immediate != null) {
|
||||
+ if (!(immediate instanceof ProtoChunkExtension) && !(immediate instanceof net.minecraft.server.Chunk)) {
|
||||
+ return false; // not full status
|
||||
+ }
|
||||
+ world.getChunkProvider().addTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
|
||||
+ world.getChunkAt(x, z); // make sure we're at ticket level 32 or lower
|
||||
+ return true;
|
||||
}
|
||||
|
||||
- if (chunk instanceof net.minecraft.server.Chunk) {
|
||||
- world.getChunkProvider().addTicket(TicketType.PLUGIN, new ChunkCoordIntPair(x, z), 1, Unit.INSTANCE);
|
||||
- return true;
|
||||
+ if (!generate) {
|
||||
+ 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 false;
|
||||
+ }
|
||||
+
|
||||
+ IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, ChunkStatus.EMPTY, true);
|
||||
+ if (!(chunk instanceof ProtoChunkExtension) && !(chunk instanceof net.minecraft.server.Chunk)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ // fall through to load
|
||||
+ // we do this so we do not re-read the chunk data on disk
|
||||
}
|
||||
-
|
||||
|
||||
- return false;
|
||||
+ world.getChunkProvider().addTicket(TicketType.PLUGIN, new ChunkCoordIntPair(x, z), 1, Unit.INSTANCE);
|
||||
+ world.getChunkProvider().addTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
|
||||
+ world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, true);
|
||||
+ return true;
|
||||
+ // Paper end
|
||||
|
@ -334,31 +375,47 @@ index bb0f75f52..ece1a68c1 100644
|
|||
- // 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);
|
||||
- }
|
||||
-
|
||||
+ IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(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 32 or lower
|
||||
}
|
||||
|
||||
- if (chunk instanceof net.minecraft.server.Chunk) {
|
||||
- return ((net.minecraft.server.Chunk)chunk).bukkitChunk;
|
||||
+ // Note: Copied from loadChunk()
|
||||
+ if (!gen) {
|
||||
+ net.minecraft.server.RegionFile file = world.getChunkProvider().playerChunkMap.getRegionFileIfLoaded(new ChunkCoordIntPair(x, z));
|
||||
+ if (file != null && file.getStatusIfCached(x, z) != ChunkStatus.FULL) {
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ // fall through to load
|
||||
+ // we do this so we do not re-read the chunk data on disk
|
||||
+ // we load at empty so we don't double-load chunk data in this case
|
||||
}
|
||||
-
|
||||
|
||||
- return null;
|
||||
+ return ((net.minecraft.server.Chunk)world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, true)).bukkitChunk;
|
||||
+ return world.getChunkAt(x, z).bukkitChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,7 +7,7 @@ The cache should contain the chunk status when saving. If not it
|
|||
will load it.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
||||
index e0798c1c8..f21961d3a 100644
|
||||
index e2f8b18d9..7cb5438e4 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 {
|
||||
|
@ -17,7 +17,7 @@ index e0798c1c8..f21961d3a 100644
|
|||
- nbttagcompound = this.readChunkData(chunkcoordintpair);
|
||||
- if (nbttagcompound != null && ChunkRegionLoader.a(nbttagcompound) == ChunkStatus.Type.LEVELCHUNK) {
|
||||
+ // Paper start - Optimize save by using status cache
|
||||
+ ChunkStatus statusOnDisk = this.getRegionFile(ichunkaccess.getPos(), false).getStatus(ichunkaccess.getPos().x, ichunkaccess.getPos().z, this);
|
||||
+ ChunkStatus statusOnDisk = this.getChunkStatusOnDisk(chunkcoordintpair);
|
||||
+ if (statusOnDisk != null && statusOnDisk.getType() == ChunkStatus.Type.LEVELCHUNK) {
|
||||
+ // Paper end
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue