--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
@@ -76,7 +76,8 @@
 import net.minecraft.world.ticks.TickListChunk;
 import org.slf4j.Logger;
 
-public record SerializableChunkData(IRegistry<BiomeBase> biomeRegistry, ChunkCoordIntPair chunkPos, int minSectionY, long lastUpdateTime, long inhabitedTime, ChunkStatus chunkStatus, @Nullable BlendingData.d blendingData, @Nullable BelowZeroRetrogen belowZeroRetrogen, ChunkConverter upgradeData, @Nullable long[] carvingMask, Map<HeightMap.Type, long[]> heightmaps, IChunkAccess.a packedTicks, ShortList[] postProcessingSections, boolean lightCorrect, List<SerializableChunkData.b> sectionData, List<NBTTagCompound> entities, List<NBTTagCompound> blockEntities, NBTTagCompound structureData) {
+// CraftBukkit - persistentDataContainer
+public record SerializableChunkData(IRegistry<BiomeBase> biomeRegistry, ChunkCoordIntPair chunkPos, int minSectionY, long lastUpdateTime, long inhabitedTime, ChunkStatus chunkStatus, @Nullable BlendingData.d blendingData, @Nullable BelowZeroRetrogen belowZeroRetrogen, ChunkConverter upgradeData, @Nullable long[] carvingMask, Map<HeightMap.Type, long[]> heightmaps, IChunkAccess.a packedTicks, ShortList[] postProcessingSections, boolean lightCorrect, List<SerializableChunkData.b> sectionData, List<NBTTagCompound> entities, List<NBTTagCompound> blockEntities, NBTTagCompound structureData, @Nullable NBTBase persistentDataContainer) {
 
     public static final Codec<DataPaletteBlock<IBlockData>> BLOCK_STATE_CODEC = DataPaletteBlock.codecRW(Block.BLOCK_STATE_REGISTRY, IBlockData.CODEC, DataPaletteBlock.d.SECTION_STATES, Blocks.AIR.defaultBlockState());
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -110,7 +111,7 @@
                 dataresult = BlendingData.d.CODEC.parse(DynamicOpsNBT.INSTANCE, nbttagcompound.getCompound("blending_data"));
                 logger = SerializableChunkData.LOGGER;
                 Objects.requireNonNull(logger);
-                blendingdata_d = (BlendingData.d) dataresult.resultOrPartial(logger::error).orElse((Object) null);
+                blendingdata_d = (BlendingData.d) ((DataResult<BlendingData.d>) dataresult).resultOrPartial(logger::error).orElse(null); // CraftBukkit - decompile error
             } else {
                 blendingdata_d = null;
             }
@@ -121,7 +122,7 @@
                 dataresult = BelowZeroRetrogen.CODEC.parse(DynamicOpsNBT.INSTANCE, nbttagcompound.getCompound("below_zero_retrogen"));
                 logger = SerializableChunkData.LOGGER;
                 Objects.requireNonNull(logger);
-                belowzeroretrogen = (BelowZeroRetrogen) dataresult.resultOrPartial(logger::error).orElse((Object) null);
+                belowzeroretrogen = (BelowZeroRetrogen) ((DataResult<BelowZeroRetrogen>) dataresult).resultOrPartial(logger::error).orElse(null); // CraftBukkit - decompile error
             } else {
                 belowzeroretrogen = null;
             }
@@ -178,7 +179,7 @@
             NBTTagList nbttaglist2 = nbttagcompound.getList("sections", 10);
             List<SerializableChunkData.b> list4 = new ArrayList(nbttaglist2.size());
             IRegistry<BiomeBase> iregistry = iregistrycustom.lookupOrThrow(Registries.BIOME);
-            Codec<PalettedContainerRO<Holder<BiomeBase>>> codec = makeBiomeCodec(iregistry);
+            Codec<DataPaletteBlock<Holder<BiomeBase>>> codec = makeBiomeCodecRW(iregistry); // CraftBukkit - read/write
 
             for (int i1 = 0; i1 < nbttaglist2.size(); ++i1) {
                 NBTTagCompound nbttagcompound3 = nbttaglist2.getCompound(i1);
@@ -196,17 +197,17 @@
                         datapaletteblock = new DataPaletteBlock<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), DataPaletteBlock.d.SECTION_STATES);
                     }
 
-                    Object object;
+                    DataPaletteBlock object; // CraftBukkit - read/write
 
                     if (nbttagcompound3.contains("biomes", 10)) {
-                        object = (PalettedContainerRO) codec.parse(DynamicOpsNBT.INSTANCE, nbttagcompound3.getCompound("biomes")).promotePartial((s1) -> {
+                        object = codec.parse(DynamicOpsNBT.INSTANCE, nbttagcompound3.getCompound("biomes")).promotePartial((s1) -> { // CraftBukkit - read/write
                             logErrors(chunkcoordintpair, b0, s1);
                         }).getOrThrow(SerializableChunkData.a::new);
                     } else {
                         object = new DataPaletteBlock<>(iregistry.asHolderIdMap(), iregistry.getOrThrow(Biomes.PLAINS), DataPaletteBlock.d.SECTION_BIOMES);
                     }
 
-                    chunksection = new ChunkSection(datapaletteblock, (PalettedContainerRO) object);
+                    chunksection = new ChunkSection(datapaletteblock, (DataPaletteBlock) object); // CraftBukkit - read/write
                 } else {
                     chunksection = null;
                 }
@@ -217,7 +218,8 @@
                 list4.add(new SerializableChunkData.b(b0, chunksection, nibblearray, nibblearray1));
             }
 
