even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even more patches

This commit is contained in:
Jason Penilla 2021-11-24 21:13:29 -08:00
parent 28459aeafe
commit 437205bba8
14 changed files with 148 additions and 389 deletions

View file

@ -91,14 +91,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
} }
private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol enumprotocol, ConnectionProtocol enumprotocol1) { private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol packetState, ConnectionProtocol currentState) {
+ // Paper start - add flush parameter + // Paper start - add flush parameter
+ this.doSendPacket(packet, callback, enumprotocol, enumprotocol1, true); + this.doSendPacket(packet, callback, packetState, currentState, true);
+ } + }
+ private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol enumprotocol, ConnectionProtocol enumprotocol1, boolean flush) { + private void doSendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback, ConnectionProtocol packetState, ConnectionProtocol currentState, boolean flush) {
+ // Paper end - add flush parameter + // Paper end - add flush parameter
if (enumprotocol != enumprotocol1) { if (packetState != currentState) {
this.setProtocol(enumprotocol); this.setProtocol(packetState);
} }
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> { @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {

View file

@ -13,38 +13,28 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializ
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+++ b/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 { @@ -0,0 +0,0 @@ import org.apache.logging.log4j.LogManager;
private static final String SKYLIGHT_STATE_TAG = "starlight.skylight_state"; import org.apache.logging.log4j.Logger;
private static final String STARLIGHT_VERSION_TAG = "starlight.light_version";
// Paper end - replace light engine impl public class ChunkSerializer {
+ // Paper start + // Paper start
+ // TODO: Check on update + // TODO: Check on update
+ public static long getLastWorldSaveTime(CompoundTag chunkData) { + public static long getLastWorldSaveTime(CompoundTag chunkData) {
+ CompoundTag levelData = chunkData.getCompound("Level"); + return chunkData.getLong("LastUpdate");
+ return levelData.getLong("LastUpdate");
+ } + }
+ // Paper end + // Paper end
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
public static final String TAG_UPGRADE_DATA = "UpgradeData";
@@ -0,0 +0,0 @@ public class ChunkSerializer { @@ -0,0 +0,0 @@ public class ChunkSerializer {
} nbttagcompound.putInt("xPos", chunkcoordintpair.x);
// Paper end nbttagcompound.putInt("yPos", chunk.getMinSection());
BiomeSource worldchunkmanager = chunkgenerator.getBiomeSource(); nbttagcompound.putInt("zPos", chunkcoordintpair.z);
- CompoundTag nbttagcompound1 = nbt.getCompound("Level"); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate - nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading
+ CompoundTag nbttagcompound1 = nbt.getCompound("Level"); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate // Paper - diff on change + nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading // Paper - diff on change
ChunkPos chunkcoordintpair1 = new ChunkPos(nbttagcompound1.getInt("xPos"), nbttagcompound1.getInt("zPos")); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime());
nbttagcompound.putString("Status", chunk.getStatus().getName());
if (!Objects.equals(pos, chunkcoordintpair1)) { BlendingData blendingdata = chunk.getBlendingData();
@@ -0,0 +0,0 @@ public class ChunkSerializer {
nbttagcompound.put("Level", nbttagcompound1);
nbttagcompound1.putInt("xPos", chunkcoordintpair.x);
nbttagcompound1.putInt("zPos", chunkcoordintpair.z);
- nbttagcompound1.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading
+ nbttagcompound1.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading // Paper - diff on change
nbttagcompound1.putLong("InhabitedTime", chunk.getInhabitedTime());
nbttagcompound1.putString("Status", chunk.getStatus().getName());
UpgradeData chunkconverter = chunk.getUpgradeData();
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
@ -96,7 +86,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper
public final File regionFile; // Paper public final Path regionFile; // Paper
+ // Paper start - try to recover from RegionFile header corruption + // Paper start - try to recover from RegionFile header corruption
+ private static long roundToSectors(long bytes) { + private static long roundToSectors(long bytes) {
@ -140,7 +130,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position())); + InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position()));
+ +
+ return NbtIo.read((java.io.DataInput)new DataInputStream(new BufferedInputStream(input))); + return NbtIo.read(new DataInputStream(input));
+ } catch (Exception ex) { + } catch (Exception ex) {
+ return null; + return null;
+ } + }
@ -156,18 +146,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ private void backupRegionFile() { + private void backupRegionFile() {
+ File backup = new File(this.regionFile.getParent(), this.regionFile.getName() + "." + new java.util.Random().nextLong() + ".backup"); + Path backup = this.regionFile.getParent().resolve(this.regionFile.getFileName() + "." + new java.util.Random().nextLong() + ".backup");
+ this.backupRegionFile(backup); + this.backupRegionFile(backup);
+ } + }
+ +
+ private void backupRegionFile(File to) { + private void backupRegionFile(Path to) {
+ try { + try {
+ this.file.force(true); + this.file.force(true);
+ LOGGER.warn("Backing up regionfile \"" + this.regionFile.getAbsolutePath() + "\" to " + to.getAbsolutePath()); + LOGGER.warn("Backing up regionfile \"" + this.regionFile.toAbsolutePath() + "\" to " + to.toAbsolutePath());
+ java.nio.file.Files.copy(this.regionFile.toPath(), to.toPath()); + java.nio.file.Files.copy(this.regionFile, to);
+ LOGGER.warn("Backed up the regionfile to " + to.getAbsolutePath()); + LOGGER.warn("Backed up the regionfile to " + to.toAbsolutePath());
+ } catch (IOException ex) { + } catch (IOException ex) {
+ LOGGER.error("Failed to backup to " + to.getAbsolutePath(), ex); + LOGGER.error("Failed to backup to " + to.toAbsolutePath(), ex);
+ } + }
+ } + }
+ +
@ -182,11 +172,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ ChunkPos ourLowerLeftPosition = RegionFileStorage.getRegionFileCoordinates(this.regionFile); + ChunkPos ourLowerLeftPosition = RegionFileStorage.getRegionFileCoordinates(this.regionFile);
+ if (ourLowerLeftPosition == null) { + if (ourLowerLeftPosition == null) {
+ LOGGER.fatal("Unable to get chunk location of regionfile " + this.regionFile.getAbsolutePath() + ", cannot recover header"); + LOGGER.fatal("Unable to get chunk location of regionfile " + this.regionFile.toAbsolutePath() + ", cannot recover header");
+ return false; + return false;
+ } + }
+ synchronized (this) { + synchronized (this) {
+ LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile " + this.regionFile.getAbsolutePath(), new Throwable()); + LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile " + this.regionFile.toAbsolutePath(), new Throwable());
+ +
+ // try to backup file so maybe it could be sent to us for further investigation + // try to backup file so maybe it could be sent to us for further investigation
+ +
@ -210,7 +200,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(compound); + ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(compound);
+ if (!inSameRegionfile(ourLowerLeftPosition, chunkPos)) { + if (!inSameRegionfile(ourLowerLeftPosition, chunkPos)) {
+ LOGGER.error("Ignoring absolute chunk " + chunkPos + " in regionfile as it is not contained in the bounds of the regionfile '" + this.regionFile.getAbsolutePath() + "'. It should be in regionfile (" + (chunkPos.x >> 5) + "," + (chunkPos.z >> 5) + ")"); + LOGGER.error("Ignoring absolute chunk " + chunkPos + " in regionfile as it is not contained in the bounds of the regionfile '" + this.regionFile.toAbsolutePath() + "'. It should be in regionfile (" + (chunkPos.x >> 5) + "," + (chunkPos.z >> 5) + ")");
+ continue; + continue;
+ } + }
+ int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5); + int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5);
@ -222,9 +212,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ // aikar oversized? + // aikar oversized?
+ File aikarOversizedFile = this.getOversizedFile(chunkPos.x, chunkPos.z); + Path aikarOversizedFile = this.getOversizedFile(chunkPos.x, chunkPos.z);
+ boolean isAikarOversized = false; + boolean isAikarOversized = false;
+ if (aikarOversizedFile.exists()) { + if (Files.exists(aikarOversizedFile)) {
+ try { + try {
+ CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z); + CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z);
+ if (ChunkSerializer.getLastWorldSaveTime(compound) == ChunkSerializer.getLastWorldSaveTime(aikarOversizedCompound)) { + if (ChunkSerializer.getLastWorldSaveTime(compound) == ChunkSerializer.getLastWorldSaveTime(aikarOversizedCompound)) {
@ -232,7 +222,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ isAikarOversized = true; + isAikarOversized = true;
+ } + }
+ } catch (Exception ex) { + } catch (Exception ex) {
+ LOGGER.error("Failed to read aikar oversized data for absolute chunk (" + chunkPos.x + "," + chunkPos.z + ") in regionfile " + this.regionFile.getAbsolutePath() + ", oversized data for this chunk will be lost", ex); + LOGGER.error("Failed to read aikar oversized data for absolute chunk (" + chunkPos.x + "," + chunkPos.z + ") in regionfile " + this.regionFile.toAbsolutePath() + ", oversized data for this chunk will be lost", ex);
+ // fall through, if we can't read aikar oversized we can't risk corrupting chunk data + // fall through, if we can't read aikar oversized we can't risk corrupting chunk data
+ } + }
+ } + }
@ -252,7 +242,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // local data compound + // local data compound
+ +
+ java.nio.file.Path containingFolder = this.externalFileDir; + java.nio.file.Path containingFolder = this.externalFileDir;
+ File[] regionFiles = containingFolder.toFile().listFiles(); + Path[] regionFiles = Files.list(containingFolder).toArray(Path[]::new);
+ boolean[] oversized = new boolean[32 * 32]; + boolean[] oversized = new boolean[32 * 32];
+ RegionFileVersion[] oversizedCompressionTypes = new RegionFileVersion[32 * 32]; + RegionFileVersion[] oversizedCompressionTypes = new RegionFileVersion[32 * 32];
+ +
@ -263,7 +253,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ int upperZBound = lowerZBound + 32 - 1; // inclusive + int upperZBound = lowerZBound + 32 - 1; // inclusive
+ +
+ // read mojang oversized data + // read mojang oversized data
+ for (File regionFile : regionFiles) { + for (Path regionFile : regionFiles) {
+ ChunkPos oversizedCoords = getOversizedChunkPair(regionFile); + ChunkPos oversizedCoords = getOversizedChunkPair(regionFile);
+ if (oversizedCoords == null) { + if (oversizedCoords == null) {
+ continue; + continue;
@ -279,9 +269,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ byte[] chunkData; + byte[] chunkData;
+ try { + try {
+ chunkData = Files.readAllBytes(regionFile.toPath()); + chunkData = Files.readAllBytes(regionFile);
+ } catch (Exception ex) { + } catch (Exception ex) {
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.getAbsolutePath() + ", data will be lost", ex); + LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", data will be lost", ex);
+ continue; + continue;
+ } + }
+ +
@ -291,7 +281,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ RegionFileVersion compression = null; + RegionFileVersion compression = null;
+ for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) { + for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) {
+ try { + try {
+ DataInputStream in = new DataInputStream(new BufferedInputStream(compressionType.wrap(new ByteArrayInputStream(chunkData)))); // typical java + DataInputStream in = new DataInputStream(compressionType.wrap(new ByteArrayInputStream(chunkData))); // typical java
+ compound = NbtIo.read((java.io.DataInput)in); + compound = NbtIo.read((java.io.DataInput)in);
+ compression = compressionType; + compression = compressionType;
+ break; // reaches here iff readNBT does not throw + break; // reaches here iff readNBT does not throw
@ -301,12 +291,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ if (compound == null) { + if (compound == null) {
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.getAbsolutePath() + ", it's corrupt. Its data will be lost"); + LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", it's corrupt. Its data will be lost");
+ continue; + continue;
+ } + }
+ +
+ if (!ChunkSerializer.getChunkCoordinate(compound).equals(oversizedCoords)) { + if (!ChunkSerializer.getChunkCoordinate(compound).equals(oversizedCoords)) {
+ LOGGER.error("Can't use oversized chunk stored in " + regionFile.getAbsolutePath() + ", got absolute chunkpos: " + ChunkSerializer.getChunkCoordinate(compound) + ", expected " + oversizedCoords); + LOGGER.error("Can't use oversized chunk stored in " + regionFile.toAbsolutePath() + ", got absolute chunkpos: " + ChunkSerializer.getChunkCoordinate(compound) + ", expected " + oversizedCoords);
+ continue; + continue;
+ } + }
+ +
@ -340,7 +330,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ if (newSectorAllocations.tryAllocate(sectorOffset, sectorLength)) { + if (newSectorAllocations.tryAllocate(sectorOffset, sectorLength)) {
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized + calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
+ } else { + } else {
+ LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath() + ", chunk will be regenerated"); + LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath() + ", chunk will be regenerated");
+ } + }
+ } + }
+ } + }
@ -364,7 +354,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized + calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
+ } catch (IOException ex) { + } catch (IOException ex) {
+ newSectorAllocations.free(sectorOffset, sectorLength); + newSectorAllocations.free(sectorOffset, sectorLength);
+ LOGGER.error("Failed to write new oversized chunk data holder, local chunk at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath() + " will be regenerated"); + LOGGER.error("Failed to write new oversized chunk data holder, local chunk at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath() + " will be regenerated");
+ } + }
+ } + }
+ } + }
@ -386,18 +376,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ try { + try {
+ this.writeOversizedMeta(); + this.writeOversizedMeta();
+ } catch (Exception ex) { + } catch (Exception ex) {
+ LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile " + this.regionFile.getAbsolutePath(), ex); + LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile " + this.regionFile.toAbsolutePath(), ex);
+ this.getOversizedMetaFile().delete(); + Files.deleteIfExists(this.getOversizedMetaFile());
+ } + }
+ } else { + } else {
+ this.getOversizedMetaFile().delete(); + Files.deleteIfExists(this.getOversizedMetaFile());
+ } + }
+ +
+ this.usedSectors.copyFrom(newSectorAllocations); + this.usedSectors.copyFrom(newSectorAllocations);
+ +
+ // before we overwrite the old sectors, print a summary of the chunks that got changed. + // before we overwrite the old sectors, print a summary of the chunks that got changed.
+ +
+ LOGGER.info("Starting summary of changes for regionfile " + this.regionFile.getAbsolutePath()); + LOGGER.info("Starting summary of changes for regionfile " + this.regionFile.toAbsolutePath());
+ +
+ for (int chunkX = 0; chunkX < 32; ++chunkX) { + for (int chunkX = 0; chunkX < 32; ++chunkX) {
+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) { + for (int chunkZ = 0; chunkZ < 32; ++chunkZ) {
@ -414,16 +404,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ if (oldOffset == 0) { + if (oldOffset == 0) {
+ // found lost data + // found lost data
+ LOGGER.info("Found missing data for local chunk (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.getAbsolutePath()); + LOGGER.info("Found missing data for local chunk (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath());
+ } else if (newOffset == 0) { + } else if (newOffset == 0) {
+ LOGGER.warn("Data for local chunk (" + chunkX + "," + chunkZ + ") could not be recovered in regionfile " + this.regionFile.getAbsolutePath() + ", it will be regenerated"); + LOGGER.warn("Data for local chunk (" + chunkX + "," + chunkZ + ") could not be recovered in regionfile " + this.regionFile.toAbsolutePath() + ", it will be regenerated");
+ } else { + } else {
+ LOGGER.info("Local chunk (" + chunkX + "," + chunkZ + ") changed to point to newer data or correct chunk in regionfile " + this.regionFile.getAbsolutePath()); + LOGGER.info("Local chunk (" + chunkX + "," + chunkZ + ") changed to point to newer data or correct chunk in regionfile " + this.regionFile.toAbsolutePath());
+ } + }
+ } + }
+ } + }
+ +
+ LOGGER.info("End of change summary for regionfile " + this.regionFile.getAbsolutePath()); + LOGGER.info("End of change summary for regionfile " + this.regionFile.toAbsolutePath());
+ +
+ // simply destroy the timestamp header, it's not used + // simply destroy the timestamp header, it's not used
+ +
@ -435,9 +425,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ try { + try {
+ this.flush(); + this.flush();
+ this.file.force(true); // try to ensure it goes through... + this.file.force(true); // try to ensure it goes through...
+ LOGGER.info("Successfully wrote new header to disk for regionfile " + this.regionFile.getAbsolutePath()); + LOGGER.info("Successfully wrote new header to disk for regionfile " + this.regionFile.toAbsolutePath());
+ } catch (IOException ex) { + } catch (IOException ex) {
+ LOGGER.fatal("Failed to write new header to disk for regionfile " + this.regionFile.getAbsolutePath(), ex); + LOGGER.fatal("Failed to write new header to disk for regionfile " + this.regionFile.toAbsolutePath(), ex);
+ } + }
+ } + }
+ +
@ -451,12 +441,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private final ChunkStatus[] statuses = new ChunkStatus[32 * 32]; private final ChunkStatus[] statuses = new ChunkStatus[32 * 32];
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
public RegionFile(File file, File directory, boolean dsync) throws IOException { public RegionFile(Path file, Path directory, boolean dsync) throws IOException {
this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync); this(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync);
} }
+ // Paper start - add can recalc flag + // Paper start - add can recalc flag
+ public RegionFile(File file, File directory, boolean dsync, boolean canRecalcHeader) throws IOException { + public RegionFile(Path file, Path directory, boolean dsync, boolean canRecalcHeader) throws IOException {
+ this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader); + this(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader);
+ } + }
+ // Paper end - add can recalc flag + // Paper end - add can recalc flag
@ -468,7 +458,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.canRecalcHeader = canRecalcHeader; + this.canRecalcHeader = canRecalcHeader;
+ // Paper end - add can recalc flag + // Paper end - add can recalc flag
this.header = ByteBuffer.allocateDirect(8192); this.header = ByteBuffer.allocateDirect(8192);
this.regionFile = file.toFile(); // Paper this.regionFile = file; // Paper
initOversizedState(); // Paper initOversizedState(); // Paper
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
RegionFile.LOGGER.warn("Region file {} has truncated header: {}", file, i); RegionFile.LOGGER.warn("Region file {} has truncated header: {}", file, i);
@ -516,12 +506,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper start - recalculate header on header corruption + // Paper start - recalculate header on header corruption
+ if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) { + if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) {
+ if (canRecalcHeader) { + if (canRecalcHeader) {
+ LOGGER.error("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() + "! Recalculating header..."); + LOGGER.error("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() + "! Recalculating header...");
+ needsHeaderRecalc = true; + needsHeaderRecalc = true;
+ break; + break;
+ } else { + } else {
+ // location = chunkX | (chunkZ << 5); + // location = chunkX | (chunkZ << 5);
+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() + + LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() +
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); + "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
+ if (!hasBackedUp) { + if (!hasBackedUp) {
+ hasBackedUp = true; + hasBackedUp = true;
@ -534,11 +524,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength); + boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength);
+ if (failedToAllocate) { + if (failedToAllocate) {
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.regionFile.getAbsolutePath()); + LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.regionFile.toAbsolutePath());
} }
+ if (failedToAllocate & !canRecalcHeader) { + if (failedToAllocate & !canRecalcHeader) {
+ // location = chunkX | (chunkZ << 5); + // location = chunkX | (chunkZ << 5);
+ LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.getAbsolutePath() + + LOGGER.fatal("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() +
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); + "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
+ if (!hasBackedUp) { + if (!hasBackedUp) {
+ hasBackedUp = true; + hasBackedUp = true;
@ -555,7 +545,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper start - recalculate header on header corruption + // Paper start - recalculate header on header corruption
+ // we move the recalc here so comparison to old header is correct when logging to console + // we move the recalc here so comparison to old header is correct when logging to console
+ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues + if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues
+ LOGGER.error("Recalculating regionfile " + this.regionFile.getAbsolutePath() + ", header gave erroneous offsets & locations"); + LOGGER.error("Recalculating regionfile " + this.regionFile.toAbsolutePath() + ", header gave erroneous offsets & locations");
+ this.recalculateHeader(); + this.recalculateHeader();
+ } + }
+ // Paper end + // Paper end
@ -572,8 +562,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
} }
+ // Paper start + // Paper start
+ private static ChunkPos getOversizedChunkPair(File file) { + private static ChunkPos getOversizedChunkPair(Path file) {
+ String fileName = file.getName(); + String fileName = file.getFileName().toString();
+ +
+ if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) { + if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) {
+ return null; + return null;
@ -692,30 +682,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/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 { @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
private final File folder; private final Path folder;
private final boolean sync; private final boolean sync;
+ private final boolean isChunkData; // Paper + private final boolean isChunkData; // Paper
+ +
RegionFileStorage(File directory, boolean dsync) { RegionFileStorage(Path directory, boolean dsync) {
+ // Paper start - add isChunkData param + // Paper start - add isChunkData param
+ this(directory, dsync, false); + this(directory, dsync, false);
+ } + }
+ RegionFileStorage(File directory, boolean dsync, boolean isChunkData) { + RegionFileStorage(Path directory, boolean dsync, boolean isChunkData) {
+ this.isChunkData = isChunkData; + this.isChunkData = isChunkData;
+ // Paper end - add isChunkData param + // Paper end - add isChunkData param
this.folder = directory; this.folder = directory;
this.sync = dsync; this.sync = dsync;
} }
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
Files.createDirectories(this.folder);
File file = this.folder; Path path = this.folder;
int j = chunkcoordintpair.getRegionX(); int j = chunkcoordintpair.getRegionX();
- File file1 = new File(file, "r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); - Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
+ File file1 = new File(file, "r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change + Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change
if (existingOnly && !file1.exists()) return null; // CraftBukkit if (existingOnly && !Files.exists(path1)) return null; // CraftBukkit
- RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync); - RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
+ RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header + RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header
this.regionCache.putAndMoveToFirst(i, regionfile1); this.regionCache.putAndMoveToFirst(i, regionfile1);
// Paper start // Paper start
@ -741,12 +731,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ if (this.isChunkData) { + if (this.isChunkData) {
+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound); + ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound);
+ if (!chunkPos.equals(pos)) { + if (!chunkPos.equals(pos)) {
+ MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos.toString() + " but got chunk data for " + chunkPos.toString() + " instead! Attempting regionfile recalculation for regionfile " + regionfile.regionFile.getAbsolutePath()); + net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + chunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionfile.regionFile.toAbsolutePath());
+ if (regionfile.recalculateHeader()) { + if (regionfile.recalculateHeader()) {
+ regionfile.fileLock.lock(); // otherwise we will unlock twice and only lock once. + regionfile.fileLock.lock(); // otherwise we will unlock twice and only lock once.
+ return this.read(pos, regionfile); + return this.read(pos, regionfile);
+ } + }
+ MinecraftServer.LOGGER.fatal("Can't recalculate regionfile header, regenerating chunk " + pos.toString() + " for " + regionfile.regionFile.getAbsolutePath()); + net.minecraft.server.MinecraftServer.LOGGER.fatal("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + regionfile.regionFile.toAbsolutePath());
+ return null; + return null;
+ } + }
+ } + }
@ -758,12 +748,12 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVer
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
@@ -0,0 +0,0 @@ import java.util.zip.InflaterInputStream; @@ -0,0 +0,0 @@ import javax.annotation.Nullable;
import javax.annotation.Nullable; import net.minecraft.util.FastBufferedInputStream;
public class RegionFileVersion { public class RegionFileVersion {
- private static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>(); - private static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>();
+ public static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>(); // Paper - public + public static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>(); // Paper - public
public static final RegionFileVersion VERSION_GZIP = register(new RegionFileVersion(1, GZIPInputStream::new, GZIPOutputStream::new)); public static final RegionFileVersion VERSION_GZIP = register(new RegionFileVersion(1, (inputStream) -> {
public static final RegionFileVersion VERSION_DEFLATE = register(new RegionFileVersion(2, InflaterInputStream::new, DeflaterOutputStream::new)); return new FastBufferedInputStream(new GZIPInputStream(inputStream));
public static final RegionFileVersion VERSION_NONE = register(new RegionFileVersion(3, (inputStream) -> { }, (outputStream) -> {

View file

@ -55,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) { public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
super(new File(session.getDimensionPath(world.dimension()), "region"), dataFixer, dsync); super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
- this.visibleChunkMap = this.updatingChunkMap.clone(); - this.visibleChunkMap = this.updatingChunkMap.clone();
+ // Paper - don't copy + // Paper - don't copy
this.pendingUnloads = new Long2ObjectLinkedOpenHashMap(); this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
@ -100,14 +100,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
do { do {
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
//this.flushWorker(); // Paper - nuke IOWorker
this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour
// this.i(); // Paper - nuke IOWorker
} else { } else {
- this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).forEach((playerchunk) -> { - this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded);
+ this.updatingChunks.getVisibleValuesCopy().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).forEach((playerchunk) -> { // Paper + this.updatingChunks.getVisibleValuesCopy().forEach(this::saveChunkIfNeeded); // Paper
ChunkAccess ichunkaccess = (ChunkAccess) playerchunk.getChunkToSave().getNow(null); // CraftBukkit - decompile error }
if (ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk) { }
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
while (longiterator.hasNext()) { // Spigot while (longiterator.hasNext()) { // Spigot
long j = longiterator.nextLong(); long j = longiterator.nextLong();
@ -117,6 +117,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
if (playerchunk != null) { if (playerchunk != null) {
this.pendingUnloads.put(j, playerchunk); this.pendingUnloads.put(j, playerchunk);
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
int l = 0;
- ObjectIterator objectiterator = this.visibleChunkMap.values().iterator();
+ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper
while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) {
if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) {
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
if (!this.modified) { if (!this.modified) {
return false; return false;
@ -132,6 +141,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
return true; return true;
} }
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.viewDistance = j;
this.distanceManager.updatePlayerTickets(this.viewDistance);
- ObjectIterator objectiterator = this.updatingChunkMap.values().iterator();
+ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper
while (objectiterator.hasNext()) {
ChunkHolder playerchunk = (ChunkHolder) objectiterator.next();
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
} }
public int size() { public int size() {
@ -139,7 +157,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return this.updatingChunks.getVisibleMap().size(); // Paper - Don't copy + return this.updatingChunks.getVisibleMap().size(); // Paper - Don't copy
} }
protected DistanceManager getDistanceManager() { public DistanceManager getDistanceManager() {
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
} }
@ -149,7 +167,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
} }
void dumpChunks(Writer writer) throws IOException { void dumpChunks(Writer writer) throws IOException {
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").build(writer); CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer);
TickingTracker tickingtracker = this.distanceManager.tickingTracker();
- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator(); - ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator();
+ ObjectBidirectionalIterator objectbidirectionaliterator = this.updatingChunks.getVisibleMap().clone().long2ObjectEntrySet().fastIterator(); // Paper + ObjectBidirectionalIterator objectbidirectionaliterator = this.updatingChunks.getVisibleMap().clone().long2ObjectEntrySet().fastIterator(); // Paper

View file

@ -18,18 +18,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap(); private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
private MinecraftTimings() {} private MinecraftTimings() {}
diff --git a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
+++ b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
@@ -0,0 +0,0 @@ public final class PaperTickList<T> extends ServerTickList<T> { // extend to avo
toTick.tickState = STATE_SCHEDULED;
this.addToNotTickingReady(toTick);
}
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick
} catch (final Throwable thr) {
// start copy from TickListServer // TODO check on update
CrashReport crashreport = CrashReport.forThrowable(thr, "Exception while ticking");
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java --- a/src/main/java/net/minecraft/server/MinecraftServer.java
@ -119,33 +107,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
return true; return true;
} else { } else {
if (this.haveTime()) { if (this.haveTime()) {
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 {
Collections.shuffle(shuffled);
iterator = shuffled.iterator();
}
+ int chunksTicked = 0; // Paper
try { while (iterator.hasNext()) {
LevelChunk chunk = iterator.next();
ChunkHolder playerchunk = chunk.playerChunk;
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
this.level.tickChunk(chunk, k);
// this.level.timings.doTickTiles.stopTiming(); // Spigot // Paper
}
+ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper
}
} // Paper start - optimise chunk tick iteration
} finally {
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java 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 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/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 { @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
final Int2ObjectMap<EnderDragonPart> dragonParts;
private final StructureFeatureManager structureFeatureManager; private final StructureFeatureManager structureFeatureManager;
private final StructureCheck structureCheck;
private final boolean tickTime; private final boolean tickTime;
- -
+ // Paper start - execute chunk tasks mid tick + // Paper start - execute chunk tasks mid tick

View file

@ -831,8 +831,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- private final net.minecraft.server.level.ServerLevel world; // Paper - private final net.minecraft.server.level.ServerLevel world; // Paper
+ public final net.minecraft.server.level.ServerLevel world; // Paper // Paper public + public final net.minecraft.server.level.ServerLevel world; // Paper // Paper public
public PoiManager(File directory, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) { public PoiManager(Path path, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) {
super(directory, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world); super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world);
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> { @@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection> {
} }
@ -854,12 +854,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - re-route to faster logic + // Paper end - re-route to faster logic
} }
public Optional<BlockPos> findClosest(Predicate<PoiType> predicate, Predicate<BlockPos> predicate2, BlockPos blockPos, int i, PoiManager.Occupancy occupancy) { public Optional<BlockPos> findClosest(Predicate<PoiType> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus) {
- return this.getInRange(predicate, blockPos, i, occupancy).map(PoiRecord::getPos).filter(predicate2).min(Comparator.comparingDouble((blockPos2) -> { - return this.getInRange(typePredicate, pos, radius, occupationStatus).map(PoiRecord::getPos).filter(posPredicate).min(Comparator.comparingDouble((blockPos2) -> {
- return blockPos2.distSqr(blockPos); - return blockPos2.distSqr(pos);
- })); - }));
+ // Paper start - re-route to faster logic + // Paper start - re-route to faster logic
+ BlockPos ret = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, predicate, predicate2, blockPos, i, i*i, occupancy, false); + BlockPos ret = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, radius, radius * radius, occupationStatus, false);
+ return Optional.ofNullable(ret); + return Optional.ofNullable(ret);
+ // Paper end - re-route to faster logic + // Paper end - re-route to faster logic
} }
@ -886,8 +886,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public Optional<BlockPos> getRandom(Predicate<PoiType> typePredicate, Predicate<BlockPos> positionPredicate, PoiManager.Occupancy occupationStatus, BlockPos pos, int radius, Random random) { public Optional<BlockPos> getRandom(Predicate<PoiType> typePredicate, Predicate<BlockPos> positionPredicate, PoiManager.Occupancy occupationStatus, BlockPos pos, int radius, Random random) {
- List<PoiRecord> list = this.getInRange(typePredicate, pos, radius, occupationStatus).collect(Collectors.toList()); - List<PoiRecord> list = this.getInRange(typePredicate, pos, radius, occupationStatus).collect(Collectors.toList());
- Collections.shuffle(list, random); - Collections.shuffle(list, random);
- return list.stream().filter((poiRecord) -> { - return list.stream().filter((poi) -> {
- return positionPredicate.test(poiRecord.getPos()); - return positionPredicate.test(poi.getPos());
- }).findFirst().map(PoiRecord::getPos); - }).findFirst().map(PoiRecord::getPos);
+ // Paper start - re-route to faster logic + // Paper start - re-route to faster logic
+ List<PoiRecord> list = new java.util.ArrayList<>(); + List<PoiRecord> list = new java.util.ArrayList<>();
@ -949,7 +949,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- villageplace.ensureLoadedAndValid(this.level, blockposition, i); - villageplace.ensureLoadedAndValid(this.level, blockposition, i);
- Optional<PoiRecord> optional = villageplace.getInSquare((villageplacetype) -> { - Optional<PoiRecord> optional = villageplace.getInSquare((villageplacetype) -> {
- return villageplacetype == PoiType.NETHER_PORTAL; - return villageplacetype == PoiType.NETHER_PORTAL;
- }, blockposition, i, PoiManager.Occupancy.ANY).sorted(Comparator.comparingDouble((PoiRecord villageplacerecord) -> { // CraftBukkit - decompile error - }, blockposition, i, PoiManager.Occupancy.ANY).filter((villageplacerecord) -> {
- return worldborder.isWithinBounds(villageplacerecord.getPos());
- }).sorted(Comparator.comparingDouble((PoiRecord villageplacerecord) -> { // CraftBukkit - decompile error
- return villageplacerecord.getPos().distSqr(blockposition); - return villageplacerecord.getPos().distSqr(blockposition);
- }).thenComparingInt((villageplacerecord) -> { - }).thenComparingInt((villageplacerecord) -> {
- return villageplacerecord.getPos().getY(); - return villageplacerecord.getPos().getY();
@ -970,6 +972,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // why would we generate the chunk? + // why would we generate the chunk?
+ return false; + return false;
+ } + }
+ if (!worldborder.isWithinBounds(pos)) {
+ return false;
+ }
+ return lowest.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS); + return lowest.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
+ }, + },
+ blockposition, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records + blockposition, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records

View file

@ -919,21 +919,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+++ b/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 { @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
DataFixer datafixer = minecraftserver.getFixerUpper(); DataFixer datafixer = minecraftserver.getFixerUpper();
EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, new File(convertable_conversionsession.getDimensionPath(resourcekey), "entities"), datafixer, flag2, minecraftserver); EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver);
- this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage); - this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage);
+ this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Paper + this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Paper
StructureManager definedstructuremanager = minecraftserver.getStructureManager(); StructureManager definedstructuremanager = minecraftserver.getStructureManager();
int j = this.spigotConfig.viewDistance; // Spigot int j = this.spigotConfig.viewDistance; // Spigot
PersistentEntitySectionManager persistententitysectionmanager = this.entityManager; int k = this.spigotConfig.simulationDistance; // Spigot
diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java --- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java
+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java +++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
@@ -0,0 +0,0 @@ public class WorldGenRegion implements WorldGenLevel { @@ -0,0 +0,0 @@ public class WorldGenRegion implements WorldGenLevel {
@Nullable public long nextSubTickCount() {
private Supplier<String> currentlyGenerating; return this.subTickCount.getAndIncrement();
}
+
+ // Paper start + // Paper start
+ // No-op, this class doesn't provide entity access + // No-op, this class doesn't provide entity access
+ @Override + @Override
@ -950,15 +951,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ @Override + @Override
+ public <T> void getEntitiesByClass(Class<? extends T> clazz, Entity except, AABB box, List<? super T> into, Predicate<? super T> predicate) {} + public <T> void getEntitiesByClass(Class<? extends T> clazz, Entity except, AABB box, List<? super T> into, Predicate<? super T> predicate) {}
+ // Paper end + // Paper end
+ }
public WorldGenRegion(ServerLevel world, List<ChunkAccess> list, ChunkStatus chunkstatus, int i) {
this.generatingStatus = chunkstatus;
this.writeRadiusCutoff = i;
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java --- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/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, n @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
} }
// Paper end - make end portalling safe // Paper end - make end portalling safe
@ -1015,7 +1013,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public Entity(EntityType<?> type, Level world) { public Entity(EntityType<?> type, Level world) {
this.id = Entity.ENTITY_COUNTER.incrementAndGet(); this.id = Entity.ENTITY_COUNTER.incrementAndGet();
this.passengers = ImmutableList.of(); this.passengers = ImmutableList.of();
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
return InteractionResult.PASS; return InteractionResult.PASS;
} }
@ -1052,42 +1050,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
List<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate); List<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate);
<T extends Entity> List<T> getEntities(EntityTypeTest<Entity, T> filter, AABB box, Predicate<? super T> predicate); <T extends Entity> List<T> getEntities(EntityTypeTest<Entity, T> filter, AABB box, Predicate<? super T> predicate);
@@ -0,0 +0,0 @@ public interface EntityGetter {
return Stream.empty();
} else {
AABB aABB = box.inflate(1.0E-7D);
- return this.getEntities(entity, aABB, predicate.and((entityx) -> {
- if (entityx.getBoundingBox().intersects(aABB)) {
+ Predicate<Entity> hardCollides = (entityx) -> { // Paper - optimise entity hard collisions
+ if (true || entityx.getBoundingBox().intersects(aABB)) { // Paper - always true
if (entity == null) {
if (entityx.canBeCollidedWith()) {
return true;
@@ -0,0 +0,0 @@ public interface EntityGetter {
}
return false;
- })).stream().map(Entity::getBoundingBox).map(Shapes::create);
+ }; // Paper start - optimise entity hard collisions
+ predicate = predicate == null ? hardCollides : hardCollides.and(predicate);
+ return (entity != null && entity.hardCollides() ? this.getEntities(entity, aABB, predicate) : this.getHardCollidingEntities(entity, aABB, predicate))
+ .stream().map(Entity::getBoundingBox).map(Shapes::create);
+ // Paper end - optimise entity hard collisions
}
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java 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 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/Level.java --- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/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 { @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return this.typeKey;
} public abstract ResourceKey<LevelStem> getTypeKey();
+ // Paper start + // Paper start
+ protected final io.papermc.paper.world.EntitySliceManager entitySliceManager; + protected final io.papermc.paper.world.EntitySliceManager entitySliceManager;
+ +
+ // Paper start - optimise CraftChunk#getEntities
+ public org.bukkit.entity.Entity[] getChunkEntities(int chunkX, int chunkZ) { + public org.bukkit.entity.Entity[] getChunkEntities(int chunkX, int chunkZ) {
+ io.papermc.paper.world.ChunkEntitySlices slices = this.entitySliceManager.getChunk(chunkX, chunkZ); + io.papermc.paper.world.ChunkEntitySlices slices = this.entitySliceManager.getChunk(chunkX, chunkZ);
+ if (slices == null) { + if (slices == null) {
@ -1095,7 +1068,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ return slices.getChunkEntities(); + return slices.getChunkEntities();
+ } + }
+ // Paper end - optimise CraftChunk#getEntities
+ +
+ @Override + @Override
+ public List<Entity> getHardCollidingEntities(Entity except, AABB box, Predicate<? super Entity> predicate) { + public List<Entity> getHardCollidingEntities(Entity except, AABB box, Predicate<? super Entity> predicate) {
@ -1128,13 +1100,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ // Paper end + // Paper end
+ +
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, final DimensionType dimensionmanager, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, final DimensionType dimensionmanager, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) {
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.chunkPacketBlockController = this.paperConfig.antiXray ? this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper
new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
: com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
+ this.entitySliceManager = new io.papermc.paper.world.EntitySliceManager((ServerLevel)this); // Paper + this.entitySliceManager = new io.papermc.paper.world.EntitySliceManager((ServerLevel)this); // Paper
} }
@ -1177,12 +1149,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
- } - }
- -
- if (entity instanceof EnderDragon) { - if (entity instanceof EnderDragon) {
- EnderDragonPart[] aentitycomplexpart = ((EnderDragon) entity).getSubEntities(); - EnderDragon entityenderdragon = (EnderDragon) entity;
- EnderDragonPart[] aentitycomplexpart = entityenderdragon.getSubEntities();
- int i = aentitycomplexpart.length; - int i = aentitycomplexpart.length;
- -
- for (int j = 0; j < i; ++j) { - for (int j = 0; j < i; ++j) {
- EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; - EnderDragonPart entitycomplexpart = aentitycomplexpart[j];
- T t0 = filter.tryCast(entitycomplexpart); - T t0 = filter.tryCast(entitycomplexpart); // CraftBukkit - decompile error
- -
- if (t0 != null && predicate.test(t0)) { - if (t0 != null && predicate.test(t0)) {
- list.add(t0); - list.add(t0);
@ -1228,7 +1201,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A @@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
EntitySection<T> entitysection = this.sectionStorage.getOrCreateSection(i); EntitySection<T> entitysection = this.sectionStorage.getOrCreateSection(i);
entitysection.add(entity); // CraftBukkit - decompile error entitysection.add(entity);
+ this.entitySliceManager.addEntity((Entity)entity); // Paper + this.entitySliceManager.addEntity((Entity)entity); // Paper
entity.setLevelCallback(new PersistentEntitySectionManager.Callback(entity, i, entitysection)); entity.setLevelCallback(new PersistentEntitySectionManager.Callback(entity, i, entitysection));
if (!existing) { if (!existing) {
@ -1264,7 +1237,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ public class CraftChunk implements Chunk { @@ -0,0 +0,0 @@ public class CraftChunk implements Chunk {
long pair = ChunkPos.asLong(x, z); long pair = ChunkPos.asLong(x, z);
if (entityManager.areEntitiesLoaded(pair)) { // PAIL rename isEntitiesLoaded if (entityManager.areEntitiesLoaded(pair)) {
- return entityManager.getEntities(new ChunkPos(this.x, this.z)).stream() - return entityManager.getEntities(new ChunkPos(this.x, this.z)).stream()
- .map(net.minecraft.world.entity.Entity::getBukkitEntity) - .map(net.minecraft.world.entity.Entity::getBukkitEntity)
- .filter(Objects::nonNull).toArray(Entity[]::new); - .filter(Objects::nonNull).toArray(Entity[]::new);
@ -1288,8 +1261,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java --- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
@@ -0,0 +0,0 @@ public class DummyGeneratorAccess implements WorldGenLevel { @@ -0,0 +0,0 @@ public class DummyGeneratorAccess implements WorldGenLevel {
public Stream<? extends StructureStart<?>> startsForFeature(SectionPos pos, StructureFeature<?> feature) { public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth) {
throw new UnsupportedOperationException("Not supported yet."); return false; // SPIGOT-6515
} }
+ +
+ // Paper start + // Paper start

View file

@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 11 Apr 2021 02:58:48 -0700
Subject: [PATCH] Don't read neighbour chunk data off disk when converting
chunks
Lighting is purged on update anyways, so let's not add more
into the conversion process
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
// CraftBukkit start
private boolean check(ServerChunkCache cps, int x, int z) throws IOException {
+ if (true) return true; // Paper - this isn't even needed anymore, light is purged updating to 1.14+, why are we holding up the conversion process reading chunk data off disk - return true, we need to set light populated to true so the converter recognizes the chunk as being "full"
ChunkPos pos = new ChunkPos(x, z);
if (cps != null) {
//com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); // Paper - this function is now MT-Safe

View file

@ -1,178 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Sun, 22 Aug 2021 23:03:33 -0700
Subject: [PATCH] Fix and optimize legacy world conversion
CraftBukkit breaks legacy world conversion in three ways:
- Writes userdata to the path of the userdata folder rather than to
the correct file inside the aforementioned folder. This causes the
userdata folder to fail to be created as a file already exists at
its path.
- Makes changes to how multiworld works, without modifying
McRegionUpgrader to be aware of these changes.
- Calls methods on Bukkit before the server is initialized.
This patch fixes all of these issues, and also threads the
McRegionUpgrader to improve performance.
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
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
@@ -0,0 +0,0 @@ public class OldUsersConverter {
}
private void movePlayerFile(File playerDataFolder, String fileName, String uuid) {
- File file5 = new File(file, fileName + ".dat");
+ File file5 = new File(file, fileName + ".dat"); // Paper - diff on change
File file6 = new File(playerDataFolder, uuid + ".dat");
// CraftBukkit start - Use old file name to seed lastKnownName
CompoundTag root = null;
try {
- root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
+ root = NbtIo.readCompressed(new java.io.FileInputStream(file5)); // Paper - diff on change
} catch (Exception exception) {
exception.printStackTrace();
ServerInternalException.reportInternalException(exception); // Paper
@@ -0,0 +0,0 @@ public class OldUsersConverter {
data.putString("lastKnownName", fileName);
try {
- NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
+ NbtIo.writeCompressed(root, new java.io.FileOutputStream(file5)); // Paper - write to correct path (diff on change)
} catch (Exception exception) {
exception.printStackTrace();
ServerInternalException.reportInternalException(exception); // Paper
diff --git a/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java b/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
+++ b/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
@@ -0,0 +0,0 @@ public class LevelStorageSource {
});
}
+ // Paper start - copied from vanilla before below CB diff
+ public File getDimensionPathForLegacyConversion(ResourceKey<Level> key) {
+ return DimensionType.getStorageFolder(key, this.levelPath.toFile());
+ }
+ // Paper end
+
public File getDimensionPath(ResourceKey<Level> key) {
return LevelStorageSource.getFolder(this.levelPath.toFile(), this.dimensionType); // CraftBukkit
}
diff --git a/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java b/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
+++ b/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
@@ -0,0 +0,0 @@ public class McRegionUpgrader {
private static final String MCREGION_EXTENSION = ".mcr";
static boolean convertLevel(LevelStorageSource.LevelStorageAccess storageSession, ProgressListener progressListener) {
+ // Paper start
+ progressListener = new ProgressListener() {
+ @Override
+ public void progressStartNoAbort(net.minecraft.network.chat.Component title) {}
+ @Override
+ public void progressStart(net.minecraft.network.chat.Component title) {}
+ @Override
+ public void progressStage(net.minecraft.network.chat.Component task) {}
+ @Override
+ public void progressStagePercentage(int percentage) {}
+ @Override
+ public void stop() {}
+ };
+ // Paper end
progressListener.progressStagePercentage(0);
List<File> list = Lists.newArrayList();
List<File> list2 = Lists.newArrayList();
List<File> list3 = Lists.newArrayList();
- File file = storageSession.getDimensionPath(Level.OVERWORLD);
- File file2 = storageSession.getDimensionPath(Level.NETHER);
- File file3 = storageSession.getDimensionPath(Level.END);
+ // Paper start
+ File file = storageSession.getDimensionPathForLegacyConversion(Level.OVERWORLD);
+ File file2 = storageSession.getDimensionPathForLegacyConversion(Level.NETHER);
+ File file3 = storageSession.getDimensionPathForLegacyConversion(Level.END);
+ // Paper end
LOGGER.info("Scanning folders...");
addRegionFiles(file, list);
if (file2.exists()) {
@@ -0,0 +0,0 @@ public class McRegionUpgrader {
}
private static void convertRegions(RegistryAccess.RegistryHolder registryManager, File directory, Iterable<File> files, BiomeSource biomeSource, int i, int j, ProgressListener progressListener) {
- for(File file : files) {
- convertRegion(registryManager, directory, file, biomeSource, i, j, progressListener);
- ++i;
- int k = (int)Math.round(100.0D * (double)i / (double)j);
- progressListener.progressStagePercentage(k);
+ // Paper start - thread this because it's dead simple
+ convertRegionsThreaded(registryManager, directory, files, biomeSource, i, j, progressListener);
+ }
+
+ private static void convertRegionsThreaded(RegistryAccess.RegistryHolder registryManager, File directory, Iterable<File> files, BiomeSource biomeSource, int progress, int total, ProgressListener progressListener) {
+ if (!files.iterator().hasNext()) {
+ return;
}
+ final int threads = Runtime.getRuntime().availableProcessors() / 2;
+ final java.util.concurrent.ExecutorService threadPool = java.util.concurrent.Executors.newFixedThreadPool(Math.max(1, threads), new java.util.concurrent.ThreadFactory() {
+ private final java.util.concurrent.atomic.AtomicInteger threadCounter = new java.util.concurrent.atomic.AtomicInteger();
+
+ @Override
+ public Thread newThread(final Runnable run) {
+ final Thread ret = new Thread(run);
+
+ ret.setName("World upgrader thread for directory " + directory + " #" + this.threadCounter.getAndIncrement());
+ ret.setUncaughtExceptionHandler((thread, throwable) -> {
+ LOGGER.fatal("Error upgrading world", throwable);
+ });
+
+ return ret;
+ }
+ });
+ final java.util.concurrent.atomic.AtomicInteger converted = new java.util.concurrent.atomic.AtomicInteger(progress);
+
+ final long start = System.nanoTime();
+
+ for (final File file : files) {
+ threadPool.execute(() -> {
+ convertRegion(registryManager, directory, file, biomeSource, 0, total, progressListener);
+ converted.incrementAndGet();
+ });
+ }
+ threadPool.shutdown();
+
+ final java.text.DecimalFormat format = new java.text.DecimalFormat("#0.00");
+ while (!threadPool.isTerminated()) {
+ final int getConverted = converted.get();
+ LOGGER.info("Converting... {}/{} ({}%)", getConverted, total, format.format(100.0D * (double) getConverted / (double) total));
+ try {
+ Thread.sleep(1000L);
+ } catch (final InterruptedException ignored) {}
+ }
+
+ final long end = System.nanoTime();
+
+ final double durationSeconds = Math.ceil((end - start) * 1.0e-9);
+ LOGGER.info("Conversion for {} completed in {}s", directory, durationSeconds);
}
+ // Paper end
private static void convertRegion(RegistryAccess.RegistryHolder registryManager, File directory, File file, BiomeSource biomeSource, int i, int j, ProgressListener progressListener) {
String string = file.getName();
diff --git a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
+++ b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
@@ -0,0 +0,0 @@ public class PrimaryLevelData implements ServerLevelData, WorldData {
levelTag.putUUID("WanderingTraderId", this.wanderingTraderId);
}
- levelTag.putString("Bukkit.Version", Bukkit.getName() + "/" + Bukkit.getVersion() + "/" + Bukkit.getBukkitVersion()); // CraftBukkit
+ if (Bukkit.getServer() != null) levelTag.putString("Bukkit.Version", Bukkit.getName() + "/" + Bukkit.getVersion() + "/" + Bukkit.getBukkitVersion()); // CraftBukkit // Paper - server may not be started yet
}
@Override

View file

@ -26,3 +26,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
check ChunkHolder#updateFutures async catcher check ChunkHolder#updateFutures async catcher
leaf: check mid tick chunk task diff in ServerChunkCache