--- a/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -57,14 +_,14 @@
 import net.minecraft.world.ticks.TickContainerAccess;
 import org.slf4j.Logger;
 
-public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, LightChunk, StructureAccess {
+public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, LightChunk, StructureAccess, ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk { // Paper - rewrite chunk system
     public static final int NO_FILLED_SECTION = -1;
     private static final Logger LOGGER = LogUtils.getLogger();
     private static final LongSet EMPTY_REFERENCE_SET = new LongOpenHashSet();
     protected final ShortList[] postProcessing;
     private volatile boolean unsaved;
     private volatile boolean isLightCorrect;
-    protected final ChunkPos chunkPos;
+    protected final ChunkPos chunkPos; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
     private long inhabitedTime;
     @Nullable
     @Deprecated
@@ -74,14 +_,70 @@
     protected final UpgradeData upgradeData;
     @Nullable
     protected BlendingData blendingData;
-    protected final Map<Heightmap.Types, Heightmap> heightmaps = Maps.newEnumMap(Heightmap.Types.class);
-    protected ChunkSkyLightSources skyLightSources;
+    public final Map<Heightmap.Types, Heightmap> heightmaps = Maps.newEnumMap(Heightmap.Types.class);
+    // Paper - rewrite chunk system
     private final Map<Structure, StructureStart> structureStarts = Maps.newHashMap();
     private final Map<Structure, LongSet> structuresRefences = Maps.newHashMap();
     protected final Map<BlockPos, CompoundTag> pendingBlockEntities = Maps.newHashMap();
-    protected final Map<BlockPos, BlockEntity> blockEntities = new Object2ObjectOpenHashMap<>();
+    public final Map<BlockPos, BlockEntity> blockEntities = new Object2ObjectOpenHashMap<>();
     protected final LevelHeightAccessor levelHeightAccessor;
     protected final LevelChunkSection[] 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(ChunkAccess.DATA_TYPE_REGISTRY);
+    // CraftBukkit end
+    public final Registry<Biome> biomeRegistry; // CraftBukkit
+
+    // Paper start - rewrite chunk system
+    private volatile ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] blockNibbles;
+    private volatile ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] skyNibbles;
+    private volatile boolean[] skyEmptinessMap;
+    private volatile boolean[] blockEmptinessMap;
+
+    @Override
+    public ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] starlight$getBlockNibbles() {
+        return this.blockNibbles;
+    }
+
+    @Override
+    public void starlight$setBlockNibbles(final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] nibbles) {
+        this.blockNibbles = nibbles;
+    }
+
+    @Override
+    public ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] starlight$getSkyNibbles() {
+        return this.skyNibbles;
+    }
+
+    @Override
+    public void starlight$setSkyNibbles(final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] nibbles) {
+        this.skyNibbles = nibbles;
+    }
+
+    @Override
+    public boolean[] starlight$getSkyEmptinessMap() {
+        return this.skyEmptinessMap;
+    }
+
+    @Override
+    public void starlight$setSkyEmptinessMap(final boolean[] emptinessMap) {
+        this.skyEmptinessMap = emptinessMap;
+    }
+
+    @Override
+    public boolean[] starlight$getBlockEmptinessMap() {
+        return this.blockEmptinessMap;
+    }
+
+    @Override
+    public void starlight$setBlockEmptinessMap(final boolean[] emptinessMap) {
+        this.blockEmptinessMap = emptinessMap;
+    }
+    // Paper end - rewrite chunk system
+    // Paper start - get block chunk optimisation
+    private final int minSection;
+    private final int maxSection;
+    // Paper end - get block chunk optimisation
 
     public ChunkAccess(
         ChunkPos chunkPos,
@@ -92,14 +_,15 @@
         @Nullable LevelChunkSection[] sections,
         @Nullable BlendingData blendingData
     ) {
-        this.chunkPos = chunkPos;
+        this.locX = chunkPos.x; this.locZ = chunkPos.z; // Paper - reduce need for field lookups
+        this.chunkPos = chunkPos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key
         this.upgradeData = upgradeData;
         this.levelHeightAccessor = levelHeightAccessor;
         this.sections = new LevelChunkSection[levelHeightAccessor.getSectionsCount()];
         this.inhabitedTime = inhabitedTime;
         this.postProcessing = new ShortList[levelHeightAccessor.getSectionsCount()];
         this.blendingData = blendingData;
-        this.skyLightSources = new ChunkSkyLightSources(levelHeightAccessor);
+        // Paper - rewrite chunk system
         if (sections != null) {
             if (this.sections.length == sections.length) {
                 System.arraycopy(sections, 0, this.sections, 0, this.sections.length);
@@ -108,13 +_,24 @@
             }
         }
 
-        replaceMissingSections(biomeRegistry, this.sections);
+        this.replaceMissingSections(biomeRegistry, this.sections); // Paper - Anti-Xray - make it a non-static method
+        this.biomeRegistry = biomeRegistry; // CraftBukkit
+        // Paper start - rewrite chunk system
+        if (!((Object)this instanceof ImposterProtoChunk)) {
+            this.starlight$setBlockNibbles(ca.spottedleaf.moonrise.patches.starlight.light.StarLightEngine.getFilledEmptyLight(levelHeightAccessor));
+            this.starlight$setSkyNibbles(ca.spottedleaf.moonrise.patches.starlight.light.StarLightEngine.getFilledEmptyLight(levelHeightAccessor));
+        }
+        // Paper end - rewrite chunk system
+        // Paper start - get block chunk optimisation
+        this.minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(levelHeightAccessor);
+        this.maxSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(levelHeightAccessor);
+        // Paper end - get block chunk optimisation
     }
 
