--- a/net/minecraft/world/level/chunk/IChunkAccess.java
+++ b/net/minecraft/world/level/chunk/IChunkAccess.java
@@ -85,6 +85,11 @@
     protected final LevelHeightAccessor levelHeightAccessor;
     protected final ChunkSection[] sections;
 
+    // CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading.
+    private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
+    public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(DATA_TYPE_REGISTRY);
+    // CraftBukkit end
+
     public IChunkAccess(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter, LevelHeightAccessor levelheightaccessor, IRegistry<BiomeBase> iregistry, long i, @Nullable ChunkSection[] achunksection, @Nullable BlendingData blendingdata) {
         this.chunkPos = chunkcoordintpair;
         this.upgradeData = chunkconverter;
@@ -103,7 +108,11 @@
         }
 
         replaceMissingSections(iregistry, this.sections);
+        // CraftBukkit start
+        this.biomeRegistry = iregistry;
     }
+    public final IRegistry<BiomeBase> biomeRegistry;
+    // CraftBukkit end
 
     private static void replaceMissingSections(IRegistry<BiomeBase> iregistry, ChunkSection[] achunksection) {
         for (int i = 0; i < achunksection.length; ++i) {
@@ -275,6 +284,7 @@
     public boolean tryMarkSaved() {
         if (this.unsaved) {
             this.unsaved = false;
+            this.persistentDataContainer.dirty(false); // CraftBukkit - SPIGOT-6814: chunk was saved, pdc is no longer dirty
             return true;
         } else {
             return false;
@@ -282,7 +292,7 @@
     }
 
     public boolean isUnsaved() {
-        return this.unsaved;
+        return this.unsaved || this.persistentDataContainer.dirty(); // CraftBukkit - SPIGOT-6814: chunk is unsaved if pdc was mutated
     }
 
     public abstract ChunkStatus getPersistedStatus();
@@ -463,6 +473,27 @@
         }
     }
 
+    // CraftBukkit start
+    public void setBiome(int i, int j, int k, Holder<BiomeBase> biome) {
+        try {
+            int l = QuartPos.fromBlock(this.getMinY());
+            int i1 = l + QuartPos.fromBlock(this.getHeight()) - 1;
+            int j1 = MathHelper.clamp(j, l, i1);
+            int k1 = this.getSectionIndex(QuartPos.toBlock(j1));
+
+            this.sections[k1].setBiome(i & 3, j1 & 3, k & 3, biome);
+        } catch (Throwable throwable) {
+            CrashReport crashreport = CrashReport.forThrowable(throwable, "Setting biome");
+            CrashReportSystemDetails crashreportsystemdetails = crashreport.addCategory("Biome being set");
+
+            crashreportsystemdetails.setDetail("Location", () -> {
+                return CrashReportSystemDetails.formatLocation(this, i, j, k);
+            });
+            throw new ReportedException(crashreport);
+        }
+    }
+    // CraftBukkit end
+
     public void fillBiomesFromNoise(BiomeResolver biomeresolver, Climate.Sampler climate_sampler) {
         ChunkCoordIntPair chunkcoordintpair = this.getPos();
         int i = QuartPos.fromBlock(chunkcoordintpair.getMinBlockX());
