--- a/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
+++ b/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
@@ -21,7 +21,7 @@
     private volatile boolean hasSourceInconsistencies;
 
     protected SkyLightSectionStorage(LightChunkGetter chunkProvider) {
-        super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new Long2ObjectOpenHashMap<>(), new Long2IntOpenHashMap(), Integer.MAX_VALUE));
+        super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int(), Integer.MAX_VALUE, false)); // Paper - avoid copying light data
     }
 
     @Override
@@ -32,8 +32,9 @@
     protected int getLightValue(long blockPos, boolean cached) {
         long l = SectionPos.blockToSection(blockPos);
         int i = SectionPos.y(l);
-        SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = cached ? this.updatingSectionData : this.visibleSectionData;
-        int j = skyDataLayerStorageMap.topSections.get(SectionPos.getZeroNode(l));
+        synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
+        SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = (SkyLightSectionStorage.SkyDataLayerStorageMap) this.e_visible; // Paper - avoid copying light data - must be after lock acquire
+        int j = skyDataLayerStorageMap.otherData.getVisibleAsync(SectionPos.getZeroNode(l)); // Paper - avoid copying light data
         if (j != skyDataLayerStorageMap.currentLowestY && i < j) {
             DataLayer dataLayer = this.getDataLayer(skyDataLayerStorageMap, l);
             if (dataLayer == null) {
@@ -52,6 +53,7 @@
         } else {
             return cached && !this.lightOnInSection(l) ? 0 : 15;
         }
+        } // Paper - avoid copying light data
     }
 
     @Override
@@ -59,13 +61,13 @@
         int i = SectionPos.y(sectionPos);
         if ((this.updatingSectionData).currentLowestY > i) {
             (this.updatingSectionData).currentLowestY = i;
-            (this.updatingSectionData).topSections.defaultReturnValue((this.updatingSectionData).currentLowestY);
+            (this.updatingSectionData).otherData.queueDefaultReturnValue((this.updatingSectionData).currentLowestY); // Paper - avoid copying light data
         }
 
         long l = SectionPos.getZeroNode(sectionPos);
-        int j = (this.updatingSectionData).topSections.get(l);
+        int j = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
         if (j < i + 1) {
-            (this.updatingSectionData).topSections.put(l, i + 1);
+            (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
             if (this.columnsWithSkySources.contains(l)) {
                 this.queueAddSource(sectionPos);
                 if (j > (this.updatingSectionData).currentLowestY) {
@@ -102,19 +104,19 @@
         }
 
         int i = SectionPos.y(sectionPos);
-        if ((this.updatingSectionData).topSections.get(l) == i + 1) {
+        if ((this.updatingSectionData).otherData.getUpdating(l) == i + 1) { // Paper - avoid copying light data
             long m;
             for(m = sectionPos; !this.storingLightForSection(m) && this.hasSectionsBelow(i); m = SectionPos.offset(m, Direction.DOWN)) {
                 --i;
             }
 
             if (this.storingLightForSection(m)) {
-                (this.updatingSectionData).topSections.put(l, i + 1);
+                (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
                 if (bl) {
                     this.queueAddSource(m);
                 }
             } else {
-                (this.updatingSectionData).topSections.remove(l);
+                (this.updatingSectionData).otherData.queueRemove(l); // Paper - avoid copying light data
             }
         }
 
@@ -128,7 +130,7 @@
     protected void enableLightSources(long columnPos, boolean enabled) {
         this.runAllUpdates();
         if (enabled && this.columnsWithSkySources.add(columnPos)) {
-            int i = (this.updatingSectionData).topSections.get(columnPos);
+            int i = (this.updatingSectionData).otherData.getUpdating(columnPos); // Paper - avoid copying light data
             if (i != (this.updatingSectionData).currentLowestY) {
                 long l = SectionPos.asLong(SectionPos.x(columnPos), i - 1, SectionPos.z(columnPos));
                 this.queueAddSource(l);
@@ -152,7 +154,7 @@
             return dataLayer;
         } else {
             long l = SectionPos.offset(sectionPos, Direction.UP);
-            int i = (this.updatingSectionData).topSections.get(SectionPos.getZeroNode(sectionPos));
+            int i = (this.updatingSectionData).otherData.getUpdating(SectionPos.getZeroNode(sectionPos)); // Paper - avoid copying light data
             if (i != (this.updatingSectionData).currentLowestY && SectionPos.y(l) < i) {
                 DataLayer dataLayer2;
                 while((dataLayer2 = this.getDataLayer(l, true)) == null) {
@@ -275,7 +277,7 @@
 
     protected boolean isAboveData(long sectionPos) {
         long l = SectionPos.getZeroNode(sectionPos);
-        int i = (this.updatingSectionData).topSections.get(l);
+        int i = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
         return i == (this.updatingSectionData).currentLowestY || SectionPos.y(sectionPos) >= i;
     }
 
@@ -286,18 +288,21 @@
 
     protected static final class SkyDataLayerStorageMap extends DataLayerStorageMap<SkyLightSectionStorage.SkyDataLayerStorageMap> {
         int currentLowestY;
-        final Long2IntOpenHashMap topSections;
+        private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data
 
-        public SkyDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays, Long2IntOpenHashMap columnToTopSection, int minSectionY) {
-            super(arrays);
-            this.topSections = columnToTopSection;
-            columnToTopSection.defaultReturnValue(minSectionY);
+        // Paper start - avoid copying light data
+        public SkyDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> arrays, com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int columnToTopSection, int minSectionY, boolean isVisible) {
+            super(arrays, isVisible);
+            this.otherData = columnToTopSection;
+            otherData.queueDefaultReturnValue(minSectionY);
+            // Paper end
             this.currentLowestY = minSectionY;
         }
 
         @Override
         public SkyLightSectionStorage.SkyDataLayerStorageMap copy() {
-            return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.map.clone(), this.topSections.clone(), this.currentLowestY);
+            this.otherData.performUpdatesLockMap(); // Paper - avoid copying light data
+            return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.data, this.otherData, this.currentLowestY, true); // Paper - avoid copying light data
         }
     }
 }