-    private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) {
+    private void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) { // Paper - Anti-Xray - make it a non-static method
         for (int i = 0; i < sections.length; i++) {
             if (sections[i] == null) {
-                sections[i] = new LevelChunkSection(biomeRegistry);
+                sections[i] = new LevelChunkSection(biomeRegistry, this.levelHeightAccessor instanceof net.minecraft.world.level.Level ? (net.minecraft.world.level.Level) this.levelHeightAccessor : null, this.chunkPos, this.levelHeightAccessor.getSectionYFromSectionIndex(i)); // Paper - Anti-Xray - Add parameters
             }
         }
     }
@@ -123,6 +_,7 @@
         return GameEventListenerRegistry.NOOP;
     }
 
+    public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper
     @Nullable
     public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving);
 
@@ -273,6 +_,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;
@@ -280,7 +_,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();
@@ -433,19 +_,39 @@
 
     @Override
     public Holder<Biome> getNoiseBiome(int x, int y, int z) {
+        // Paper start - get block chunk optimisation
+        int sectionY = (y >> 2) - this.minSection;
+        int rel = y & 3;
+
+        final LevelChunkSection[] sections = this.sections;
+
+        if (sectionY < 0) {
+            sectionY = 0;
+            rel = 0;
+        } else if (sectionY >= sections.length) {
+            sectionY = sections.length - 1;
+            rel = 3;
+        }
+
+        return sections[sectionY].getNoiseBiome(x & 3, rel, z & 3);
+        // Paper end - get block chunk optimisation
+    }
+    // CraftBukkit start
+    public void setBiome(int x, int y, int z, Holder<Biome> biome) {
         try {
-            int quartPosMinY = QuartPos.fromBlock(this.getMinY());
-            int i = quartPosMinY + QuartPos.fromBlock(this.getHeight()) - 1;
-            int i1 = Mth.clamp(y, quartPosMinY, i);
-            int sectionIndex = this.getSectionIndex(QuartPos.toBlock(i1));
-            return this.sections[sectionIndex].getNoiseBiome(x & 3, i1 & 3, z & 3);
-        } catch (Throwable var8) {
-            CrashReport crashReport = CrashReport.forThrowable(var8, "Getting biome");
-            CrashReportCategory crashReportCategory = crashReport.addCategory("Biome being got");
-            crashReportCategory.setDetail("Location", () -> CrashReportCategory.formatLocation(this, x, y, z));
-            throw new ReportedException(crashReport);
+            int minY = QuartPos.fromBlock(this.getMinY());
+            int maxY = minY + QuartPos.fromBlock(this.getHeight()) - 1;
+            int clampedY = Mth.clamp(y, minY, maxY);
+            int sectionIndex = this.getSectionIndex(QuartPos.toBlock(clampedY));
+            this.sections[sectionIndex].setBiome(x & 3, clampedY & 3, z & 3, biome);
+        } catch (Throwable throwable) {
+            CrashReport report = CrashReport.forThrowable(throwable, "Setting biome");
+            CrashReportCategory reportCategory = report.addCategory("Biome being set");
+            reportCategory.setDetail("Location", () -> CrashReportCategory.formatLocation(this, x, y, z));
+            throw new ReportedException(report);
         }
     }
+    // CraftBukkit end
 
     public void fillBiomesFromNoise(BiomeResolver resolver, Climate.Sampler sampler) {
         ChunkPos pos = this.getPos();
@@ -478,12 +_,12 @@
     }
 
     public void initializeLightSources() {
-        this.skyLightSources.fillFrom(this);
+        // Paper - rewrite chunk system
     }
 
     @Override
     public ChunkSkyLightSources getSkyLightSources() {
-        return this.skyLightSources;
+        return null; // Paper - rewrite chunk system
     }
 
     public record PackedTicks(List<SavedTick<Block>> blocks, List<SavedTick<Fluid>> fluids) {
