From 3cf764645b43a1736df95315c88249b3c60d3a21 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sat, 26 Oct 2024 17:49:28 +0200 Subject: [PATCH] Apply more patches --- ...culate-regionfile-header-if-it-is-co.patch | 104 +++++++++--------- .../{unapplied => }/server/Bundle-spark.patch | 8 +- .../Entity-load-save-limit-per-chunk.patch | 4 +- 3 files changed, 58 insertions(+), 58 deletions(-) rename patches/{unapplied => }/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch (93%) rename patches/{unapplied => }/server/Bundle-spark.patch (99%) rename patches/{unapplied => }/server/Entity-load-save-limit-per-chunk.patch (97%) diff --git a/patches/unapplied/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch similarity index 93% rename from patches/unapplied/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch rename to patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch index e41ac6f156..0aa11765a3 100644 --- a/patches/unapplied/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch +++ b/patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch @@ -9,38 +9,6 @@ we instead drop the current regionfile header and recalculate - hoping that at least then we don't swap chunks, and maybe recover them all. -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -0,0 +0,0 @@ import net.minecraft.world.ticks.ProtoChunkTicks; - import org.slf4j.Logger; - - public class ChunkSerializer { -+ // Paper start - Attempt to recalculate regionfile header if it is corrupt -+ // TODO: Check on update -+ public static long getLastWorldSaveTime(CompoundTag chunkData) { -+ final int dataVersion = ChunkStorage.getVersion(chunkData); -+ if (dataVersion < 2842) { // Level tag is removed after this version -+ final CompoundTag levelData = chunkData.getCompound("Level"); -+ return levelData.getLong("LastUpdate"); -+ } else { -+ return chunkData.getLong("LastUpdate"); -+ } -+ } -+ // Paper end - Attempt to recalculate regionfile header if it is corrupt - - public static final Codec> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), null); // Paper - Anti-Xray - Add preset block states - private static final Logger LOGGER = LogUtils.getLogger(); -@@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound.putInt("xPos", chunkcoordintpair.x); - nbttagcompound.putInt("yPos", chunk.getMinSection()); - nbttagcompound.putInt("zPos", chunkcoordintpair.z); -- nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime() : world.getGameTime()); // Paper - async chunk saving -+ nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime() : world.getGameTime()); // Paper - async chunk saving // Paper - diff on change - nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime()); - nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(chunk.getPersistedStatus()).toString()); - BlendingData blendingdata = chunk.getBlendingData(); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java @@ -77,7 +45,7 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.ja index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/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, ca.spottedleaf.moonrise.patche private final IntBuffer timestamps; @VisibleForTesting protected final RegionBitmap usedSectors; @@ -191,7 +159,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } + -+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(compound); ++ ChunkPos chunkPos = SerializableChunkData.getChunkCoordinate(compound); + if (!inSameRegionfile(ourLowerLeftPosition, chunkPos)) { + LOGGER.error("Ignoring absolute chunk " + chunkPos + " in regionfile as it is not contained in the bounds of the regionfile '" + this.path.toAbsolutePath() + "'. It should be in regionfile (" + (chunkPos.x >> 5) + "," + (chunkPos.z >> 5) + ")"); + continue; @@ -200,7 +168,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + CompoundTag otherCompound = compounds[location]; + -+ if (otherCompound != null && ChunkSerializer.getLastWorldSaveTime(otherCompound) > ChunkSerializer.getLastWorldSaveTime(compound)) { ++ if (otherCompound != null && SerializableChunkData.getLastWorldSaveTime(otherCompound) > SerializableChunkData.getLastWorldSaveTime(compound)) { + continue; // don't overwrite newer data. + } + @@ -210,7 +178,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (Files.exists(aikarOversizedFile)) { + try { + CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z); -+ if (ChunkSerializer.getLastWorldSaveTime(compound) == ChunkSerializer.getLastWorldSaveTime(aikarOversizedCompound)) { ++ if (SerializableChunkData.getLastWorldSaveTime(compound) == SerializableChunkData.getLastWorldSaveTime(aikarOversizedCompound)) { + // best we got for an id. hope it's good enough + isAikarOversized = true; + } @@ -288,12 +256,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } + -+ if (!ChunkSerializer.getChunkCoordinate(compound).equals(oversizedCoords)) { -+ LOGGER.error("Can't use oversized chunk stored in " + regionFile.toAbsolutePath() + ", got absolute chunkpos: " + ChunkSerializer.getChunkCoordinate(compound) + ", expected " + oversizedCoords); ++ if (!SerializableChunkData.getChunkCoordinate(compound).equals(oversizedCoords)) { ++ LOGGER.error("Can't use oversized chunk stored in " + regionFile.toAbsolutePath() + ", got absolute chunkpos: " + SerializableChunkData.getChunkCoordinate(compound) + ", expected " + oversizedCoords); + continue; + } + -+ if (compounds[location] == null || ChunkSerializer.getLastWorldSaveTime(compound) > ChunkSerializer.getLastWorldSaveTime(compounds[location])) { ++ if (compounds[location] == null || SerializableChunkData.getLastWorldSaveTime(compound) > SerializableChunkData.getLastWorldSaveTime(compounds[location])) { + oversized[location] = true; + oversizedCompressionTypes[location] = compression; + } @@ -430,9 +398,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final boolean canRecalcHeader; // final forces compile fail on new constructor + // Paper end - Attempt to recalculate regionfile header if it is corrupt - public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { - this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { + // Paper start - rewrite chunk system + @Override +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche throw new IllegalArgumentException("Expected directory, got " + String.valueOf(directory.toAbsolutePath())); } else { this.externalFileDir = directory; @@ -440,7 +408,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.offsets = this.header.asIntBuffer(); ((java.nio.Buffer) this.offsets).limit(1024); // CraftBukkit - decompile error ((java.nio.Buffer) this.header).position(4096); // CraftBukkit - decompile error -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche RegionFile.LOGGER.warn("Region file {} has truncated header: {}", path, i); } @@ -462,7 +430,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Spigot start if (j1 == 255) { // We're maxed out, so we need to read the proper length from the section -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche j1 = (realLen.getInt(0) + 4) / 4096 + 1; } // Spigot end @@ -533,7 +501,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche } private Path getExternalChunkPath(ChunkPos chunkPos) { @@ -571,7 +539,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException { int i = this.getOffset(pos); -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche ((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error if (bytebuffer.remaining() < 5) { RegionFile.LOGGER.error("Chunk {} header is truncated: expected {} but read {}", new Object[]{pos, l, bytebuffer.remaining()}); @@ -583,7 +551,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return null; } else { int i1 = bytebuffer.getInt(); -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche if (i1 == 0) { RegionFile.LOGGER.warn("Chunk {} is allocated, but stream is missing", pos); @@ -595,7 +563,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return null; } else { int j1 = i1 - 1; -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche if (RegionFile.isExternalStreamChunk(b0)) { if (j1 != 0) { RegionFile.LOGGER.warn("Chunk has both internal and external streams"); @@ -643,7 +611,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } } -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche } private ByteBuffer createExternalStub() { @@ -665,7 +633,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - return ret; + } } // Paper end - rewrite chunk system + // Paper start - recalculate region file headers @@ -706,14 +674,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers } - public RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - public + // Paper start - rewrite chunk system @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise try { if (datainputstream != null) { nbttagcompound = NbtIo.read((DataInput) datainputstream); + // Paper start - recover from corrupt regionfile header + if (this.isChunkData) { -+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound); ++ ChunkPos chunkPos = SerializableChunkData.getChunkCoordinate(nbttagcompound); + if (!chunkPos.equals(pos)) { + 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.getPath().toAbsolutePath()); + if (regionfile.recalculateHeader()) { @@ -740,3 +708,35 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static final Object2ObjectMap VERSIONS_BY_NAME = new Object2ObjectOpenHashMap<>(); public static final RegionFileVersion VERSION_GZIP = register( new RegionFileVersion( +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +@@ -0,0 +0,0 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun + } + } + // Paper end - guard against serializing mismatching coordinates ++ // Paper start - Attempt to recalculate regionfile header if it is corrupt ++ // TODO: Check on update ++ public static long getLastWorldSaveTime(final CompoundTag chunkData) { ++ final int dataVersion = ChunkStorage.getVersion(chunkData); ++ if (dataVersion < 2842) { // Level tag is removed after this version ++ final CompoundTag levelData = chunkData.getCompound("Level"); ++ return levelData.getLong("LastUpdate"); ++ } else { ++ return chunkData.getLong("LastUpdate"); ++ } ++ } ++ // Paper end - Attempt to recalculate regionfile header if it is corrupt + + // Paper start - Do not let the server load chunks from newer versions + private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion(); +@@ -0,0 +0,0 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun + nbttagcompound.putInt("xPos", this.chunkPos.x); + nbttagcompound.putInt("yPos", this.minSectionY); + nbttagcompound.putInt("zPos", this.chunkPos.z); +- nbttagcompound.putLong("LastUpdate", this.lastUpdateTime); ++ nbttagcompound.putLong("LastUpdate", this.lastUpdateTime); // Paper - Diff on change + nbttagcompound.putLong("InhabitedTime", this.inhabitedTime); + nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString()); + DataResult dataresult; // CraftBukkit - decompile error diff --git a/patches/unapplied/server/Bundle-spark.patch b/patches/server/Bundle-spark.patch similarity index 99% rename from patches/unapplied/server/Bundle-spark.patch rename to patches/server/Bundle-spark.patch index 3961bd73fe..df87061f4f 100644 --- a/patches/unapplied/server/Bundle-spark.patch +++ b/patches/server/Bundle-spark.patch @@ -306,13 +306,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ++this.tickCount; @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk - for (final Entity entity : entities) { + for (final Entity entity : PlatformHooks.get().modifySavedEntities(world, chunkPos.x, chunkPos.z, entities)) { + // Paper start - Entity load/save limit per chunk + final EntityType entityType = entity.getType(); + final int saveLimit = world.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1); @@ -42,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final java.util.Map, Integer> loadedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk public boolean tryAdvance(Consumer consumer) { return spliterator.tryAdvance((nbtbase) -> { - EntityType.loadEntityRecursive((CompoundTag) nbtbase, world, (entity) -> { + EntityType.loadEntityRecursive((CompoundTag) nbtbase, world, reason, (entity) -> { + // Paper start - Entity load/save limit per chunk + final EntityType entityType = entity.getType(); + final int saveLimit = world.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);