diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch index 1e67cf2171..0e5609389a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch @@ -134,3 +134,24 @@ CompoundTag nbttagcompound1 = new CompoundTag(); nbttagcompound1.putString("dimension", worldKey.location().toString()); +@@ -108,8 +172,19 @@ + } + + public CompletableFuture write(ChunkPos chunkPos, Supplier nbtSupplier) { ++ // Paper start - guard against possible chunk pos desync ++ final Supplier guardedPosCheck = () -> { ++ CompoundTag nbt = nbtSupplier.get(); ++ if (nbt != null && !chunkPos.equals(SerializableChunkData.getChunkCoordinate(nbt))) { ++ final String world = (ChunkStorage.this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap) ChunkStorage.this).level.getWorld().getName() : null; ++ throw new IllegalArgumentException("Chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + chunkPos ++ + " but compound says coordinate is " + SerializableChunkData.getChunkCoordinate(nbt) + (world == null ? " for an unknown world" : (" for world: " + world))); ++ } ++ return nbt; ++ }; ++ // Paper end - guard against possible chunk pos desync + this.handleLegacyStructureIndex(chunkPos); +- return this.worker.store(chunkPos, nbtSupplier); ++ return this.worker.store(chunkPos, guardedPosCheck); // Paper - guard against possible chunk pos desync + } + + protected void handleLegacyStructureIndex(ChunkPos chunkPos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch index 132fde3257..f29dca5073 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch @@ -10,7 +10,34 @@ public static final Codec> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); private static final Logger LOGGER = LogUtils.getLogger(); -@@ -110,7 +111,7 @@ +@@ -90,13 +91,25 @@ + public static final String SECTIONS_TAG = "sections"; + public static final String BLOCK_LIGHT_TAG = "BlockLight"; + public static final String SKY_LIGHT_TAG = "SkyLight"; ++ // Paper start - guard against serializing mismatching coordinates ++ // TODO Note: This needs to be re-checked each update ++ public static ChunkPos getChunkCoordinate(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 new ChunkPos(levelData.getInt("xPos"), levelData.getInt("zPos")); ++ } else { ++ return new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos")); ++ } ++ } ++ // Paper end - guard against serializing mismatching coordinates + + @Nullable + public static SerializableChunkData parse(LevelHeightAccessor world, RegistryAccess registryManager, CompoundTag nbt) { + if (!nbt.contains("Status", 8)) { + return null; + } else { +- ChunkPos chunkcoordintpair = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); ++ ChunkPos chunkcoordintpair = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate + long i = nbt.getLong("LastUpdate"); + long j = nbt.getLong("InhabitedTime"); + ChunkStatus chunkstatus = ChunkStatus.byName(nbt.getString("Status")); +@@ -110,7 +123,7 @@ dataresult = BlendingData.Packed.CODEC.parse(NbtOps.INSTANCE, nbt.getCompound("blending_data")); logger = SerializableChunkData.LOGGER; Objects.requireNonNull(logger); @@ -19,7 +46,7 @@ } else { blendingdata_d = null; } -@@ -121,7 +122,7 @@ +@@ -121,7 +134,7 @@ dataresult = BelowZeroRetrogen.CODEC.parse(NbtOps.INSTANCE, nbt.getCompound("below_zero_retrogen")); logger = SerializableChunkData.LOGGER; Objects.requireNonNull(logger); @@ -28,7 +55,7 @@ } else { belowzeroretrogen = null; } -@@ -178,7 +179,7 @@ +@@ -178,7 +191,7 @@ ListTag nbttaglist2 = nbt.getList("sections", 10); List list4 = new ArrayList(nbttaglist2.size()); Registry iregistry = registryManager.lookupOrThrow(Registries.BIOME); @@ -37,7 +64,7 @@ for (int i1 = 0; i1 < nbttaglist2.size(); ++i1) { CompoundTag nbttagcompound3 = nbttaglist2.getCompound(i1); -@@ -196,17 +197,17 @@ +@@ -196,17 +209,17 @@ datapaletteblock = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } @@ -58,7 +85,7 @@ } else { chunksection = null; } -@@ -217,7 +218,8 @@ +@@ -217,7 +230,8 @@ list4.add(new SerializableChunkData.SectionData(b0, chunksection, nibblearray, nibblearray1)); } @@ -68,34 +95,34 @@ } } -@@ -289,6 +291,12 @@ +@@ -287,7 +301,13 @@ + if (this.chunkStatus.isOrAfter(ChunkStatus.INITIALIZE_LIGHT)) { + protochunk.setLightEngine(levellightengine); } - } - ++ } ++ + // CraftBukkit start - load chunk persistent data from nbt - SPIGOT-6814: Already load PDC here to account for 1.17 to 1.18 chunk upgrading. + if (this.persistentDataContainer instanceof CompoundTag) { + ((ChunkAccess) object).persistentDataContainer.putAll((CompoundTag) this.persistentDataContainer); -+ } + } + // CraftBukkit end -+ + ((ChunkAccess) object).setLightCorrect(this.lightCorrect); EnumSet enumset = EnumSet.noneOf(Heightmap.Types.class); - Iterator iterator1 = ((ChunkAccess) object).getPersistedStatus().heightmapsAfter().iterator(); -@@ -346,7 +354,13 @@ - - private static Codec>> makeBiomeCodec(Registry biomeRegistry) { +@@ -348,6 +368,12 @@ return PalettedContainer.codecRO(biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS)); -+ } -+ + } + + // CraftBukkit start - read/write + private static Codec>> makeBiomeCodecRW(Registry iregistry) { + return PalettedContainer.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS)); - } ++ } + // CraftBukkit end - ++ public static SerializableChunkData copyOf(ServerLevel world, ChunkAccess chunk) { if (!chunk.canBeSerialized()) { -@@ -419,7 +433,14 @@ + throw new IllegalArgumentException("Chunk can't be serialized: " + String.valueOf(chunk)); +@@ -419,7 +445,14 @@ }); CompoundTag nbttagcompound1 = packStructureData(StructurePieceSerializationContext.fromLevel(world), chunkcoordintpair, chunk.getAllStarts(), chunk.getAllReferences()); @@ -111,7 +138,7 @@ } } -@@ -432,7 +453,7 @@ +@@ -432,7 +465,7 @@ nbttagcompound.putLong("LastUpdate", this.lastUpdateTime); nbttagcompound.putLong("InhabitedTime", this.inhabitedTime); nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString()); @@ -120,7 +147,7 @@ Logger logger; if (this.blendingData != null) { -@@ -513,6 +534,11 @@ +@@ -513,6 +546,11 @@ }); nbttagcompound.put("Heightmaps", nbttagcompound2); nbttagcompound.put("structures", this.structureData); @@ -132,7 +159,7 @@ return nbttagcompound; } -@@ -623,6 +649,12 @@ +@@ -623,6 +661,12 @@ StructureStart structurestart = StructureStart.loadStaticStart(context, nbttagcompound1.getCompound(s), worldSeed); if (structurestart != null) {