--- a/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -28,26 +28,32 @@
     private static final int MIN_PALETTE_BITS = 0;
     private final PaletteResize<T> dummyPaletteResize = (newSize, added) -> 0;
     public final IdMap<T> registry;
-    private volatile PalettedContainer.Data<T> data;
+    private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values
+    public volatile PalettedContainer.Data<T> data; // Paper - optimise collisions - public
     private final PalettedContainer.Strategy strategy;
-    private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer");
+    // private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
 
     public void acquire() {
-        this.threadingDetector.checkAndLock();
+        // this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization
     }
 
     public void release() {
-        this.threadingDetector.checkAndUnlock();
+        // this.threadingDetector.checkAndUnlock(); // Paper - disable this
     }
 
-    public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) {
-        PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = PalettedContainer::unpack;
+    // Paper start - Anti-Xray - Add preset values
+    @Deprecated @io.papermc.paper.annotation.DoNotUse public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) { return PalettedContainer.codecRW(idList, entryCodec, paletteProvider, defaultValue, null); }
+    public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues) {
+        PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = (idListx, paletteProviderx, serialized) -> {
+            return unpack(idListx, paletteProviderx, serialized, defaultValue, presetValues);
+        };
+        // Paper end
         return codec(idList, entryCodec, paletteProvider, defaultValue, unpacker);
     }
 
     public static <T> Codec<PalettedContainerRO<T>> codecRO(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) {
         PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (idListx, paletteProviderx, serialized) -> unpack(
-                    idListx, paletteProviderx, serialized
+                    idListx, paletteProviderx, serialized, defaultValue, null // Paper - Anti-Xray - Add preset values
                 )
                 .map(result -> (PalettedContainerRO<T>)result);
         return codec(idList, entryCodec, paletteProvider, defaultValue, unpacker);
@@ -71,25 +77,58 @@
             );
     }
 
+    // Paper start - Anti-Xray - Add preset values
+    @Deprecated @io.papermc.paper.annotation.DoNotUse public PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Configuration<T> dataProvider, BitStorage storage, List<T> paletteEntries) { this(idList, paletteProvider, dataProvider, storage, paletteEntries, null, null); }
     public PalettedContainer(
         IdMap<T> idList,
         PalettedContainer.Strategy paletteProvider,
         PalettedContainer.Configuration<T> dataProvider,
         BitStorage storage,
-        List<T> paletteEntries
+        List<T> paletteEntries, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues
     ) {
+        this.presetValues = presetValues;
         this.registry = idList;
         this.strategy = paletteProvider;
         this.data = new PalettedContainer.Data<>(dataProvider, storage, dataProvider.factory().create(dataProvider.bits(), idList, this, paletteEntries));
+
+        if (presetValues != null && (dataProvider.factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY ? this.data.palette.valueFor(0) != defaultValue : dataProvider.factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY)) {
+            // In 1.18 Mojang unfortunately removed code that already handled possible resize operations on read from disk for us
+            // We readd this here but in a smarter way than it was before
+            int maxSize = 1 << dataProvider.bits();
+
+            for (T presetValue : presetValues) {
+                if (this.data.palette.getSize() >= maxSize) {
+                    java.util.Set<T> allValues = new java.util.HashSet<>(paletteEntries);
+                    allValues.addAll(Arrays.asList(presetValues));
+                    int newBits = Mth.ceillog2(allValues.size());
+
+                    if (newBits > dataProvider.bits()) {
+                        this.onResize(newBits, null);
+                    }
+
+                    break;
+                }
+
+                this.data.palette.idFor(presetValue);
+            }
+        }
+        // Paper end
     }
 
-    private PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Data<T> data) {
+    // Paper start - Anti-Xray - Add preset values
+    private PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Data<T> data, T @org.jetbrains.annotations.Nullable [] presetValues) {
+        this.presetValues = presetValues;
+        // Paper end
         this.registry = idList;
         this.strategy = paletteProvider;
         this.data = data;
     }
 
