mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-27 11:27:35 +01:00
Fix loadChunk(x, z, false)
I was not correctly checking if the status was even cached. Actually fix it this time Do not forget about the async chunk placeholder Actually fix it this time I hope No plugin tickets for getChunkAtGen(x, z, boolean) Change ChunkStatus ABI This is required for asynchronous IO. async io will require calls to getChunkStatusIfCached to return the chunk status for a chunk currently queued to save - this cannot be reasonably done with current ABI
This commit is contained in:
parent
ff085b8e8e
commit
36c4831619
@ -1,4 +1,4 @@
|
||||
From f652935fc9f95af75b49dc0e665ed32fe7eb74e0 Mon Sep 17 00:00:00 2001
|
||||
From 56ad1b929e7dcae4e58f7d68c31c749ace2e2b1e Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 15 Jun 2019 08:54:33 -0700
|
||||
Subject: [PATCH] Fix World#isChunkGenerated calls
|
||||
@ -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
|
||||
@@ -27,7 +27,7 @@ public class ChunkProviderServer extends IChunkProvider {
|
||||
@ -134,10 +134,10 @@ 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
|
||||
@@ -807,10 +807,23 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
||||
@@ -807,11 +807,56 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -156,18 +156,51 @@ 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
|
||||
@@ -31,6 +31,47 @@ public class RegionFile implements AutoCloseable {
|
||||
@@ -31,6 +31,30 @@ public class RegionFile implements AutoCloseable {
|
||||
private final int[] d = new int[1024];private int[] timestamps = d; // Paper - OBFHELPER
|
||||
private final List<Boolean> e; private List<Boolean> getFreeSectors() { return this.e; } // Paper - OBFHELPER
|
||||
|
||||
@ -193,29 +226,20 @@ 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
|
||||
@@ -299,6 +340,7 @@ public class RegionFile implements AutoCloseable {
|
||||
@@ -286,6 +310,7 @@ 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;
|
||||
}
|
||||
@@ -299,6 +324,7 @@ public class RegionFile implements AutoCloseable {
|
||||
this.writeInt(i); // Paper - Avoid 3 io write calls
|
||||
}
|
||||
|
||||
@ -223,7 +247,7 @@ index 2e14d8465..d610253b9 100644
|
||||
private int f(ChunkCoordIntPair chunkcoordintpair) {
|
||||
return chunkcoordintpair.j() + chunkcoordintpair.k() * 32;
|
||||
}
|
||||
@@ -312,6 +354,7 @@ public class RegionFile implements AutoCloseable {
|
||||
@@ -312,6 +338,7 @@ public class RegionFile implements AutoCloseable {
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
@ -265,10 +289,10 @@ 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
|
||||
@@ -393,8 +393,20 @@ public class CraftWorld implements World {
|
||||
@@ -393,8 +393,19 @@ public class CraftWorld implements World {
|
||||
|
||||
@Override
|
||||
public boolean isChunkGenerated(int x, int z) {
|
||||
@ -284,81 +308,114 @@ 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);
|
||||
}
|
||||
@@ -506,20 +518,24 @@ public class CraftWorld implements World {
|
||||
@@ -506,20 +517,45 @@ public class CraftWorld implements World {
|
||||
@Override
|
||||
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
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2249,21 +2265,20 @@ public class CraftWorld implements World {
|
||||
@@ -2249,21 +2285,40 @@ 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);
|
||||
- }
|
||||
-
|
||||
+ 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
From 258e62129db2aeb3cdabadfeaf0baf682ab9d983 Mon Sep 17 00:00:00 2001
|
||||
From af0d14664907ee01ca8462ecf282c3c46d8941ef Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 16 Jun 2019 23:30:25 -0700
|
||||
Subject: [PATCH] Fix MC-154214
|
||||
@ -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
|
||||
@@ -359,12 +359,18 @@ public abstract class ChunkMapDistance {
|
||||
|
@ -1,4 +1,4 @@
|
||||
From 3423bf44d5532a8e2d8a7b2fdf6aa278aa1702b1 Mon Sep 17 00:00:00 2001
|
||||
From ba7006117301143d6877b70bfd4f0043feb4fa5d Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 22 Jun 2019 04:20:47 -0700
|
||||
Subject: [PATCH] Use ChunkStatus cache when saving protochunks
|
||||
@ -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
|
||||
@@ -723,8 +723,10 @@ 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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
From ff5ffde5a598d484afed73de5c1e35743cb184bf Mon Sep 17 00:00:00 2001
|
||||
From 3db1a7a3ad9eac4b9e25423bad3a4281d2cdcba5 Mon Sep 17 00:00:00 2001
|
||||
From: stonar96 <minecraft.stonar96@gmail.com>
|
||||
Date: Mon, 20 Aug 2018 03:03:58 +0200
|
||||
Subject: [PATCH] Anti-Xray
|
||||
@ -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
|
||||
@@ -494,7 +494,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
||||
@ -1577,7 +1577,7 @@ index f21961d3a..f5b35b95b 100644
|
||||
}, this.executor);
|
||||
}
|
||||
|
||||
@@ -1116,7 +1116,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
||||
@@ -1148,7 +1148,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
||||
|
||||
private void a(EntityPlayer entityplayer, Packet<?>[] apacket, Chunk chunk) {
|
||||
if (apacket[0] == null) {
|
||||
|
Loading…
Reference in New Issue
Block a user