-            return new SerializableChunkData(iregistry, chunkcoordintpair, levelheightaccessor.getMinSectionY(), i, j, chunkstatus, blendingdata_d, belowzeroretrogen, chunkconverter, along, map, ichunkaccess_a, ashortlist, flag, list4, list2, list3, nbttagcompound2);
+            // CraftBukkit - ChunkBukkitValues
+            return new SerializableChunkData(iregistry, chunkcoordintpair, levelheightaccessor.getMinSectionY(), i, j, chunkstatus, blendingdata_d, belowzeroretrogen, chunkconverter, along, map, ichunkaccess_a, ashortlist, flag, list4, list2, list3, nbttagcompound2, nbttagcompound.get("ChunkBukkitValues"));
         }
     }
 
@@ -289,6 +291,12 @@
             }
         }
 
+        // 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 (persistentDataContainer instanceof NBTTagCompound) {
+            ((IChunkAccess) object).persistentDataContainer.putAll((NBTTagCompound) persistentDataContainer);
+        }
+        // CraftBukkit end
+
         ((IChunkAccess) object).setLightCorrect(this.lightCorrect);
         EnumSet<HeightMap.Type> enumset = EnumSet.noneOf(HeightMap.Type.class);
         Iterator iterator1 = ((IChunkAccess) object).getPersistedStatus().heightmapsAfter().iterator();
@@ -348,6 +356,12 @@
         return DataPaletteBlock.codecRO(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), DataPaletteBlock.d.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS));
     }
 
+    // CraftBukkit start - read/write
+    private static Codec<DataPaletteBlock<Holder<BiomeBase>>> makeBiomeCodecRW(IRegistry<BiomeBase> iregistry) {
+        return DataPaletteBlock.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), DataPaletteBlock.d.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS));
+    }
+    // CraftBukkit end
+
     public static SerializableChunkData copyOf(WorldServer worldserver, IChunkAccess ichunkaccess) {
         if (!ichunkaccess.canBeSerialized()) {
             throw new IllegalArgumentException("Chunk can't be serialized: " + String.valueOf(ichunkaccess));
@@ -419,7 +433,14 @@
             });
             NBTTagCompound nbttagcompound1 = packStructureData(StructurePieceSerializationContext.fromLevel(worldserver), chunkcoordintpair, ichunkaccess.getAllStarts(), ichunkaccess.getAllReferences());
 
-            return new SerializableChunkData(worldserver.registryAccess().lookupOrThrow(Registries.BIOME), chunkcoordintpair, ichunkaccess.getMinSectionY(), worldserver.getGameTime(), ichunkaccess.getInhabitedTime(), ichunkaccess.getPersistedStatus(), (BlendingData.d) Optionull.map(ichunkaccess.getBlendingData(), BlendingData::pack), ichunkaccess.getBelowZeroRetrogen(), ichunkaccess.getUpgradeData().copy(), along, map, ichunkaccess_a, ashortlist, ichunkaccess.isLightCorrect(), list, list2, list1, nbttagcompound1);
+            // CraftBukkit start - store chunk persistent data in nbt
+            NBTTagCompound persistentDataContainer = null;
+            if (!ichunkaccess.persistentDataContainer.isEmpty()) { // SPIGOT-6814: Always save PDC to account for 1.17 to 1.18 chunk upgrading.
+                persistentDataContainer = ichunkaccess.persistentDataContainer.toTagCompound();
+            }
+
+            return new SerializableChunkData(worldserver.registryAccess().lookupOrThrow(Registries.BIOME), chunkcoordintpair, ichunkaccess.getMinSectionY(), worldserver.getGameTime(), ichunkaccess.getInhabitedTime(), ichunkaccess.getPersistedStatus(), (BlendingData.d) Optionull.map(ichunkaccess.getBlendingData(), BlendingData::pack), ichunkaccess.getBelowZeroRetrogen(), ichunkaccess.getUpgradeData().copy(), along, map, ichunkaccess_a, ashortlist, ichunkaccess.isLightCorrect(), list, list2, list1, nbttagcompound1, persistentDataContainer);
+            // CraftBukkit end
         }
     }
 
@@ -432,7 +453,7 @@
         nbttagcompound.putLong("LastUpdate", this.lastUpdateTime);
         nbttagcompound.putLong("InhabitedTime", this.inhabitedTime);
         nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString());
-        DataResult dataresult;
+        DataResult<NBTBase> dataresult; // CraftBukkit - decompile error
         Logger logger;
 
         if (this.blendingData != null) {
@@ -513,6 +534,11 @@
         });
         nbttagcompound.put("Heightmaps", nbttagcompound2);
         nbttagcompound.put("structures", this.structureData);
+        // CraftBukkit start - store chunk persistent data in nbt
+        if (persistentDataContainer != null) { // SPIGOT-6814: Always save PDC to account for 1.17 to 1.18 chunk upgrading.
+            nbttagcompound.put("ChunkBukkitValues", persistentDataContainer);
+        }
+        // CraftBukkit end
         return nbttagcompound;
     }
 
@@ -623,6 +649,12 @@
                 StructureStart structurestart = StructureStart.loadStaticStart(structurepieceserializationcontext, nbttagcompound1.getCompound(s), i);
 
                 if (structurestart != null) {
+                    // CraftBukkit start - load persistent data for structure start
+                    net.minecraft.nbt.NBTBase persistentBase = nbttagcompound1.getCompound(s).get("StructureBukkitValues");
+                    if (persistentBase instanceof NBTTagCompound) {
+                        structurestart.persistentDataContainer.putAll((NBTTagCompound) persistentBase);
+                    }
+                    // CraftBukkit end
                     map.put(structure, structurestart);
                 }
             }