-    public PalettedContainer(IdMap<T> idList, T object, PalettedContainer.Strategy paletteProvider) {
+    // Paper start - Anti-Xray - Add preset values
+    @Deprecated @io.papermc.paper.annotation.DoNotUse public PalettedContainer(IdMap<T> idList, T object, PalettedContainer.Strategy paletteProvider) { this(idList, object, paletteProvider, null); }
+    public PalettedContainer(IdMap<T> idList, T object, PalettedContainer.Strategy paletteProvider, T @org.jetbrains.annotations.Nullable [] presetValues) {
+        this.presetValues = presetValues;
+        // Paper end
         this.strategy = paletteProvider;
         this.registry = idList;
         this.data = this.createOrReuseData(null, 0);
@@ -104,13 +143,35 @@
     }
 
     @Override
-    public int onResize(int newBits, T object) {
+    public synchronized int onResize(int newBits, T object) { // Paper - synchronize
         PalettedContainer.Data<T> data = this.data;
+
+        // Paper start - Anti-Xray - Add preset values
+        if (this.presetValues != null && object != null && data.configuration().factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY) {
+            int duplicates = 0;
+            List<T> presetValues = Arrays.asList(this.presetValues);
+            duplicates += presetValues.contains(object) ? 1 : 0;
+            duplicates += presetValues.contains(data.palette.valueFor(0)) ? 1 : 0;
+            newBits = Mth.ceillog2((1 << this.strategy.calculateBitsForSerialization(this.registry, 1 << newBits)) + presetValues.size() - duplicates);
+        }
+
         PalettedContainer.Data<T> data2 = this.createOrReuseData(data, newBits);
         data2.copyFrom(data.palette, data.storage);
         this.data = data2;
-        return data2.palette.idFor(object);
+        this.addPresetValues();
+        return object == null ? -1 : data2.palette.idFor(object);
+        // Paper end
+    }
+
+    // Paper start - Anti-Xray - Add preset values
+    private void addPresetValues() {
+        if (this.presetValues != null && this.data.configuration().factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY) {
+            for (T presetValue : this.presetValues) {
+                this.data.palette.idFor(presetValue);
+            }
+        }
     }
+    // Paper end
 
     public T getAndSet(int x, int y, int z, T value) {
         this.acquire();
@@ -129,7 +190,7 @@
         return this.getAndSet(this.strategy.getIndex(x, y, z), value);
     }
 
-    private T getAndSet(int index, T value) {
+    private synchronized T getAndSet(int index, T value) { // Paper - synchronize
         int i = this.data.palette.idFor(value);
         int j = this.data.storage.getAndSet(index, i);
         return this.data.palette.valueFor(j);
@@ -145,7 +206,7 @@
         }
     }
 
-    private void set(int index, T value) {
+    private synchronized void set(int index, T value) { // Paper - synchronize
         int i = this.data.palette.idFor(value);
         this.data.storage.set(index, i);
     }
@@ -155,7 +216,7 @@
         return this.get(this.strategy.getIndex(x, y, z));
     }
 
-    protected T get(int index) {
+    public T get(int index) { // Paper - public
         PalettedContainer.Data<T> data = this.data;
         return data.palette.valueFor(data.storage.get(index));
     }
@@ -168,7 +229,7 @@
         intSet.forEach(id -> action.accept(palette.valueFor(id)));
     }
 
-    public void read(FriendlyByteBuf buf) {
+    public synchronized void read(FriendlyByteBuf buf) { // Paper - synchronize
         this.acquire();
 
         try {
@@ -177,24 +238,33 @@
             data.palette.read(buf);
             buf.readLongArray(data.storage.getRaw());
             this.data = data;
+            this.addPresetValues(); // Paper - Anti-Xray - Add preset values (inefficient, but this isn't used by the server)
         } finally {
             this.release();
         }
     }
 
+    // Paper start - Anti-Xray; Add chunk packet info
     @Override
-    public void write(FriendlyByteBuf buf) {
+    @Deprecated @io.papermc.paper.annotation.DoNotUse public void write(FriendlyByteBuf buf) { this.write(buf, null, 0); }
+    @Override
+    public synchronized void write(FriendlyByteBuf buf, @Nullable com.destroystokyo.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) { // Paper - Synchronize
         this.acquire();
 
         try {
-            this.data.write(buf);
+            this.data.write(buf, chunkPacketInfo, chunkSectionIndex);
+
+            if (chunkPacketInfo != null) {
+                chunkPacketInfo.setPresetValues(chunkSectionIndex, this.presetValues);
+            }
+            // Paper end
         } finally {
             this.release();
         }
     }
 
     private static <T> DataResult<PalettedContainer<T>> unpack(
-        IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainerRO.PackedData<T> serialized
+        IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainerRO.PackedData<T> serialized, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues // Paper - Anti-Xray - Add preset values
     ) {
         List<T> list = serialized.paletteEntries();
         int i = paletteProvider.size();
@@ -227,11 +297,11 @@
             }
         }
 
-        return DataResult.success(new PalettedContainer<>(idList, paletteProvider, configuration, bitStorage, list));
+        return DataResult.success(new PalettedContainer<>(idList, paletteProvider, configuration, bitStorage, list, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values
     }
 
     @Override
-    public PalettedContainerRO.PackedData<T> pack(IdMap<T> idList, PalettedContainer.Strategy paletteProvider) {
+    public synchronized PalettedContainerRO.PackedData<T> pack(IdMap<T> idList, PalettedContainer.Strategy paletteProvider) { // Paper - synchronize
         this.acquire();
 
         PalettedContainerRO.PackedData var12;
@@ -284,12 +354,12 @@
     }
 
     public PalettedContainer<T> copy() {
-        return new PalettedContainer<>(this.registry, this.strategy, this.data.copy());
+        return new PalettedContainer<>(this.registry, this.strategy, this.data.copy(), this.presetValues); // Paper - Anti-Xray - Add preset values
     }
 
     @Override
     public PalettedContainer<T> recreate() {
-        return new PalettedContainer<>(this.registry, this.data.palette.valueFor(0), this.strategy);
+        return new PalettedContainer<>(this.registry, this.data.palette.valueFor(0), this.strategy, this.presetValues); // Paper - Anti-Xray - Add preset values
     }
 
     @Override
@@ -328,9 +398,18 @@
             return 1 + this.palette.getSerializedSize() + VarInt.getByteSize(this.storage.getRaw().length) + this.storage.getRaw().length * 8;
         }
 
-        public void write(FriendlyByteBuf buf) {
+        // Paper start - Anti-Xray - Add chunk packet info
+        public void write(FriendlyByteBuf buf, @Nullable com.destroystokyo.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) {
             buf.writeByte(this.storage.getBits());
             this.palette.write(buf);
+
+            if (chunkPacketInfo != null) {
+                chunkPacketInfo.setBits(chunkSectionIndex, this.configuration.bits());
+                chunkPacketInfo.setPalette(chunkSectionIndex, this.palette);
+                chunkPacketInfo.setIndex(chunkSectionIndex, buf.writerIndex() + VarInt.getByteSize(this.storage.getRaw().length));
+            }
+            // Paper end
+
             buf.writeLongArray(this.storage.getRaw());
         }
 
